HTB Cyber Apocalypse 2024: SoundOfSilence
Navigate the shadows in a dimly lit room,silently evading detection as you strategize to outsmart your foes. Employ clever distractions to divert their attention,paving the way for your daring escape!
TL;DR
Populate
rdi
via amov
instruction to provide parameter tosystem()
.
Challenge Overview
SoundOfSilence is an extremely minimal binary with an unbounded buffer overflow. We have control over the EIP almost immediately but there is no win function available, meaning we'll have to ROP somewhere else. The use of system()
does look quite suspicious.
In terms of binary protection, no canary and PIE base were found. This means an info leak wouldn't be necessary.
At this point, I was thinking of different ways to exploit this after controlling the EIP:
How about a simple ret2system? - No useful gadgets to control
rdi
and write/bin/sh
.How about ret2libc? - No useful GOT entries like
puts
orwrite
. Even ifwrite
exists, there is no__libc_csu_init
gadget present as well.How about ret2dlresolve? - We're dealing with large page sizes in 64-bit, plus the lack of gadgets to populate
rdi
.Since we have unlimited ROP size thanks to the no boundary check of
gets()
, how about a SIGROP attack? - There is no syscall gadget available either.How about writing
/bin/sh
to.bss
section via a write-what-where gadget, followed byexecev()
pointing back to the.bss
as shown in this writeup? - No such write-what-where gadget available.
Debugging
Since the binary was so minimal, I decided to take a look at all the register values by stepping through the instructions line-by-line. Let's take a look at the registers just before it's about to perform the ret
instruction.
To debug the binary in GDB, we'll have to enable set follow-fork-mode parent
since it uses system()
to clear the terminal during program startup.
Right before the main function returns, we can see that our user input is saved in the rax
register. This means that if we can find an instruction or gadget that copies whatever is in rax
into rdi
, we essentially satisfy all the requirements to execute system(/bin/sh)
.
Taking a look at the disassembly code, the instruction at 0x401169
fits just right into what we're looking for.
Solution
The ROP chain is fairly simple: Once we have control over the EIP, we can jump to the mov rdi, rax
instruction to populate rdi
with /bin/sh
, followed by a call to system()
to get a shell.
Flag: HTB{n0_n33d_4_l34k5_wh3n_u_h4v3_5y5t3m}
Last updated