DASCTF2021伪随机数题

自能生羽翼,何必仰云梯


代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
error_reporting(0);
session_start();
highlight_file(__FILE__);

include "flag.php";
$login = $_GET['id'];

if(!@isset($login['cookie'])||$login['cookie'] != @md5($_SESSION['flag'])){
die('error!');
}else{
mt_srand(substr($login['cookie'],17,7));
$content = "<?php \$flag="."'".$flag."'"."?>";
$filename = (string)mt_rand().".php";
file_put_contents($filename,$content);
mt_srand(mt_rand());
if ($_POST['key'] == mt_rand())
{
echo file_get_contents(${$_POST[mt_rand()]});
}
}

error_reporting(0) 关闭所有PHP错误报告

session_start() 初始化session

highlight_file(__FILE__) 对当前文件进行语法高亮显示

开头先包含了一个 flag.php 文件进来,然后通过 GET 传入 id 赋值给 login 变量

1
2
include "flag.php";
$login = $_GET['id'];

判断,如果 login 里没有 cookie 这个参数,或者 cookie 参数不等于 md5 后的 session flag 值 ,满足一个条件,就直接 die

1
2
if(!@isset($login['cookie'])||$login['cookie'] != @md5($_SESSION['flag'])){
die('error!');}

满足这个条件很简单,cookie 设置 flag=123456 ,然后把 123456 进行 md5 加密后传给cookie

走进 else 里面

1
mt_srand(substr($login['cookie'],17,7));

把传入的 cookie 值从第17位起,后面的7位截取出来做种子(我这里截取出来就是 9800998 ),然后传给 mt_srand() 函数做种子

mt_scand(seed) 这个函数分发种子,然后再通过 mt_rand() 函数来生成随机数

这个题的核心考点也就是关于这个函数使用不当产生的漏洞利用:同一个种子下生成的随机数值是相同的

网上有大佬做的实验:

设置固定种子后,后面每次执行,随机数也都相同,这证明了破解随机种子的可行性

再往下

1
2
3
$content = "<?php \$flag="."'".$flag."'"."?>";
$filename = (string)mt_rand().".php";
file_put_contents($filename,$content);

写入内容赋值给 content 变量里,变量 flag 应该是包含开头的 flag.php文件里面的

然后 filename 等于一个 mt_rand() 生成的随机数,使用我们的种子(9800998)生成一个随机数看看

生成的第一个随机数是:1160121479,证明我们生成的文件名应该就是 1160121479.php

然后就是把第一行的内容写入到第二行的文件里面,生成文件

继续往下

1
2
3
4
5
mt_srand(mt_rand());
if ($_POST['key'] == mt_rand())
{
echo file_get_contents(${$_POST[mt_rand()]});
}

发现又使用了新的种子,我们在本地也模拟一下

发现使用新的种子生成的随机数是 954576979 1277894509

得出后续的随机数后,继续往下跟

1
2
3
4
if ($_POST['key'] == mt_rand())
{
echo file_get_contents(${$_POST[mt_rand()]});
}

判断POST里面的 key 需要等于 mt_rand() 随机值,我们把新种子生成的第一个随机数 954576979 传进去

成功走进 if 里面,然后下面就是一个动态变量覆盖,不过他的值又需要下一个随机数,我们上面已经算出来了,下一个随机数是1277894509

然后我们把变量 filename 传给他,他可以直接请求到变量文件里面的 flag

最后一个语句就类似变成了 file_get_contents($filename) ,把 flag 文件给我们读取出来了