in the name of zero

November 16, 2006

veneta’s Linux Crackme v1

{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
{{{ HI! Welcome to my first Crackme writen for linux it is also my }}}
{{{ first program in asm for Linux. It was Compiled with nasm :) . }}}
{{{ mail:veneta8@poczta.onet.pl My: veneta.prv.pl MBE: mbe.prv.pl }}}
{{{ }}}
{{{ Coded by: }}}
{{{ veneta//MBE }}}
{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}

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


i started off by running it thru ‘file’:

cm1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), corrupted section header size

it has a corrupted section header size so BFD-based tools like objdump are practically useless until the section information of the file has been fixed. aside from this, it’s dynamically linked.

misha@heaven ~/veneta $ readelf -d cm1 | grep -i library
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

i fired up IDA, which automatically placed me in the entry point. i verified thru readelf.

misha@heaven ~/veneta $ readelf -a cm1 | grep -i entry
readelf: Error: Section headers are not available!
  Entry point address:               0x804819f

the first thing i noticed was this was not the usual libc startup. encrypted? unlikely. this is the start routine so these must be the real thing infront of my eyes. i searched in my bookmarks and found a link that would help me get things started. startup state of a linux/i386 elf binary by konstantin boldyshev. many interesting things to note here. but for now, i was only concerned with the stack layout upon loading of the elf entry point.

in a nutshell, we have –top [argc] [argv0 … argv1 … argvX] [NULL] [env0 … env1 … envX] [NULL] bottom–

sidenote: as of this moment, i still don’t freakin’ know how to copy from the IDA window to vim!! :(

[ analyzing the first few blocks ]

LOAD:0804819F start	proc near
LOAD:0804819F		pop     esi
LOAD:080481A0		pop     ebx
LOAD:080481A1		mov     ebx, offset dword_80483D0
LOAD:080481A6		mov     ebp, offset loc_8048192
LOAD:080481AB		push    0
LOAD:080481AD		push    dword ptr [ebx+1Ch]
LOAD:080481B0		push    76h
LOAD:080481B2		mov     esi, offset word_8048326
LOAD:080481B7		sub     edi, edi
LOAD:080481B9		jmp     short loc_80481C0

now obviously, the first instruction - pop esi placed the argc value into esi.
the second pop placed argv into ebx. (the program name)

the third instruction was a little weird, i inspected offset dword_80483D0 and the following came up.

LOAD:080483D0 dword_80483D0	dd 2 dup(?)
LOAD:080483D8			dd offset getchar
LOAD:080483DC			dd offset write
LOAD:080483E0			dd 3 dup(?)
LOAD:080483EC			dd offset _exit
LOAD:080483F0			dd 4 dup(?)

so it only places an address to ebx. but notice that offsets to 3 libc functions (getchar, write and _exit) are in the array.
then it does a mov ebp, loc_8048192, which i can only assume that it is setting up a frame. i’ll investigate more on this later.
its pushes a zero on the stack followed by a dereference to [ebx+1Ch]

by now, i know that ebx contains the memory address 0x80483D0 + 28 = 0x80483EC. going back to the function array, i verified that this is the offset of _exit. then, pushes 0x76 on the stack.

next comes mov esi, offset word_8048326, i followed the offset to a bunch of byte declarations. pressed ‘A’ and the message made itself known. obviously, the next instruction makes edi zero. then i followed the jmp to another block of instructions.

LOAD:080481C0 loc_80481C0:
LOAD:080481C0		push	esi
LOAD:080481C1		push	1
LOAD:080481C3		call	dword ptr [ebx+0Ch]
LOAD:080481C6		add	esp, 0Ch
LOAD:080481C9		dec	eax
LOAD:080481CA		cmp	edi, 13h
LOAD:080481D0		jnz	short loc_80481D3
LOAD:080481D2		retn

more pushes, then again, we have a libc function dereferenced via offset. quick math tells us that we are now calling the write() function in the array of function pointers. before the call to the write function write(1, message, 118) - the crackme is printing the banner message to stdout.

it then cleans the stack and decrements the return value of write() = 118. it compares edi to 13h, which toggles the zero flag to off, making the jnz short loc_80481D3 resolve. because edi = 0.

LOAD:080481D3 loc_80481D3:
LOAD:080481D3			lea	edi, [ebx+20h]
LOAD:080481D6			push	12h
LOAD:080481D8			pop	esi

what the above does is to load the address of a buffer in edi and sets esi to 0x12 (18)

LOAD:080481D9 loc_80481D9:
LOAD:080481D9			call	dword ptr [ebx+8]	; call getchar()
LOAD:080481DC			or	eax, eax		; set the sign flag
LOAD:080481DE			js	short loc_804823E	; exit()
LOAD:080481E0			cmp	al, 20h			; input is a space?
LOAD:080481E2			jz	short loc_8048129	; yeah, skip it.
LOAD:080481E4			cmp	al, 9			; more check
LOAD:080481E6			jb	short loc_80481EC	; process
LOAD:080481E8			cmp	al, 0Eh			; more more check
LOAD:080481EA			jb	short loc_80481D9	; sanity skip

and then the next block (LOAD:080481EC) is a repetition of the getchar() block still with the same checks. it also saves the character to the buffer pointed to by EDI. 18 characters all in all.

LOAD:080481EC: loc_80481EC:
LOAD:080481EC			stosb				; al to edi
LOAD:080481ED			dec	esi			; decrement character counter
LOAD:080481EE			jz	short loc_8048203	; 18 characters max

ultimately, it forwards control to LOAD:08058203 that first null terminates the string we just inputted loads esi with the start of the buffer holding our string and calls a function (call sub_8048242). obviously, i had to follow the call to understand what the function does. skimming thru, i noticed that it makes some bad ass bit manipulations! (terribly frustrating to follow by pen and paper.)

some initial analysis (first dword):

1) i noticed that the whole routine only makes use of 8 characters from the userinput.
2) index [0,1,4,5] are grouped together as well as [2,3,6,7]. a total of (still) 8 characters.
3) index [0,1,4,5] from user input buffer is used as input to get the first 4 bytes of password.
4) after some bit fiddling, the result is xored with another “predefined” string inplace.
5) lastly, the final modified character array is compared byte by byte with another “predefined”
string, which i took as the password merely based on logic.

