本文最后更新于 219 天前,其中的信息可能已经有所发展或是发生改变。
WEB
枯燥的抽奖
题目
猜字符串游戏(大小写字母+数字),猜中全部20位得flag+送去非洲,你不小心偷看到了一部分是:
qdTh9b4OAR
解决方案
F12查看源码。
没什么奇怪的东西、
看一下响应,找到了源码。
copy一下:
FXtv4OYzcv
<?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");
大致是生成一个随机数seed(范围在0-999999999)作为mt_srand的种子,调用mt_rand(范围在0-61),生成20个数字。其中给出前十位数字,要求求出完整的字符串。
本题的漏洞在mt_rand函数只是伪随机数,只要使用相同的种子,所生成的随机数一定是固定的。
也就是只要通过前十位数字,找到了mt_rand的种子,带入,就可以求出后十位数字了。
这里使用了php_mt_seed工具: https://www.openwall.com/php_mt_seed/
按指定的四个数字一组的格式生成字符串。
写一个cpp脚本,求前十个数值的偏移量。
#include <iostream>
int main() {
std::string str1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string str2 = "qdTh9b4OAR";
std::cout << std::endl;
for (char i : str2) {
std::cout << str1.find(i) << ' ' << str1.find(i) << " 0 61 ";
}
}
开一个linux子系统,在php_mt_seed工具的根目录下:
$ time ./php_mt_seed 15 17 0 61 2 4 0 61 54 56 0 61 6 8 0 61 34 36 0 61 0 2 0 61 29 31 0 61 49 51 0 61 35 37 0 61 52 54 0 61
得到种子:
最后用搬来的php脚本(来源: http://wonderkun.cc/index.html/?p=585 )
<?php
function wp_generate_password($length) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$password = '';
for ( $i = 0; $i < $length; $i++ )
$password .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
return $password;
}
mt_srand(142242880); //手工添加了这个种子
$key = wp_generate_password(10);
echo "[*] This is a key for public:".$key."\n";
$private = wp_generate_password(10);
echo "[*] Create a private key which you don't know:".$private."\n";
?>
运行有:
由于题目要求输入完整的字符串,也可以直接输入20作为length就可以了。
输入完整的字符串,获得flag。
(踩了一个坑,只输入了一半的字符串……我是得有多傻)