tips:一些可能涉及伪随机数的CTF题目类型
- 伪随机数生成器预测:在这类题目中,你可能需要预测一个伪随机数生成器的输出。这通常涉及到对伪随机数生成器的工作原理的理解和分析,以及找出它的弱点。
- 重播攻击:如果一个系统使用伪随机数生成器生成的序列作为一次性密码,那么重播攻击可能是一个问题。在这类题目中,你可能需要捕获并重播一些通信来达到某个目标。
- 种子恢复:如果你能够观察到一个伪随机数生成器的输出,你可能能够恢复它的种子。这通常需要对伪随机数生成器的内部状态进行某种形式的推断。
- 状态恢复攻击:某些伪随机数生成器的设计使得它们容易受到状态恢复攻击。在这类题目中,你可能需要通过观察一些输出来恢复生成器的内部状态。
- 流密码破解:许多流密码依赖于伪随机数生成器来产生密钥流。如果这个生成器有弱点,那么密码可能会被破解。
知识点补充:Z3约束器
1.伪随机数介绍:
1.伪随机数的运行机制:
假设有
a1=f(seed)
,an+1=f(an)
,那么就可以得到一个序列a1,a2,a3...an
制作一个伪随机数也就是让其每次返回序列的下一个元素,如图:
对于
java.utiol.Random
,比较老的C语言的rand()
库,和一部分php的rand()
,它们使用的就是这种线性的随机数方法。这种方法一开始一般会取一个48bit的值作为seed直接放到state0里,而每个新的state的产生方式则为: next_state=(state * multiplier + addend) mod (2 ^ precision)
(state为老的state,后面三个为固定的常量(multiplier
=25214903917,addend
= 11,precision
= 48))。而从state计算到output的过程如下图:
output:为原数据右移16位之后的32比特的数据
2.C语言中的随机数函数:(rand,srand)
rand和srand是用于产生伪随机数的两个函数,其返回值为[0,RAND_MAX]之间的数据
1.rand函数:
rand()函数是使用线性同余法做的,它并不是真的随机数,因为其周期特别长,所以在一定范围内可以看成随机的。
2.srand函数:
srand()为初始化随机数发生器,用于设置rand()产生随机数时的种子
tips
一般为了srand值相同导致的产生随机数值相同,随机数种子考虑使用时间(
srand(time(NULL))
)2.关于随机数的攻击方式:
对于随机的攻击来说可以分为两种情况考虑,一种是可以通过逆向算法来获取到随机数的情况,另一种是只能得到生成的随机数,需要想办法逆推出种子的情况。
情况一:根据算法推出种子
这种情况基本就是看它的随机数是怎么得出来的,目前见过的都是建立方程组然后用z3约束器求解
根据算法推出种子的逆向实例情况二:根据生成的随机数推出种子
ATTACK1:
当我们能够获得两个连续的output时:

假设获得到的output为0和1,state0右移十六位得出out0,state1右移十六位得出out1,设state的右16位为x,可设立方程
out0<<16+x=state0
,将这个带着x的state0做线性变换就可以得出state1,再将带着x的state1右移16位则得到了out1,。通过建立方程得出state0后就可以得出所有的state(这里可能会有疑问明明是一元一次方程为啥还需要知道state1,因为右移的操作可能会导致有多个x的值加上左移16位后的out0等于state0,为了确定是哪个所以需要state1)- multiplier = 25214903917
- addend = 11
- next_state = (state * multiplier + addend) & 0xFFFFFFFFFFFF
- outout = state >> 16
ATTACK2:
Ruby’s rand( ),Python’s random module,PHP’s mt_rand( )
1.这类的随机数基本原理为:
- state以一次624个int为一组生成的,也就是说生成state时一次生成624个state,然后才会进行下一次state的生成

- 生成output的方法:
这里的操作虽然很复杂,但和上面的
java.utiol.Random
不同它是用的循环右移,所以并不会破坏原来的值- 新的624个state的生成方法:
每一个新的state都与之前624个state中的第一个,第二个和第398个有关
- 攻击条件:
- 需要知道624个output
- 因为绿色箭头部分的操作是可逆的,所以只要知道624个output就可以逆推出一整个state块的值从而获得到下一块的state和output
