php伪随机数安全

随机数真的随机吗?

PHP中的随机函数

在PHP中,常用的随机数生成算法有rand(),mt_rand().

这两个函数各有最大范围不超过2147483647,rand()的范围是很小的,非常不安全的,所以一般用mt_rand().

<?php
//on windows
print getrandmax();//2147483647
print mt_getrandmax();//2147483647
?>

然鹅mt_rand()在实现上也有缺陷.

伪随机数是由数学算法来实现的,真正随机的地方在于种子.种子一旦确定,再通过同一随机数算法计算出来的随机数,值是固定的.多次计算所得值得顺序也是固定的

在PHP4.2.0之前的版本,必须要通过srand()或mt_srand()给rand()或mt_rand()播种,

在PHP4.2.0之后的版本,事先可以不再通过srand()或mt_srand()播种. 如直接调用mt_rand(),系统会自动播种.

但是,可能为了和之前版本兼容,PHP代码里面还会这样写:

mt_srand(time());
mt_srand((double) microtime() * 100000);
mt_srand((double) microtime() * 1000000);
mt_srand((double) microtime() * 10000000);

但是,时间也不是随机的 . 攻击者通过某种方式获取系统时间,就可以短时间内枚举出种子

上面提到的如果不播种,系统会自动播种,系统播种种子范围为0-2^32(32位系统),这样似乎也能枚举emm

固定的种子

下面谈谈种子固定会发生什么?

**在同一进程中,同一个seed,每次通过mt_rand()生成的值都是固定的: **

rand.php:

<?php
mt_srand(1);
echo mt_rand().'<br/>';
echo mt_rand().'<br/>';
echo mt_rand().'<br/>';
echo mt_rand().'<br/>';
echo mt_rand().'<br/>';
echo mt_rand().'<br/>';
?>

无论访问这个页面多少次,都是上面的结果,上面的序列.正好验证了上面的结论;

得到相同的种子

这里有个trick是,可以通过Keep-Alive HTTP头,迫使服务端使用同一PHP进程相应请求,所以也就能使种子保持一直.

别的就依赖PHP程序员出错了.

获得种子

既然知道了,同一个种子生成的序列是固定的,那么也能根据序列猜测seed

工具:php_mt_seed:https://github.com/lepiaf/php_mt_seed
Linux下安装使用方法

git clone https://github.com/lepiaf/php_mt_seed 
cd php_mt_seed/
gcc php_mt_seed.c -o php_mt_seed
make

使用: ./php_mt_seed 随机数

就会根据随机数,找seed,可能会找到多个,就需要自己验证哪个seed符和条件了

CTF题目

题目来自@https://ctf.show/

0x01

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 13:26:39
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 13:53:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(372619038);
    if(intval($r)===intval(mt_rand())){
        echo $flag;
    }
}else{
    highlight_file(__FILE__);
    echo system('cat /proc/version');
}
 mt_srand(372619038);
 var_dump(mt_rand());//int(1155388967)

0x02

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 13:56:57
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 15:47:33
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(hexdec(substr(md5($flag), 0,8)));
    $rand = intval($r)-intval(mt_rand());
    if((!$rand)){
        if($_COOKIE['token']==(mt_rand()+mt_rand())){
            echo $flag;
        }
    }else{
        echo $rand;
    }
}else{
    highlight_file(__FILE__);
    echo system('cat /proc/version');
}

由?r=1

可以算出序列中第一个数,再跑脚本

找到两个种子,一个一个试

可以利用插件改cookie

posted @ 2020-11-12 21:48  10nnn4R  阅读(205)  评论(0编辑  收藏