Seal’s Pwn Zero2Hero Stack Challenges - SROP
The 10th challenge from Seals PWN Zero2Hero
Source was provided.
; nasm vuln.nasm -f elf64
; ld vuln.o -o vuln -z noexecstack
global _start
section .text
_start:
;char buf[0x100]
enter 0x100, 0
call timer
; write(1, message, len)
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, len
syscall
; read(0, buf, 0x1000)
mov rax, 0
mov rdi, 0
mov rsi, rsp
mov rdx, 0x1000
syscall
; epilogue
leave
ret
timer:
;alarm
mov rdi, 0xf
mov rax, 0x25
syscall
ret
section .data
message: db "To pass this challenge you need to get a shell using /bin/sh"
len: equ $-message
Gist is that we have some assembly code that prints To pass this challenge you need to get a shell using /bin/sh
using the write
syscall and reads in input using the read
syscall
Vulnerability
The read
syscall reads in 0x1000 bytes while our buffer is only 0x100. That makes this is a standard buffer overflow.
Exploitation
We’ll need to use the SROP (Sigreturn-Oriented Programming) technique to solve this challenge. To do that we’ll need:
- A
pop RAX
gadget - will be used to set the syscall to 0xf (sigreturn) - A pointer to the
/bin/sh
string - A gadget for
syscall
Once we find all those we can start building out our exploit.
The first issue we run into though, is that there is no pop RAX
gadget. To mitigate this we could use the read syscall and make it read 0xf bytes. Unfortunately, we end up overwritting the return address with the second read call and the final new line that gets sent causes sigbus errors. So Instead, we can use the alarm syscall because the return value is whatever the number of seconds remaining was for a previously set alarm. Otherwise, the return value is zero if there isn’t another alarm. We can use alarm syscall to set RAX because return values are stored in RAX
for x64 architectures. To do this we’ll just jump to the alarm syscall initially to set RAX
and then continue.
/bin/sh
can be found using next(elf.search(b'/bin/sh')
pretty much the same way as finding it in libc.
For the syscall
gadget we can grab it using ROPGadget.
Now we just need the offset for controlling the instruction pointer which is 264.
Now that we have that, we need to contruct our sigreturn frame which will contain our execve
syscall.
Next we can start contructing our final exploit. We’ll be jumping to alarm first, calling it twice, and then call the sigreturn syscall
Solution
Running the script gets the flag.