[GWCTF 2019]枯燥的抽奖

查看页面源码可以看到一段JS代码:

javascript 复制代码
$(document).ready(function(){
    $("#div1").load("check.php #p1");

        $(".close").click(function(){
        		$("#myAlert").hide();
    });	     

    $("#button1").click(function(){
    	$("#myAlert").hide();
    	guess=$("input").val();
		$.ajax({
	   type: "POST",
	   url: "check.php",
	   data: "num="+guess,
		   success: function(msg){
		     $("#div2").append(msg);
		     alertmsg = $("#flag").text(); 
		     if(alertmsg=="没抽中哦,再试试吧"){
		      $("#myAlert").attr("class","alert alert-warning");
		      if($("#new").text()=="")
		     	$("#new").append(alertmsg);
		     }
		     else{		     	
		     	$("#myAlert").attr("class","alert alert-success");
		     	if($("#new").text()=="")	
		     		$("#new").append(alertmsg);	
		     }

		 
		   }
		}); 
		$("#myAlert").show();
		$("#new").empty();
		 $("#div2").empty();
	});
});

这段代码实现了一个与后端 check.php 交互的功能,通过 AJAX 提交用户输入,根据后端返回结果显示不同的提示信息。

通过抓包获取后端响应:

php 复制代码
y5DXaGgCOC

没抽中哦,再试试吧
<?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"); 

随机生成一个SESSION['seed']并且当作生成随机数的种子值。同一个种子每次运行随机生成的序列都是相同的:

但是在本题中种子值也是随机生成的,我们不知道。但是我们可以本地跑出来,因为给了我们随机序列的前十位。

种子随机范围太大了。跑不了一点。只能换个思路.......

用爆破工具php_mt_seed。首先将题中给出的前十位转换成原始数列:

php 复制代码
<?php
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$max = strlen($str_long1)-1;
$min = 0;
$str = 'ZrNsqX9wYd';
for ($i = 0; $i < strlen($str); $i++) {
    $s = $str[$i];
    $num = strpos($str_long1, $s);
    if ($num !== false) {
        echo "$num $num $min $max "; //这是官方文档指定的格式
    }
}

得到

61 61 0 61 17 17 0 61 49 49 0 61 18 18 0 61 16 16 0 61 59 59 0 61 35 35 0 61 22 22 0 61 60 60 0 61 3 3 0 61

然后使用php7.1.1+使用该随机种子利用题目源码生成序列:

php 复制代码
<?php
mt_srand(798533660);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
echo $str_show = substr($str, 0, 20);

最后成功拿到flag。

总结一下:首先客户端网页源代码是由JS程序控制,需要通过抓包直接查看服务端响应获得源码提示。然后利用php_mt_seed工具爆破随机种子。