qnix’s qcrk2
before anything else, my recent soundtrip. oldies songs, specifically everly brothers, gin blossoms and “yakap sa dilim by APO hiking society”
so i found time to solve another crackme -qnix’s qcrk2
Difficulty: 2 - Needs a little brain (or luck)This is a binary ELF crackme programmed in C for Linux
you should make the programe print CRACKED .Rules : NO PATCHING .
HINT : BOF
Platform: Unix/linux etc.
Language: C/C++
there is anti-ptrace but no environment variable detection e.g. LD_PRELOAD so a ptrace wrapper did all the trick. anyway, onto relevant blocks…
first, the argv[1] handler…
804850d: 8b 45 0c mov eax,DWORD PTR [ebp+12] ; argv[0] 8048510: 83 c0 04 add eax,0x4 ; argv[1] 8048513: 83 ec 0c sub esp,0xc 8048516: ff 30 push DWORD PTR [eax] 8048518: e8 6f fe ff ff call 804838c <strlen@plt> ; strlen(argv[1]) 804851d: 83 c4 10 add esp,0x10 8048520: 3d ff 03 00 00 cmp eax,0x3ff ; 1023d 8048525: 76 3b jbe 8048562 <main+0xea> ; copy to buffer1 ; -- snipped. crackme error/overflow protection block -- 804855d: e9 1c 01 00 00 jmp 804867e <main+0x206> ; exit(0);
we move now to the second user argument handler
80485c2: 8b 45 0c mov eax,DWORD PTR [ebp+12] ; argv[0] 80485c5: 83 c0 08 add eax,0x8 ; argv[2] 80485c8: 83 ec 0c sub esp,0xc 80485cb: ff 30 push DWORD PTR [eax] 80485cd: e8 ba fd ff ff call 804838c <strlen@plt> ; strlen(argv[2]) 80485d2: 83 c4 10 add esp,0x10 80485d5: 3d ff 0b 00 00 cmp eax,0xbff ; 3071d 80485da: 76 38 jbe 8048614; copy to buffer2
how is argv[2] being copied anyway?
804862a: 8b 45 0c mov eax,DWORD PTR [ebp+12] ; argv[0]
804862d: 83 c0 08 add eax,0x8 ; argv[2]
8048630: ff 30 push DWORD PTR [eax] ; varg
8048632: 68 7d 88 04 08 push 0x804887d ; const char *fmt = ("%s")
8048637: 68 00 0c 00 00 push 0xc00 ; size_t
804863c: 8d 85 f8 f7 ff ff lea eax,[ebp-2056] ;
8048642: 50 push eax ; char *str
8048643: e8 74 fd ff ff call 80483bc <snprintf@plt> ; snprintf()
translated to C, the listing above is approximately equal to snprintf(buff, 3072, “%s”, argv[2]);
sizeof(buf) is more or less 2056 bytes. (as gcc’s stack allocation is a complete mystery to me) but the snprintf() is called with sizeof 3072 bytes. clearly writing past the end of the buffer.
08048686 <crap>: 8048686: 55 push ebp ; save old frame 8048687: 89 e5 mov ebp,esp ; new frame 8048689: 83 ec 08 sub esp,0x8 804868c: 83 ec 08 sub esp,0x8 ; 16 bytes allocation 804868f: 68 e0 88 04 08 push 0x80488e0 ; our dear string 8048694: ff 35 84 9a 04 08 push ds:0x8049a84 ; STDOUT@GLIBC 804869a: e8 dd fc ff ff call 804837c <fprintf@plt> 804869f: 83 c4 10 add esp,0x10 ; unwind stack 80486a2: b8 00 00 00 00 mov eax,0x0 ; function return value = success 80486a7: c9 leave ; restore old frame 80486a8: c3 ret ; return from function crap()
now, looking thru the listing, there was really no way that function crap() was being called from the crackme itself. no direct cross reference whatsoever.
this is where the author’s hint comes into play: BOF (buffer overflow)
1) first argument is useless.
2) second argument buffer will be filled with the address of the crap() function (0x8048686) so that the return address in the stack will be overwritten with the address of crap().
i verified those things with gdb. (using a ptrace wrapper ‘ptrace.so”)
misha@localhost ~ $ gdb qcrk2
niela@gdb $ set env LD_PRELOAD=./ptrace.so
niela@gdb $ r tmp `perl -e 'print "a"x3071'`
---------------------------
Qcrack v2
By: Qnix
Qnix[at]bsdmail.org
www.0x11.org
---------------------------
(+) Copying argv[1] into the buffer1 ... [done] (3)
(+) Copying argv[2] into the buffer2 ... [done] (3071)
Program received signal SIGSEGV, Segmentation fault.
_______________________________________________________________________________
eax:00000000 ebx:B7F02FF4 ecx:B7F03880 edx:00000010 eflags:00010286
esi:B7F2AC80 edi:BFC27A84 esp:BFC27A30 ebp:61616161 eip:61616161
cs:0073 ds:007B es:007B fs:0000 gs:0000 ss:007B o d I t S z a P c
[007B:BFC27A30]———————————————————[stack]
BFC27A60 : 61 61 61 61 61 61 61 61 - 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
BFC27A50 : 61 61 61 61 61 61 61 61 - 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
BFC27A40 : 61 61 61 61 61 61 61 61 - 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
BFC27A30 : 61 61 61 61 61 61 61 61 - 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa
[007B:B7F2AC80]———————————————————[ data]
B7F2AC80 : 00 00 00 00 00 10 00 00 - 0C 06 02 00 EB 7B C2 BF ………….{..
B7F2AC90 : 04 00 00 00 B4 72 F0 B7 - 04 00 00 00 64 00 00 00 …..r……d…
[0073:61616161]———————————————————[ code]
0x61616161: Error while running hook_stop:
Cannot access memory at address 0x61616161
0x61616161 in ?? ()
clearly, the EIP and EBP are being overwritten with “a” (note the values in bold)
as there is already a solution by cyrex on how to overflow the stack to overwrite the return address, doing repeating that would be reinventing the wheel.
the only objective of this crackme was to make it print the string “cracked”, so i basically extended the ptrace wrapper to set up a SIGSEGV signal handler via attribute ((constructor)) to call crap() using a function pointer. and finally, force the crackme to segfault.
— crack.c –
/* gcc -shared -fPIC -o crack.so crack.c */
#include <signal.h>
#include <stdlib.h>
#define CRAP_FUNC_ADDR 0x8048686
/* call crap() on SIGSEGV */
void handler(int sig)
{
void (*fp)();
fp = (void *) CRAP_FUNC_ADDR;
fp();
exit(0);
}
/* setup a signal handler for the SIGSEGV signal */
void __attribute__ ((constructor)) qcrk_constructor()
{
signal(SIGSEGV, handler);
}
/* we don't even need this anymore */
int ptrace(int a, int b, int c, int d)
{
return 0; // always return succesfully!
}
i tried it out on the crackme and it _somehow_ works…
misha@heaven ~ $ gcc -shared -fPIC -o crack.so crack.c
misha@heaven ~ $ LD_PRELOAD=./crack.so ./qcrk2 hello `perl -e 'print "a"x3071'`
---------------------------
Qcrack v2
By: Qnix
Qnix[at]bsdmail.org
www.0x11.org
---------------------------
(+) Copying argv[1] into the buffer1 ... [done] (5)
(+) Copying argv[2] into the buffer2 ... [done] (3071)
---[[[ CRACKED ]]]---
it’s also good to reminisce aleph one’s smashing the stack for fun and profit and a former blog entry i wrote, shellcode injection via ptrace.
oh, and lastly, happy birthday daddy!

wow! teach me please
Comment by pipitaMaster — August 22, 2006 @ 10:59 am