On the 22th of january 2010, SCRT organised for a third year in a row it's Ethical Hacking competition: Insomni'hack.
The competition is now over.
Over a 100 hackers battled for hours to try to solve the maximum number of challenges covering several different topics regarding information security.
Top 10 participants
Solutions
Les soirées de Kevin 1
Description
Un fichier pcap était mis à disposition et le but était de retrouver les authentifiants utilisés par un utilisateur.
Solution
En ouvrant le fichier pcap avec un outil tel que Wireshark, on repère rapidement les tentatives de connexions à un serveur FTP.
L'utilisateur tente une première connexion avec le couple admin/toto, mais le serveur renvoie : "530 Login or password incorrect!". Une seconde tentative avec admin/paswrod123 échoue également. Le serveur répond finalement "230 Logged on" pour le couple admin/password123.
Il fallait donc valider admin/password123.
Les soirées de Kevin 2
Description
Un fichier pcap était mis à disposition avec la description suivante:
"Vendredi soir: soirée de jeux en réseau pour Kevin et ses amis. Kevin profite également de ces soirées pour jouer des tours aux autres participants: Utilisant le module SMB de metasploit et promettant une image au coutenu douteux, il a tenté de cracker le mot de passe de John."
Solution
En regardant la documentation du module auxiliary/server/capture/smb de metasploit, on peut voir que le challenge envoyé par le serveur correspond à "\x11\x22\x33\x44\x55\x66\x77\x88", ce qui nous oriente vers l'utilisation de tables halfLM pour cracker le mot de passe.
Dans le fichier pcap, on trouve la tentative d'authentification de l'utilisateur john. En affichant les détails du protocol dans wireshark, on retrouve le mot de passe qui a été envoyé par l'utilisateur en réponse au challenge.
On utilise alors les 16 premiers caractères de ce mot de passe afin de le cracker avec rcracki pour obtenir "caribou" comme réponse:
Le but de ces challenges était d'exploiter des failles applicatives sous linux sur processeur ia32.
Les participants avaient accès à une machine virtuelle contenant un Linux Debian dans laquelle la randomisation de l'espace d'adressage était désactivée et les binaires étaient compilés sans canary.
Solution
Une fois loggé en tant que level1, on trouve un binaire setuid appartenant à level2.
Le binaire level1 prend en argument sur la ligne de commande une chaine de caractères. On remarque que le processus segfault si une chaine trop grande lui est passée. En le lançant dans gdb avec un grand nombres de caractères, on obtient:
(gdb) r `python -c 'print "A"*132 + "BBBB"'`
Starting program: /home/level1/level1 `python -c 'print "A"*132 + "BBBB"'`
AA<..>AABBBB
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
De là, on en déduit que l'adresse de retour présente dans la pile est réécrite à partir d'au moins 132 caractères.
Etant donné que l'environnement du processus peut être contrôlé, une solution simple est de placer le shellcode dans une variable d'environnement et d'obtenir son adresse via la formule suivante:
Comme pour les autres niveaux, un binaire setuid appartenant à level4 est présent dans le répertoire de l'utilisateur level3.
Cette fois, même en passant une chaine de caractères longue, le processus ne segfault pas. Il convient de reverser le binaire avec un outil tel qu'objdump afin de comprendre son fonctionnement vu que ltrace ou strace ne donnent pas d'information.
La fonction "main" se situe à 0x080485b6 et on localise les arguments à -0xc(%ebp) ainsi que le test sur le nombre d'arguments en 0x80485cd:
Ce second bloc compare argv[1][argv[1][2]] à 0x63 (c) et dans le cas où les valeurs sont similaires, la fonction doStuff() est appellée avec comme argument argv[1]+10:
L'analyse continue alors avec la fonction doStuff. Au début de cette fonction, la chaine de caractères "/home/level4/plop" est copiée dans la pile à partir de -0x48(%ebp):
En 0x8048534, on peut voir un appel à la fonction strncpy afin de copier 0x3c octets de la chaine passée comme argument à la fonction (0x8(%ebp)) dans un buffer contenu dans la pile (-0x58(%ebp)).
On remarquera qu'il nous est alors possible d'écraser la chaine de caractères stockée en -0x48(%ebp). Il se trouve que (par chance) cette chaine correspond au nom du fichier dont le contenu est affiché par level4!
La série d'épreuves sur les PDF consistait à trouver les modifications faites dans des fichiers afin d'obtenir une clef ainsi que le PDF correspond au niveau suivant.
Solution
Le dernier puzzle contenait plusieurs erreurs. La première était qu'il manquait le contenu de deux pages. Il fallait remarquer que les objets 6 et 9 avaient comme parent 2 alors que lui ne les avaient pas dans sa liste de descendants:
Il convenait donc de les rajouter dans la définition de l'objet 2:
2 0 obj
<<
/Type /Pages
/Count 3
/Kids [ 3 0 R 6 0 R 9 0 R ]
>>
endobj
Une fois cette modification faite, 2 pages supplémentaires étaient accessible. Un faux code était présent dans la première de ces pages.
En analysant les définitions des objets, on s'aperçoit que l'objet 10 utilise un filtre spécial: PlatDecode. En se référant à la documentation du format PDF qui était fournie, on voit que ce filtre n'existe pas.
Le filtre PlatDecode était à remplacer par LZWDecode afin d'obtenir la clef qui permetait de valider l'épreuve.
Pirates de Préverenges
Description
Il s'agit de pirater le site d'une personne en ayant seulement son URL comme point de départ.
Solution
On voit qu'il y a le possibilité de récupérer un mot de passe perdu sur le site. A partir de là, il est possible de trouver que seul l'utilisateur "admin" existe. Il faut alors répondre à la question secrète "Quelle est votre couleur préférée?". Au bout de quelques tentatives on découvre que la réponse est "Violet" qui révèle le mot de passe de l'utilisateur admin : "rata!flupk". Ceci permet d'accéder au site.
Le traître
Description
Les sources d'un blog ont été récupérées et doivent être utilisées afin de récupérer un fichier sur le serveur Web. Ce fichier n'est disponible qu'aux utilisateurs faisant partie du groupe d'administrateurs.
Solution
Il y a une combinaison d'une faille Cross-Site Scripting et Cross-Site Request Forgery qui permettent à l'utilisateur de s'attribuer les droits d'administrateur. Ceci peut être fait par exemple en insérant dans la "Shoutbox" la valeur suivante
On se retrouve devant un paneau d'authentification dont la seule subtilité semble être la possibilité de se connecter avec différentes langues dont le japonais et le chinois.
Solution
Le fait que le site soit disponible en plusieurs langues dont certaines contenant des caractères exotiques devait mettre en question les possiblités d'encodage des caractères du site. On se rend compte alors que le site accepte les caractères en UTF-8, mais également en "overlong" UTF-8. Le site a été mal programmé et décode l'UTF-8 après avoir rajouté les "\" pour échapper la requête SQL. Ceci signifie qu'en encodant les apostrophes en overlong UTF-8, il est possible d'exploiter une triviale injection SQL pour bypasser l'authentification.
user = admin%c0%a7%20or%20%c0%a7a%c0%a7=%c0%a7a
Fin d'Internet
Description
On récupère un binaire au format PE (Windows) qu'il faut analyser pour comprendre son fonctionnement.
Solution
On se rend compte rapidement que la partie exécutable du code est cryptée. La solution la plus simple consiste à lancer le code dans un debugeur et mettre un point d'arrêt à la fin de la routine de décryption pour afficher le code en clair. Suite à cela il faut éviter les quelques protections afin de découvrir la raison d'être de l'exécutable. On y voit surtout qu'il injecte du code dans le processus explorer.exe et lance un RemoteThread. Les appels de fonctions ont également été cryptés, mais il suffit de mettre un nouveau point d'arrêt au niveau de la procédure CreateRemoteThread pour ensuite afficher la mémoire du processus explorer.exe par exemple pour découvrir que le but est de télécharger et d'exécuter un fichier superleet.exe qui se trouve à l'adresse http://66.66.66.66/superleet.exe.
Page Perso de Kobe
Description
On se retrouve devant une animation en flash qui demande de s'authentifier pour accéder à la partie privée.
Solution
On commence par récupérer et décompiler l'animation pour accéder aux sources. On constate que le mot de passe à utiliser et codé en dur.
if (password_field.text != "lahakers")
Shoot the caribou
Description
On se retrouve devant une page contenant un jeu en flash. Le but est de faire un score supérieur à 100 en moins de 10 secondes.
Solution
On commence par récupérer et décompiler l'animation pour accéder aux sources. On constate que les données envoyées à la page de résultat sont chiffrées en RC4 avec la clé "ghtrxwogl". Le texte chiffré est composé du score suivi de l'ID de session. On doit alors récupérer l'ID de session générée sur la page du jeu, chiffrer les données en mettant un score supérieur à 100 et envoyer le tout à la page de résultat.
var rc4_text = "" + _root.hits + ":" + id_session + "";
var rc4_key = "ghtrxwogl";
var rc4_hash = com.meychi.ascrypt.RC4.encrypt(rc4_text, rc4_key);
getURL("./scores.php?score=" + rc4_hash, "_self");
One Time Pad
Description
Le but de l'épreuve est de déchiffrer le contenu du fichier cipher2.txt.
Solution
Le fichier est chiffré à l'aide de l'outil oneTimePad.py (fourni). Ce fichier implémente un algorithme de chiffrement de type masque jetable: cipher = plain XOR keystream. De plus, deux autres fichiers sont fournis - plain1.txt et cipher1.txt - respectivement un message en clair et sa version chiffrée à 'aide du même algorithme.
La solution de l'épreuve repose sur une supposition simple: les deux fichiers ont été chiffrés à l'aide de la même clé. Cette clé peut être obtenue simplement en effectuant un XOR entre plain1.txt et cipher1.txt. Ceci peut d'ailleurs être effectué à l'aide du programme fourni.
Le but de cette épreuve est de déchiffrer le fichier cipher.txt, chiffré à l'aide de l'algorithme RSA. En plus du fichier à déchiffrer, une archive - RSATools.zip - était fournie aux participants. Cette archive contenait deux scripts Python: encTool.py et euclid.py, le premier étant l'outil utilisé pour créer le fichier chiffré et le deuxième étant l'implémentation de l'algorithme d'Euclide.
Solution
Le contenu du fichier à déchiffrer est reproduit ci-dessous.
$ cat cipher.txt
# ---------------------- BEGIN RSA HEADER ----------------------
# MjUxOjU3MjE0ODE2Nw==
# ----------------------- END RSA HEADER -----------------------
eJwdy7ERwDAMAsDek6TKGYEsaQcvkT5F9q9iu+MPuN4PbUI9kBY52zOtikT02pBLqdBp1M1T6dxg
GseIs1pP9AKxgYGA0w9YbszSyvcPIAUX4w==
On notera tout d'abord que l'en-tête du fichier correspond au texte "251:572148167" encodé en Base64. La lecture du code source des outils fournis révèle la signification de ces nombres: il s'agit de la clé publique RSA utilisée pour chiffrer le fichier (e = 251, n = 572148167)
Il faut alors noter que le module RSA est extrêmement petit et qu'il peut donc être aisément factorisé. Cette factorisation peut être effectuée à l'aide d'outils mathématiques (pour les participants disposant d'une boîte à outils bien équipée) ou à l'aide d'un simple script (la valeur étant suffisamment petite pour que cette opération ne prenne que quelques secondes sur un ordinateur portable standard).
Ayant obtenu les facteurs de 'n' il est alors possible de calculer la valeur de la clé privée correspondante ('d'), à savoir l'inverse de 'e' modulo (16943-1 * 33769-1). Pour cela, les participants pouvaient s'aider des outils mis à disposition, notamment de l'implémentation de l'algorithme d'Euclide étendu (euclid.py).
La clé privée RSA recherchée est donc (d = 34189091, n = 572097456). Il suffit alors d'utiliser l'outil de chiffrement fourni pour déchiffrer le fichier, trouvant ainsi la solution de l'épreuve: FOLLOW-TH3-WH1T3-RABB1T.
Les participants recevaient une image accompagnée du message "Rien n'est négligeable ... même les plus insignifiant des détails", les laissant ainsi trouver par eux-mêmes le but de l'épreuve.
Ce but de l'épreuven était, bien évidemment, de récupérer un message caché dans l'image.
Solution
On peut tout d'abord remarquer que l'image est un fichier BMP. Ce format est non compressé et relativement simple à manipuler (une description détaillée du format BMP faisait partie du pack d'outils mis à disposition des participants). Sans même trop s'intéresser aux détails du format, la simple ouverture du fichier dans un éditeur hexadécimal permet de voir que le contenu de l'image commence à la position 00000036. A partir de cette position chaque pixel de l'image est codé sur 24 bits (3 octets, chacun des octets représentant un des canaux RGB).
00000000 42 4d 7e ad 0a 00 00 00 00 00 36 00 00 00 28 00 |BM~.......6...(.|
00000010 00 00 88 01 00 00 53 02 00 00 01 00 18 00 00 00 |......S.........|
00000020 00 00 48 ad 0a 00 01 00 00 00 01 00 00 00 00 00 |..H.............|
00000030 00 00 00 00 00 00 fe fe fe ff ff ff fe fe fe ff |................|
00000040 ff ff fe fe fe ff ff ff ff ff ff ff ff ff fe fe |................|
00000050 fe ff ff ff fe fe fe fe fe fe ff ff ff ff ff ff |................|
00000060 ff ff ff ff ff ff fe fe fe ff ff ff fe fe fe fe |................|
00000070 fe fe ff ff ff ff ff ff ff ff ff fe fe fe fe fe |................|
00000080 fe ff ff ff fe fe fe fe fe fe fe fe fe ff ff ff |................|
00000090 fe fe fe fe fe fe fe fe fe fe fe fe ff ff ff ff |................|
000000a0 ff ff fe fe fe fe fe fe ff ff ff ff ff ff fe fe |................|
...
L'éditeur hexadécimal permet également de remarquer que les nombreux pixels blancs de l'image ne son pas homogènes. En effet ces pixels devraient être constitués de trois octets de valeur '0xFF' alors que certains de ceux observés dans l'image comprennent des octets de valeur '0xFE'. Ceci laisse donc supposer que certains des pixels ont été altérés, et plus précisément qu'un bit en a été altéré. On note également que les trois canaux ont la même valeur, laissant ainsi supposer que la même altération a été appliquée sur chacun d'eux. Ces observations conduisent logiquement à la conclusion d'une technique stéganographique de type "Least Significant Bit" (ou LSB) a été utilisée pour dissimuler de l'information dans l'image. De plus, la dernière remarque laisse supposer que cette même information a été dissimulée indépendamment dans chacun des trois canaux RGB. On peut donc, sans risque s'intéresser à un seul des canaux (par exemple le premier) et ignorer les deux autres.
Afin de décoder cete information, il était alors attendu des participants qu'ils écrivent un script prenant la valeur du dernier bit de chaque pixel (sur un canal choisi). Ces bits peuvent ensuite être groupés par 8 afin de former des octets qu'il suffit d'interpréter comme des caractères ASCII.
import binascii
import sys
def byteFromBitstring(bitstring):
return int(bitstring, 2)
def bitstringFromByte(byte):
return ''.join([str((byte >> i) & 0x01) for i in range(7, -1, -1)])
def reveal(image, offset):
message = ''
bitstring = ''
pixel = offset
while pixel < len(image):
bit = bitstringFromByte(int(binascii.hexlify(image[pixel]),16))[-1]
bitstring += bit
if len(bitstring) > 7:
message += chr(byteFromBitstring(bitstring))
bitstring = ''
pixel += 3
return message
if __name__ == '__main__':
print reveal(open(sys.argv[1], 'rb').read(), int(sys.argv[2], 16))[10:39]
Le script ci-dessus accomplit cette tâche et permet ainsi de récupérer l'information recherchée (répétée tout au long de l'image): W3LCOME_2_H4CK3R'S_WOND3RL4ND.