so is the entire encrypting process reversible? well, i saw a shl and imul instructions and both are “destructive” in some cases. for now, going with the flow sounds more promising.

i tried implementing the first few instructions that deals with index [0,1,4,5]. getting the byte values was simply just a matter of following the cross reference in ida and pressing ‘d’ to tell it to view things as data.

these were the initial results: (tnoice that only first letters are changing.)

misha@heaven ~/veneta $ ./find_key
found: u--ay--
found: u--ay--
found: %u--ay--
found: -u--ay--
found: 5u--ay--
found: =u--ay--
found: Eu--ay--
found: Mu--ay--
found: Uu--ay--
found: ]u--ay--
found: eu--ay--
found: mu--ay--
found: uu--ay--
found: }u--ay--

from here on, things were pretty simple. there are 3 constant characters visible in the string now. i went all-or-nothing, brute force. i finished the asm function i made earlier to include the remaining bit manipulations then linked it to a c file.

ran the program again and got some hits…

misha@heaven ~/veneta $ ./find_key
found! Mudvay(!
found! Mudvay(#
found! Mudvay(%
found! Mudvay('
found! Mudvay(A
found! Mudvay(C
found! Mudvay(E
found! Mudvay(G
found! Mudvay(a
found! Mudvay(c
found! Mudvay(e
found! Mudvay(g
--- sniped ---

i picked a random one and it worked.

misha@heaven ~/veneta $ ./cm1 
	
        CrackME (v1 Linux) (CM11) by veneta//MBE
        mail:veneta8@poczta.onet.pl
        site:veneta.prv.pl
	
                        Write Your Password:Mudvay(A
	
        OK Cracked Now mail me :) 

parting words:

the badass_crypt() function was a killer.

Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2006/11/16/venetas-linux-crackme-v1/trackback/

No comments yet.

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