mt_srand以及mt_rand函数的伪随机数爆破

mt_srand以及mt_rand函数的伪随机数爆破

mt_srand()函数以及mt_rand()函数

mt_scrand(seed)这个函数的意思是,通过分发seed种子,然后种子有了后,靠mt_rand()生成随机数

实例

1
2
3
4
<?php
mt_scrand(12345);
echo mt_rand()."<br/>";
?>

但是生成的随机数是有线性关系的,所以可以理解为伪随机数,因此我们可以

1
2
3
1. 知道种子后,确定伪随机数的序列

2. 知道你的随机数序列后,确定种子

所以我们可以使用php_mt_seed爆破

1
2
3
下载地址:https://www.openwall.com/php_mt_seed/

如果用make命令安装报错的话,可以参考这篇文章:https://www.coder.work/article/7305572

打开题目后,我们可以看见10个字符,然后我们猜后面10个字符

1
前10个字符:xxxq9Bgc67

然后打开页面源码,发现一串代码中有一个可疑文件check.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$(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文件,发现源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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_long1中获取相应的20个字符
}
$str_show = substr($str, 0, 10); # 取出20个字符中的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");

所以我们需要知道前10个字符的随机数是多少,从而爆破出种子数,exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
str1 ='xxxq9Bgc67'
str2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result =''


length = str(len(str2)-1)
for i in range(0,len(str1)):
for j in range(0,len(str2)):
if str1[i] == str2[j]:
result += str(j) + ' ' +str(j) + ' ' + '0' + ' ' + length + ' '
break


print(result)

然后在ubuntu中运行这个命令

1
./php_mt_seed 23 23 0 61 23 23 0 61 23 23 0 61 16 16 0 61 35 35 0 61 37 37 0 61 6 6 0 61 2 2 0 61 32 32 0 61 33 33 0 61

其中23是随机数,0和61是范围,下面的数以此类推,但是如果mt_rand()没有设定范围的话,直接将生成的随机数放进php_mt_seed中爆破即可

发现只有一个php7.1+版本的种子,但是运行php脚本的版本必须在7.4以上才可以成功,所以exp

1
2
3
4
5
6
7
8
9
10
<?php
mt_srand(929507679);
$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 "<p id='p1'>".$str."</p>";
?>

即可得到20个字符,获取flag