in the name of zero

November 19, 2006

yanisto’s Naive_crackme

Here is my first linux ELF crackme…
Not very hard to solve but not for tyros either…

Solution will be published later on nuxed.org.

Enjoy ! ++nisto

Difficulty: 2 - Needs a little brain (or luck)
Platform: Unix/linux etc.
Language: Assembler

here

misha@heaven ~/yanisto $ file naive-crk
naive-crk: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
	
misha@heaven ~/yanisto $ strings naive-crk
ptraced !!
 ---snipped some weird characters---
 Sorry, it ain't the good pass or the is file patched ;)
 ---snipped some weird characters---

i fired up ida, pressed ‘ctrl e’ and went to the crackme’s start routine. and from there, i encountered one of the first tricks employed. the author inserted some garbage bytes to (possibly) fool disassemblers. ida saw this and did the necessary modifications.

ida:
        .text:08048883 start            proc near
        .text:08048883 ; FUNCTION CHUNK AT .text:080483B2 0000000F BYTES
        .text:08048883 ; FUNCTION CHUNK AT .text:080483C4 0000008D BYTES
        .text:08048883 ; FUNCTION CHUNK AT .text:0804846B 00000020 BYTES
        .text:08048883 ; FUNCTION CHUNK AT .text:080484AF 00000098 BYTES
        .text:08048883 ; FUNCTION CHUNK AT .text:0804886C 00000017 BYTES
	
        .text:08048884                  nop
        .text:08048885                  jmp     loc_80483C4

this single byte is effectively, a nop instruction. whereas, in objdump, this is how it looked like:

 8048881:       ff                      (bad)
 8048882:       ff 90 90 e9 3a fb       call   DWORD PTR [eax-80025200]
 8048888:       ff                      (bad)  

the jz instruction at 0x080483C4 is simply a means of jumping over more garbage. to fix it, follow the jmp, press ‘d’, then at address 0x080483CB (0x080483C9 + 2 = 0x080483CB), press ‘c’ to tell ida to view the data starting there as ‘code’. after doing this, the block would now make sense, outlined below for reference.

.text:080483C9                 db   12h     ; garbage byte
.text:080483CA                 db       15h     ; garbage byte
	
.text:080483CB                 xor     ebx, ebx
.text:080483CD                 xor     eax, eax
.text:080483CF                 mov     eax, dword_8048453       ; 0x31DB3104
.text:080483D4                 mov     edx, 0A1h
.text:080483D9                 mov     ecx, edx
.text:080483DB                 mov     bl, cl
.text:080483DD                 rol     bl, 4
.text:080483E0                 ror     cl, 4
.text:080483E3                 or      bl, cl
.text:080483E5                 ror     eax, 2
.text:080483E8                 and     eax, 0FEh
.text:080483ED                 xchg    al, bl
.text:080483EF                 xor     ebx, 0C0h
.text:080483F5                 xor     esi, esi
.text:080483F7                 and     cl, 5
.text:080483FA                 push    eax                      ; 0x1A on the stack
.text:080483FB                 mov     esi, offset byte_8048451
.text:08048400                 lodsw                            ; eax = 0x5e60
.text:08048402                 xor     ax, 0DEADh               ; eax = 0x80cd
.text:08048406                 mov     edi, offset loc_8048418  ; buffer
.text:0804840B                 stosw                            ; 0x80cd to buffer
.text:0804840D                 pop     eax                      ; restore eax = 0x1a
	
.text:0804840E loc_804840E:
.text:0804840E                 xor     dx, 0A1h                 ; edx = 0
.text:08048413                 xor     bl, 80h                  ; ebx = 0
.text:08048416                 xor     esi, esi                 ; esi = 0

… succeeding two bytes were patched earlier (specifically, at .text:0804840B)

ok, note that the value 0x80cd is stored a few bytes further into the block. 0x80CD when translated to intel asm instruction, is just equal to int 0x80. we know that it’s a PTRACE_TRACEME check because eax is 0x1a (26 decimal) and ebx = 0.

misha@heaven ~/yanisto $ grep -i __nr_ptrace /usr/include/asm/unistd.h
#define __NR_ptrace              26

i now resume analysis at address 0x0804846B where the control is passed if the call to ptrace() succeeded.

