mt_rand伪随机数爆破
mt_rand伪随机数爆破
前置知识
mt_rand用法:
mt_rand()
mt_rand(min,max)
PHP mt_rand安全杂谈及应用场景详解 - FreeBuf网络安全行业门户
CTF| web篇之伪随机数 - FreeBuf网络安全行业门户
伪随机数安全问题
爆破出种子后,随机数可预测,导致加密不安全
爆破工具php_mt_seed
工具来源:
https://github.com/openwall/php_mt_seed.git
使用方法:
-
php_mt_seed expects 1, 2, 4, or more numbers on its command line. The
numbers specify constraints on mt_rand() outputs.
-
When invoked with only 1 number, that's the first mt_rand() output to
find seeds for. -
When invoked with 2 numbers, those are the bounds (minimum and maximum,
in that order) that the first mt_rand() output should fall within. -
When invoked with 4 numbers, the first 2 give the bounds for the first
mt_rand() output and the second 2 give the range passed into mt_rand(). -
When invoked with 5 or more numbers, each group of 4 and then the last
group of 1, 2, or (usually) 4 are processed as above, where each group
refers to a corresponding mt_rand() output.
可预测性验证:
用例1:
扔到php_mt_seed中进行爆破,看对应的版本拿所需的seed
可以看出知道种子后随机的结果就可以预测出来了
其他用例
而对于其他用例,可以看回这篇文章中的随机验证码还原后爆破,那里使用了用例4
的方式
PHP mt_rand安全杂谈及应用场景详解 - FreeBuf网络安全行业门户
CTF例题
[GWCTF 2019]枯燥的抽奖
通过查看网页源码后发现是通过check.php返回的值来判断是否给flag。
check.php源码
waZCyrr25g
<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}
mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";
if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>没抽中哦,再试试吧</p>";
}
}
show_source("check.php");
给到的 waZCyrr25g
是$str
的前10位,我们需要猜出来完整的$str
才能得到flag。$str
由$str_long1
中每次截取1位,而且此位取自第mt_rand(0,len)
位,最后组成20位的字符串
还原出随机数
<?php
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='waZCyrr25g';
$seed='';
for($i=0;$i<strlen($str);$i++){
$seed=strpos($str_long1,$str[$i]);
echo $seed.' ';
}
//结果:22 0 61 38 24 17 17 28 31 6
//但是这些随机数是多次随机出来的结果,所以要转化为符合爆破脚本的格式
//即用例4:前两个数字输入随机数的边界(不理解,但是感觉对整数来说是它本身,小数来说是上下取证),后两个数字输入随机数的范围
php_mt_seed格式
<?php
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='waZCyrr25g';
$seed='';
for($i=0;$i<strlen($str);$i++){
$seed=strpos($str_long1,$str[$i]);
echo $seed.' '.$seed.' 0 61 ';
}
//结果:
//22 22 0 61 0 0 0 61 61 61 0 61 38 38 0 61 24 24 0 61 17 17 0 61 17 17 0 61 28 28 0 61 31 31 0 61 6 6 0 61
seed爆破
seed是750772741 ,然后放回去check.php中计算出$str完整的值,提交$str即可获得flag