一、源码
mt_srand.php
<?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()]});
}
}
flag.php
<?php
$flag='DASCTF{34cbc70d00d131c96e2e918238dafd68}'
?>
二、解题步骤
利用原理:
相同的种子生成的随机数是相同的。
知道种子后,可以确定输出伪随机数的序列。
知道随机数序列,可以确定种子。
1.绕过IF判断
if(!@isset($login['cookie'])||$login['cookie'] != @md5($_SESSION['flag']))
输出为FALSE方可进入else循环,由于判断条件为 || (或),所以必须左右两边都为FALSE
拆分为 !@isset($login['cookie'])
与 $login['cookie'] != @md5($_SESSION['flag'])
由于!@isset($login['cookie'])
必定为FALSE,所以必须让 $login['cookie']
与 @md5($_SESSION['flag'])
相等
本地写 md5($_SESSION['flag'])
结果,源码如下
<?php
error_reporting(0);
session_start();
$a=md5($_SESSION['flag'];
echo $a;
?>
得到 md5($_SESSION['flag'])
的值
由于$login['cookie']
为在$login中取[‘cookie’]值,根据源码,GET传参,id[cookie]=d41d8cd98f00b204e9800998ecf8427e
error消失,绕过IF判断
2.伪随机数
源码第10行:
mt_srand(substr($login['cookie'],17,7));
以cookie中第17位开始向后7位,播种随机数生成器。
源码第12行 :
$filename = (string)mt_rand().".php";
返回一个随机数,并加上.php后缀,赋给$filename
源码第14行:
mt_srand(mt_rand());
以随机数生成器生成的第二个随机数重新生成新的随机数生成器
源码第15行
if ($_POST['key'] == mt_rand())
POST传参,令参数key与新的随机数生成器生成的随机数相等,即可进入IF判断
源码第18行
echo file_get_contents(${$_POST[mt_rand()]});
生成第二个随机数
本地构写几个mt_rand()结果,源码如下
<?php
error_reporting(0);
session_start();
mt_srand(substr('d41d8cd98f00b204e9800998ecf8427e',17,7));
echo mt_rand().'</br>'; //源码第12行生成的随机数
mt_srand(mt_rand()); //生成新的随机数生成器
echo mt_rand().'</br>'; //源码第15行新的随机数生成器生成的随机数
echo mt_rand().'</br>'; //源码第18行新的随机数生成器生成的第二个随机数
?>
第一行为源码第12行生成的随机数
第二行为源码第15行新的随机数生成器生成的随机数
第三行为源码第18行新的随机数生成器生成的第二个随机数
3.取FLAG
再看第18行源码:
echo file_get_contents(${$_POST[mt_rand()]});
POST传参,参数名为新的随机数生成器生成的第二个随机数
注意: 在$_POST[mt_rand()] 前还有一个$符,则代表传入的参数将成为另一个变量名,例如传入filename
则此句将会变为
echo file_get_contents($filename);
依据源码第12行,传入filename,即可读取$filename的值,也就是新flag文件的文件名
构造payload
post传参key=954576979&1277894509=filename(参数key进入18行的if循环,参数1277894509传入变量名)
进入F12查看源码
在源码中发现FLAG
写一半后接着写的时候发现靶场关闭了,后半段为本地靶场演示