Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

A nice evening at Hackgyver with r00tBSD
Thu 13 December 2012 — download

Tonight, Paul (rootbsd) Rascagneres gave a talk at the Hackgyver hackspace in Belfort, and proposed afterwards two littles reversing challenges (one on Linux, and one on Windows) with malware.lu (which is a nice resources website by the way) T-shirts as prizes to finish the evening: I won both \o/

Nothing complicated, since they had to be solvable in less than 2 hours, but still fun to reverse under pressure ("I must get a free T-shirt !").

Linux

You can get the bin here

/ function: sym.main (242)
|          0x080489a5      55               push ebp
|          0x080489a6      89e5             mov ebp, esp
|          0x080489a8      57               push edi
|          0x080489a9      83e4f0           and esp, 0xfffffff0
|          0x080489ac      83ec70           sub esp, 0x70
|          0x080489af      8b450c           mov eax, [ebp+0xc]
|          0x080489b2      8944241c         mov [esp+0x1c], eax
|          0x080489b6      65a114000000     mov eax, [gs:0x14]
|          0x080489bc      8944246c         mov [esp+0x6c], eax
|          0x080489c0      31c0             xor eax, eax
|          0x080489c2      837d0802         cmp dword [ebp+0x8], 0x2
|      ,=< 0x080489c6      740c             jz loc.080489d4 ; first test on arguments
|      |   0x080489c8      c7042401000000   mov dword [esp], 0x1
|      |   0x080489cf      e8fcfcffff       call dword imp.exit
|      `-> 0x080489d4      8b44241c         mov eax, [esp+0x1c]
|          0x080489d8      83c004           add eax, 0x4
|          0x080489db      8b00             mov eax, [eax]
|          0x080489dd      c7442418ffffffff mov dword [esp+0x18], 0xffffffff
|          0x080489e5      89c2             mov edx, eax
|          0x080489e7      b800000000       mov eax, 0x0
|          0x080489ec      8b4c2418         mov ecx, [esp+0x18]
|          0x080489f0      89d7             mov edi, edx
|          0x080489f2      f2ae             repne scasb
|          0x080489f4      89c8             mov eax, ecx
|          0x080489f6      f7d0             not eax
|          0x080489f8      83e801           sub eax, 0x1
|          0x080489fb      83f808           cmp eax, 0x8
|     ,==< 0x080489fe      770c             ja loc.08048a0c ;second test on arguments
|     |    0x08048a00      c7042401000000   mov dword [esp], 0x1
|     |    0x08048a07      e8c4fcffff       call dword imp.exit
|     `--> 0x08048a0c      8b44241c         mov eax, [esp+0x1c]
|          0x08048a10      83c004           add eax, 0x4
|          0x08048a13      8b00             mov eax, [eax]
|          0x08048a15      8d542421         lea edx, [esp+0x21]
|          0x08048a19      89542404         mov [esp+0x4], edx
|          0x08048a1d      890424           mov [esp], eax
|          0x08048a20      e88ffeffff       call dword sym.md6
|          0x08048a25      8b44241c         mov eax, [esp+0x1c]
|          0x08048a29      83c004           add eax, 0x4
|          0x08048a2c      8b00             mov eax, [eax]
|          0x08048a2e      c744240409000000 mov dword [esp+0x4], 0x9
|          0x08048a36      890424           mov [esp], eax
|          0x08048a39      e856fdffff       call dword sym.RC4_encode
|          0x08048a3e      8d542442         lea edx, [esp+0x42]
|          0x08048a42      89542404         mov [esp+0x4], edx
|          0x08048a46      890424           mov [esp], eax
|          0x08048a49      e866feffff       call dword sym.md6
|          0x08048a4e      8d442442         lea eax, [esp+0x42]
|          0x08048a52      89442404         mov [esp+0x4], eax
|          0x08048a56      8d442421         lea eax, [esp+0x21]
|          0x08048a5a      890424           mov [esp], eax
|          0x08048a5d      e85efcffff       call dword imp.strcmp
|          0x08048a62      85c0             test eax, eax
|    ,===< 0x08048a64      750e             jnz loc.08048a74 ;jumps tbadboy
|    |     0x08048a66      c70424788b0408   mov dword [esp], str.Well,nowcreateyourownkeygen
|    |     0x08048a6d      e82efcffff       call dword imp.puts
|   ,====< 0x08048a72      eb0c             jmp loc.08048a80
|   |`---> 0x08048a74      c704249c8b0408   mov dword [esp], str.Badkey
|   |      0x08048a7b      e820fcffff       call dword imp.puts
|   `----> 0x08048a80      8b54246c         mov edx, [esp+0x6c]
|          0x08048a84      65331514000000   xor edx, [gs:0x14]
|  ,=====< 0x08048a8b      7405             jz loc.08048a92
|  |       0x08048a8d      e8fefbffff       call dword imp.__stack_chk_fail
|  `-----> 0x08048a92      8b7dfc           mov edi, [ebp-0x4]
|          0x08048a95      c9               leave
\          0x08048a96      c3               ret

Looks pretty straightforward : md6(string) == md6(string[0-9] + ARC4(string, 9), but the tricks is that sys.md6 is in fact a MD5, and sym.RC4_encode is base64.

At first, I was candid enough to not check what they were really doing, and therefore lost some time.

import sys
import base64

print sys.argv[1][:9] + base64.b64encode(sys.argv[1][:9])

Funny note, r00tBSD didn't known that MD6 was a real thing !

Windows

You can get the bin here

Since I'm not as familiar with Windows as I am in Linux, I searched for string "Good PIN code" in the binary, because as the challenge was supposed to be easy enough to be solved in a short amount of time,

I though that I was not supposed to dig all around the bloated visual-studio-produced code to find the verification routine. But Windows use Unicode, so I didn't find the string at first check. R00tBSD was kind enough to remind me this fact, so I ran strings with the appropriate arguments, and voilà:

$ strings -el -t x hackgyver.exe
[...]
c918 CONOUT$
c928 HACK
c934 hackgyver.png
c950 Error
c960 Unable to create a file in the current directory
c9c4 Hackgyver
c9d8 Hackgyver: Windows Reverse
ca10 RegisterClassEx Failed!
ca40 CreateWindow Failed!
ca6c validate
ca80 Button
ca94 Edit
caa0 Enter your PIN code
cac8 Static
cad8 Good PIN code
cb0c Bad PIN code
e6a2 HACK

With those informations, I supposed that that crackme will show an (embedded) PNG if I provide him the right PIN.

.text:00401425 loc_401425:                             ; CODE XREF: sub_4013A0+8Ej
.text:00401425                 mov     ax, [ecx]
.text:00401428                 add     ecx, 2
.text:0040142B                 test    ax, ax
.text:0040142E                 jnz     short loc_401425
.text:00401430                 push    0               ; lpUsedDefaultChar
.text:00401432                 push    0               ; lpDefaultChar
.text:00401434                 push    0Ch             ; cbMultiByte
.text:00401436                 sub     ecx, edx
.text:00401438                 sar     ecx, 1
.text:0040143A                 lea     eax, [ebp+MultiByteStr]
.text:0040143D                 push    eax             ; lpMultiByteStr
.text:0040143E                 lea     eax, [ecx+1]
.text:00401441                 push    eax             ; cchWideChar
.text:00401442                 push    offset String   ; lpWideCharStr
.text:00401447                 push    0               ; dwFlags
.text:00401449                 push    0               ; CodePage
.text:0040144B                 call    ds:WideCharToMultiByte
.text:00401451                 lea     ecx, [ebp+MultiByteStr]
.text:00401454                 call    sub_401000
.text:00401459                 push    0               ; lpParam
.text:0040145B                 push    0               ; hInstance
.text:0040145D                 push    0               ; hMenu
.text:0040145F                 push    edi             ; hWndParent
.text:00401460                 push    19h             ; nHeight
.text:00401462                 push    8Ch             ; nWidth
.text:00401467                 push    32h           ; Y
.text:00401469                 push    32h             ; X
.text:0040146B                 push    50000000h       ; dwStyle
.text:00401470                 cmp     al, 1
.text:00401472                 jnz     short loc_4014A6 ; BADBOY
.text:00401474                 push    offset aGoodPinCode ; "Good PIN code"
.text:00401479                 push    offset aStatic  ; "Static"
.text:0040147E                 push    0               ; dwExStyle
.text:00401480                 call    ds:CreateWindowExW
.text:00401486                 push    offset aExplorerHackgy ; "explorer hackgyver.png"
.text:0040148B                 call    sub_401572
.text:00401490                 add     esp, 4
.text:00401493                 xor     eax, eax
.text:00401495                 pop     edi
.text:00401496                 mov     ecx, [ebp+var_4]
.text:00401499                 xor     ecx, ebp
.text:0040149B                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:004014A0                 mov     esp, ebp
.text:004014A2                 pop     ebp
.text:004014A3                 retn    10h
.text:004014A6 ; ---------------------------------------------------------------------------
.text:004014A6
.text:004014A6 loc_4014A6:                             ; CODE XREF: sub_4013A0+D2j
.text:004014A6                 push    offset aBadPinCode ; "Bad PIN code"
.text:004014AB                 push    offset aStatic  ; "Static"
.text:004014B0                 push    0               ; dwExStyle
.text:004014B2                 call    ds:CreateWindowExW
.text:004014B8                 xor     eax, eax
.text:004014BA                 pop     edi
.text:004014BB                 mov     ecx, [ebp+var_4]
.text:004014BE                 xor     ecx, ebp
.text:004014C0                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:004014C5                 mov     esp, ebp
.text:004014C7                 pop     ebp
.text:004014C8                 retn    10h

Everything seems to happen in sub_401000.

;Prolog, and strlen
[...]
.text:00401029                 cmp     ecx, 5          ; Our PIN must be 5 digits long
.text:0040102C                 jnz     BADBOY
.text:00401032                 push    ebx
.text:00401033                 push    esi
.text:00401034                 push    offset Type     ; "HACK"
.text:00401039                 push    67h             ; lpName
.text:0040103B                 push    0               ; hModule
.text:0040103D                 call    ds:FindResourceW
.text:00401043                 mov     esi, eax
.text:00401045                 push    esi             ; hResInfo
.text:00401046                 push    0               ; hModule
.text:00401048                 call    ds:SizeofResource
.text:0040104E                 push    esi             ; hResInfo
.text:0040104F                 push    0               ; hModule
.text:00401051                 mov     ebx, eax
.text:00401053                 call    ds:LoadResource
.text:00401059                 push    ecx
.text:0040105A                 mov     edx, edi
.text:0040105C                 lea     ecx, [ebp+var_908]
.text:00401062                 mov     esi, eax
.text:00401064                 call    sub_401150      ; First key computation routine
.text:00401069                 lea     eax, [ebp+var_804]
.text:0040106F                 push    ebx
.text:00401070                 push    eax
.text:00401071                 mov     edx, esi
.text:00401073                 lea     ecx, [ebp+var_908]
.text:00401079                 call    sub_4011C0      ; Second key computation routine
.text:0040107E                 add     esp, 0Ch
.text:00401081                 push    0               ; hTemplateFile
.text:00401083                 push    80h             ; dwFlagsAndAttributes
.text:00401088                 push    2               ; dwCreationDisposition
.text:0040108A                 push    0               ; lpSecurityAttributes
.text:0040108C                 push    0               ; dwShareMode
.text:0040108E                 push    40000000h       ; dwDesiredAccess
.text:00401093                 push    offset FileName ; "hackgyver.png"
.text:00401098                 call    ds:CreateFileW
.text:0040109E                 mov     esi, eax
.text:004010A0                 cmp     esi, 0FFFFFFFFh
.text:004010A3                 jnz     short loc_4010CC
;Unable to create the file, crap :/
[...]
.text:004010CC ; ---------------------------------------------------------------------------
.text:004010CC
.text:004010CC loc_4010CC:                             ; Looks like to be the check of the key
.text:004010CC                 cmp     [ebp+var_804], 0AAh
.text:004010D3                 jnz     short BADBOY2
.text:004010D5                 cmp     [ebp+var_803], 0BBh
.text:004010DC                 jnz     short BADBOY2
.text:004010DE                 cmp     [ebp+var_802], 0CCh
.text:004010E5                 jnz     short BADBOY2
.text:004010E7                 cmp     [ebp+var_801], 0DDh
.text:004010EE                 jnz     short BADBOY2
.text:004010F0                 push    0               ; lpOverlapped ;GOODBOY ;)
.text:004010F2                 lea     eax, [ebp+NumberOfBytesWritten]
.text:004010F8                 push    eax             ; lpNumberOfBytesWritten
.text:004010F9                 push    ebx             ; nNumberOfBytesToWrite
.text:004010FA                 lea     eax, [ebp+Buffer]
.text:00401100                 push    eax             ; lpBuffer
.text:00401101                 push    esi             ; hFile
.text:00401102                 call    ds:WriteFile
.text:00401108                 push    esi             ; hObject
.text:00401109                 call    ds:CloseHandle
[...]
.text:00401121                 retn

Once again, r00tBSD help us by saying that the key computation was using a well-known simple encryption scheme, and since it was split in two functions, it can/should be ARC4, that "We shall all had recognized". Unfortunately, I'm not able (yet) to identify encryption schemes simply by taking a quick look at disassembly.

To sum up, the ARC4-deciphered chunk passed as second argument to the second "key computation routine " ("\xF3\xDB\x99\x90\x95\x4E\xC2\x1E\x32...") with our PIN as the key must be equals to \xAA\xBB\xCC\xDD. Time to write a bruteforcer:

import Crypto.Cipher.ARC4 as arc4

b = '\xAA\xBB\xCC\xDD'
string = '\xF3\xDB\x99\x90\x95\x4E\xC2\x1E\x32'

for i in xrange(10000, 99999):
    if arc4.new(str(i)).decrypt(string).startswith(b):
        print i
        break

Conclusion

A nice talk + two uncomplicated-by-still-entertaining crackme + one T-shirt = a good evening ;)