[MRCTF2020]Ezaudit(随机数的安全)
目录
信息收集
代码审计
相关函数
前提知识
思路分析
补充知识
信息收集
查看源代码没有发现有用信息,尝试dirmap扫下目录
python3 dirmap.py -i 网址 -lcf
扫描时发现一个www.zip目录
下载到一份index.php文件,找到一个login.html
<?php
header('Content-type:text/html; charset=utf-8');
error_reporting(0);
if(isset($_POST['login'])){
$username = $_POST['username'];
$pass = $_POST['pass'];
$Private_key = $_POST['Private_key'];
if (($username == '') || ($pass == '') ||($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 pass = '$pass'".';';
$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???
代码审计
审计代码得知有login.html,想要登陆的话需要用户名、密码、密钥,并且用户名必须为crisper,密码使用1' or 1=1#,此时只需要知道秘钥即可
相关函数
substr(string,start,length)
string | 必需。规定要返回其中一部分的字符串。 |
start | 必需。规定在字符串的何处开始。
|
length | 可选。规定要返回的字符串长度。默认是直到字符串的结尾。
|
mt_rand()
函数使用 Mersenne Twister 算法生成随机整数
mt_rand(min,max);
参数 | 描述 |
---|---|
min | 可选。规定返回的最小数。默认是 0。 |
max | 可选。规定返回的最大数。默认是mt_getrandmax() 2147483647 |
前提知识
mt_srand
mt_srand([ int $seed] ) : void
用 seed 来给随机数发生器播种。 没有设定 seed 参数时,会被设为随时数。使用者在进行一次mt_srand()操作后,seed数值将被固定下来,给接下来的mt_rand()函数使用。
mt_rand()存在的问题
由于mt_rand()的生成的随机数只跟seed和调用该函数的次数有关。举一个简单的例子来说明一下这个问题,假设使用mt_srand(1111111)进行了一次播种操作,接下来调用mt_rand()函数,第一次生成的数值为a,第二次生成的为b,第三次生成的为c。任何一个人拿到这样的一串代码,所执行的结果都是跟刚刚描述的一样。所以当你的seed数值被他人知道后,就可以预测出你接下来的数值是多少,这就是该函数的一个问题,他并不能起到一个真随机数的作用。
简单举个例子
<?php
mt_srand(1234);
echo mt_rand()."</br>";
echo mt_rand()."</br>";
echo mt_rand()."</br>";
?>
411284887
1068724585
1335968403由1234产生的数值前三个固定为上面的值,当对手知道你的第一次为411284887时便能猜测你的seed和下一次生成的数值,因为同一个种子产生的随机数只会根据调用次数的不同产生不同的数。
思路分析
使用python脚本先将公钥转换成脚本能识别的数列
str1 ='KVQP0LdJKRaV3n9D'
str2 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
res =''
length = str(len(str2)-1)
for i in range(len(str1)):
for j in range(len(str2)):
if str1[i] == str2[j]:
res += str(j) + ' ' +str(j) + ' ' + '0' + ' ' + length + ' '
break
print(res)
36 36 0 61 47 47 0 61 42 42 0 61 41 41 0 61 52 52 0 61 37 37 0 61 3 3 0 61 35 35 0 61 36 36 0 61 43 43 0 61 0 0 0 61 47 47 0 61 55 55 0 61 13 13 0 61 61 61 0 61 29 29 0 61
36 36 0 61 47 47 0 61 42 42 0 61 41 41 0 61 52 52 0 61 37 37 0 61 3 3 0 61 35 35 0 61 36 36 0 61 43 43 0 61 0 0 0 61 47 47 0 61 55 55 0 61 13 13 0 61 61 61 0 61 29 29 0 61
kali开一个php_mt_seed来跑种子
tar zxvf php_mt_seed-4.0.tar.gz
make
chmod 777 php_mt_seed-4.0/
time ./php_mt_seed 36 36 0 61 47 47 0 61 42 42 0 61 41 41 0 61 52 52 0 61 37 37 0 61 3 3 0 61 35 35 0 61 36 36 0 61 43 43 0 61 0 0 0 61 47 47 0 61 55 55 0 61 13 13 0 61 61 61 0 61 29 29 0 61
种子为1775196155,PHP版本为(5.2.1-7.0.x)
<?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;
}
echo public_key() . "<br>";
echo private_key();
?>
这里我们PHP版本是5.3.29
KVQP0LdJKRaV3n9D
XuNhoueCDCGc
因此私钥为
XuNhoueCDCGc
拿到flag
补充知识
kali的apt命令
apt-get 功能
apt-get 安装软件包
apt-get remove 删除软件包
apt-get remove 更换所有包
apt-get purge 移除软件包及配置文件
apt-get upgrade 更新所有软件包(自动处理依赖项)
apt-get autoremove 自动删除不需要的包
apt-get dist-upgrade 在升级软件包时自动处理依赖关系
apt-cache search 搜索应用程序
apt-cache 显示安装细节
1.安装软件
apt-get install {包名}
2.更新软件
apt-get install update
3.软件包升级
apt-get upgrade
4.系统版本升级
apt-get dist -upgrade 注意:要先进行软件包升级才可以进行系统版本升级
5.移除软件
apt-get remove {包名}
6.自动移除系统不需要的旧的软件包
apt-get autoremove
7.完全移除,除了移除所需文件之外还移除配置文件以及历史文件
apt-get purge {包名}
8.清理已经安装过的软件包
apt-get clean