first encountered a function that xors some predefined characters by 0x1137 (decrypt_welcome_string()). it prints the welcome string after decryption and calls a sys_read() to get characters and save them to a buffer (8 characters).

the welcome string:

      Naive_crackme - nisto's crackme #1
      ----------------------------------
	
This is my 1st crackme...
It uses regular tricks and some others... hehe...
Hope u'll get some fun with it.
	
You can join me at yanisto@nuxed.org or on #secdev@freenode.net
	
Enter the Password :

i noticed that no comparison whatsoever was done with the user input, (well, at least not in the current function anyway) instead, upon return, another function was called which does some calculation, possibly a checksum() function to detect patching within a proximity. but here’s the twist, the user input buffer is also located within the said proximity. making a predefined spot in the block dynamic.

the checksum() is a continuous xor operation of a dword to succeeding blocks of dword values.

.text:08048454 checksum():
.text:08048454			xor	ebx, ebx
.text:08048456			xor	ecx, ecx
.text:08048458			mov	esi, offset dword_804800C	; start address
.text:0804845D checksum_loop:
.text:0804845D			lodsd					; load next dword
.text:0804845E			xor	ebx, eax			; xor it with the former xor result
.text:08048460			add	ecx, ebx
.text:08048462			cmp	esi, offset byte_8048418	; are we at the end?
.text:08048458			jbe	short checksum_loop		; no, continue with checksumming
.text:0804846A			retn

when the function returns ebx, is compared to a predefined value, 0x19160493. the block that is being checksummed roughly looks like:

[ constant values block ] checksum: 0x14a13e9f
[ user input buffer ]
[ constant values block ] checksum: 0x5df8c4c2

the buffer for user input is located in between these two blocks, therefore, the end result of the checksum() is highly dependent on the 8 characters of user input. i consulted my friend grainne yap about the checksum function which i encountered and she told me that XOR is associative, we can get the values of the two blocks with constant values and join them together. then finally, xor that with variable user input that will result to 0x19160493. also take note that the user input buffer has some constant bytes of it’s own, due to the fact that the user input doesn’t fall under a dword boundary relative to the dword increments of the checksum() function. so if we have an 8 character user input “stefanie“, the user buffer block would look something like:

note: values in hex are constants.

t    | s    | 0x80 | 0xcd
n    | a    | f    | e
0x00 | 0x2e | e    | i

so we have two variable dwords and the dword with an additional constant value 0x002e80cd.

computing for the xor is a chore, so i used ald to make the crackmes’ own checksum() function compute the xor checksums of the two blocks with constant values for me.

[ constant values block ] checksum: 0x14a13e9f
[   user input buffer   ] index [2][1][4][3]
[   user input buffer   ] index [6][5][8][7]
[  additional constant  ] checksum: 0x002e80cd
[ constant values block ] checksum: 0x5df8c4c2

the checksum of the 3 constant values is 0x49777A90. and i also know that the end result must be 0x19160493. i made a generator and tried things out.

     Naive_crackme - nisto's crackme #1
      ----------------------------------
	
This is my 1st crackme...
It uses regular tricks and some others... hehe...
Hope u'll get some fun with it.
	
You can join me at yanisto@nuxed.org or on #secdev@freenode.net
	
Enter the Password :   Pih:19kD
	
Yeahhhh evil hacker ;)  U managed to break my poor crackme…
	
Send me your code and process to get it… I’m curious… :)
The next one will be much harder i hope cuz’ I’m still a tyro ;) 
	
First, i wanted to grant you a Renault Clio 16S but, i’m sure u’d rather appear
     on some kind of hall of fame… It’s ok for me ;) 
	
++ nisto…    

parting words:

i also changed the e_entry field of the crackme to point to the rather standard _start routine to see how it’ll run, i haven’t studied it that deep so far, but something tells me this is another one of the crackmes traps.

2 Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2006/11/19/yanistos-naive_crackme/trackback/

  1. What /is/ ida anyway … ?

    Comment by chaosite — November 19, 2006 @ 11:52 pm

  2. ida (or Interactive DisAssembler) by ilfak guilfanov is a dissasembler and debugger, argued by some to be the “best-out-there” package for code analysis.

    you can find out more about it in these two sites:

    official site: http://www.datarescue.com/
    author’s blog: http://www.hexblog.com/

    cheers

    Comment by sleepy jenkins — November 20, 2006 @ 5:23 am

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome | Theme designs available here