CTF赛题 / 靶场writeup · 2021年9月9日 1

CTF-伪随机数赛题

一、源码

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