本文已参与「新人创作礼」活动,一起开启掘金创作之路。
书接上文
example2
猜字符串游戏(大小写字母+数字),猜中全部20位得flag+送去非洲,你不小心偷看到了一部分是:
NssQvWQ6a1
不知所云,看看有啥提示
看源码发现有个check.php,直接访问一下
NssQvWQ6a1
<?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");
大体看了一下,我认为是一个随机的种子分配一个值,我们就是要找到种子数
首先用到一个工具php_mt_seed-4.0
我们要先转换,把数据转能工具能解读的状态
这里直接贴一个脚本
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='NssQvWQ6a1'
str3 = str1[::-1]
length = len(str2)
res=''
for i in range(len(str2)):
for j in range(len(str1)):
if str2[i] == str1[j]:
res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
break
print(res)
接出来
49 49 0 61 18 18 0 61 18 18 0 61 52 52 0 61 21 21 0 61 58 58 0 61 52 52 0 61 32 32 0 61 0 0 0 61 27 27 0 61
kali先进入文件夹,然后make
之后time ./php_mt_seed 第一个随机数
Found 0, trying 0x36000000 - 0x37ffffff, speed 45.9 Mseeds/s
seed = 0x37d845d8 = 936920536 (PHP 7.1.0+)
之后用脚本转字符
需要注意的一点是,php版本要对的上才能跑出来正确的字符,很关键的一步
<?php
mt_srand(936920536);
$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>";
?>
[Running] php "c:\Users\XINO\Desktop\1 (2).php"
NssQvWQ6a1O0pXe8nMxb
[Done] exited with code=0 in 0.135 seconds
直接出交上就给flag
flag{c8be10cb-9d75-4cdb-85f8-d0a8e329863a}
example3
MRCTF2020]Ezaudit
源码泄露可以在www.zip下载源码
<?php
header('Content-type:text/html; charset=utf-8');
error_reporting(0);
if(isset($_POST['login'])){
$username = $_POST['username'];
$password = $_POST['password'];
$Private_key = $_POST['Private_key'];
if (($username == '') || ($password == '') ||($Private_key == '')) {
// 若为空,视为未填写,提示错误,并3秒后返回登录界面
header('refresh:2; url=login.html');
echo "用户名、密码、密钥不能为空啦,crispr会让你在2秒后跳转到登录界面的!";
exit;
}
else if($Private_key != '*************' )
{
header('refresh:2; url=login.html');
echo "假密钥,咋会让你登录?crispr会让你在2秒后跳转到登录界面的!";
exit;
}
else{
if($Private_key === '************'){
$getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password'".';';
$link=mysql_connect("localhost","root","root");
mysql_select_db("test",$link);
$result = mysql_query($getuser);
while($row=mysql_fetch_assoc($result)){
echo "<tr><td>".$row["username"]."</td><td>".$row["flag"]."</td><td>";
}
}
}
}
// genarate public_key
function public_key($length = 16) {
$strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$public_key = '';
for ( $i = 0; $i < $length; $i++ )
$public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1);
return $public_key;
}
//genarate private_key
function private_key($length = 12) {
$strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$private_key = '';
for ( $i = 0; $i < $length; $i++ )
$private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1);
return $private_key;
}
$Public_key = public_key();
//$Public_key = KVQP0LdJKRaV3n9D how to get crispr's private_key???
简单看一眼,传用户名密码私钥,
username= 'crispr' 已经固定,我们无法再改,密码可控,我们可以尝试万能密码,重点在怎样用公钥求私钥
function private_key($length = 12) {
$strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$private_key = '';
for ( $i = 0; $i < $length; $i++ )
$private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1);
return $private_key;
}
根据私钥加密算法会发现随机数的生成用了mt_rand函数,该地方存在一个伪随机数的问题
用固定脚本去跑一下
str1 ='KVQP0LdJKRaV3n9D'
str2 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
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)
用工具php_mt_seed跑出来
seed = 0x69cf57fb = 1775196155 (PHP 5.2.1 to 7.0.x; HHVM)
加密
<?php
mt_srand(1775196155);
//公钥
function public_key($length = 16) {
$strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$public_key = '';
for ( $i = 0; $i < $length; $i++ )
$public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1);
return $public_key;
}
//私钥
function private_key($length = 12) {
$strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$private_key = '';
for ( $i = 0; $i < $length; $i++ )
$private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1);
return $private_key;
}
public_key();
echo private_key();
?>
得到
XuNhoueCDCGc
在登录界面填上就行
总结
挺多CTF题都是从CVE提取出来的关键代码出的,本文讲的便是17年php爆出了一个可以根据随机种子可以被逆推的漏洞。有兴趣的小伙伴可以去了解一下,本文就不过多叙述了。