PHP 伪随机数

题目一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
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');
}
?>

tips

mt_srand():播种函数。伪随机数,种子相同,通过mt_rand()生成的一系列随机数必然相同。也就是两次播种的种子是同一个,这两次播种后每次用mt_rand()生成的随机数都互相对应。如:

1
2
3
4
5
6
7
8
9
10
<?php
mt_srand(114);
echo mt_rand().'<br>';//325627173
echo mt_rand().'<br>';//271482249
mt_srand(114);
echo mt_rand().'<br>';//325627173
echo mt_rand().'<br>';//271482249
mt_srand(514);
echo mt_rand().'<br>';//1025750179
echo mt_rand().'<br>';//490569148

mt_rand():随机数函数。可以直接用,也可以设定最大与最小值(参数1和参数2)

本题找个 PHP 解释器生成一下伪随机数,然后通过 URL 发送 GET 请求即可。


题目二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
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');
}

本题随机数种子固定 hexdec(substr(md5($flag), 0,8)) ,**$_GET['r'] 与首次生成的随机数不等时会返回两数相减的值,相等且 $_COOKIE['token'] 等于第二三次生成随机数之和**时会返回 flag 。

可以先把已生成的随机数得出来:?r=0,记得去掉负号,于是返回 flag 的第一重条件满足了。

通过伪随机数得到种子比较困难,好在有大佬写了工具 php_mt_seed ,把源码编译完即可运行。

https://github.com/openwall/php_mt_seed

在源码目录中编译

1
make

运行,<seed> 为种子。

1
time ./php_mt_seed <seed>

运行后选择 PHP 7.0 以上版本(结合题目提供的操作系统版本信息得知)的种子,每个生成三次随机数待使用。

打开 burp 抓包。修改 URL 中参数 r ,并添加 Cookie: token= ,值为某种子第二三次随机数的和(要多试几次不同的种子)。

手动修改 Cookie 时,一定要注意 burp 内的报文格式!若是请求体为空,则最后有两行空行(请求空行和请求体),这点与一般认知(请求空行作为最后一行表示请求体为空)不同。

手动修改时没注意,好几次发包响应报文都是完全空白。建议在 Proxy 模块的 Intercept 页或 Repeater 模块这两处右方的 Inspector 区域修改。

最后以正确格式发包,得到有 flag 的响应,OK。