国赛决赛web部分WP以及思路分享
决赛燃尽了,喜提国二小保底
赛后想想虽然小部分题目质量一般但是还是有很多值得复现的东西的
Day1
hardPHP (未完成)
题目给了一个sql注入,要求$row['password'] === $password
第一时间想起了几个月前刚学的sql quine,但是quine要用的replace函数被ban了,于是一整天都在想用其他函数如何绕过,到最后一小时才发现,即使ban了sleep和benchmark也是可以打延时盲注的…
延时用笛卡尔积,substr用insert即可绕过
时间问题最后脚本没来得及爆出来,这是一个测试成功的payload
'/**/union/**/select/**/if((select/**/insert((SELECT/**/password/**/FROM/**/users/**/WHERE/**/username/**/like/**/'admin'/**/limit/**/1),2,1000,"")/**/like/**/'a'),1,(SELECT/**/count(*)/**/FROM/**/information_schema.columns/**/A,/**/information_schema.columns/**/B,/**/information_schema.tables/**/C))#
出题人套娃,后续有一个和sql毫无关系的shellshock,但是没打到后面就不知道了,小可惜
Day2
Secuirity_rasp(仅完成Fix)
break
题目给了一个反序列化接口可以直接打 jackson链
但是上了百度的rasp,从底层hook了所有的命令执行,并且反序列化黑名单中加入了链子最后一步做getter->RCE的templatesImpl,又hook掉了所有的JNDI,真不知道怎么入手了。
0解题,希望赛后有大手子可以教教怎么打的
fix
总共15次机会,前14次全部失败,最后一次提交极限通过,太刺激了
要求只能改rasp的配置official.js,之前试过无脑ban所有,结果一直exp利用成功,估计是js语法错误导致rasp直接失效了
最后一次从反序列化拦截入手,本来想在黑名单里加点东西,但是还是怕漏掉一些类,干脆直接反序列化行为全部ban掉,也就是循环判断的部分把return clean改掉就行
if (algorithmConfig.deserialization_blacklist.action != 'ignore')
{
plugin.register('deserialization', function (params, context) {
var clazz = params.clazz
for (var index in algorithmConfig.deserialization_blacklist.clazz) {
if (clazz === algorithmConfig.deserialization_blacklist.clazz[index]) {
return {
action: algorithmConfig.deserialization_blacklist.action,
message: _("Deserialization blacklist - blocked " + clazz + " in resolveClass"),
confidence: 100,
algorithm: 'deserialization_blacklist'
}
}
}
return {
action: algorithmConfig.deserialization_blacklist.action,
message: _("Deserialization blacklist - blocked in resolveClass"),
confidence: 100,
algorithm: 'deserialization_blacklist'
}
})
}
ota (仅完成Fix)
break本地通了远程不通,jar包和jdk一毛一样,拼尽全力无法理解环境是什么情况
break
题目虽然硬编码给了admin密码可以直接登,但是最终的jdbc attack的利用点 /admin/init接口要求是SUPERADMIN身份
那么思路很明显,首先是可以通过WebConfig的这个
return RouterFunctions.resources("/static/**", new FileSystemResource("static/"));
打 CVE-2024-38816 做目录穿越,把题目的jar包读下来,拿到jwt的secret
然后伪造superadmin身份
在这个接口打H2 jdbc attack即可
本地是已经随便读了
远程死活通不了,试了很多payload和文件就是不行,心态爆炸,可能有什么关键的东西没用上
Fix
只修了jdbc的洞是没用的,要把CVE也修了,不然还是会“exp利用成功”,估计利用成功不一定是打出flag吧?或者是他知道flag文件名直接读到了
把/admin/init路由下的jdbc修了,可以直接注释掉,或者加过滤也行
@PostMapping({"/admin/init"})
@ResponseBody
public String initH2Database(@RequestBody JdbcRequest request) {
try {
if (request.getJdbcUrl().length() > 100) {
return "Failed to initialize H2 database: ";
} else if (request.getJdbcUrl().contains("$$")) {
return "Failed to initialize H2 database: ";
} else if (request.getJdbcUrl().contains("Runtime")) {
return "Failed to initialize H2 database: ";
} else if (request.getJdbcUrl().contains("Process")) {
return "Failed to initialize H2 database: ";
} else if (request.getJdbcUrl().contains("http")) {
return "Failed to initialize H2 database: ";
} else if (request.getJdbcUrl().contains("RUNSCRIPT")) {
return "Failed to initialize H2 database: ";
} else {
return request.getJdbcUrl().contains(" FROM") ? "Failed to initialize H2 database: " : "Failed to initialize H2 database: ";
}
} catch (Exception var6) {
Exception var5 = var6;
Exception var4 = var5;
Exception var3 = var4;
Exception e = var3;
e.printStackTrace();
return "Failed to initialize H2 database: " + e.getMessage();
}
}
(build jar的时候给注释的加载jdbc那段搞没了)
然后是修复CVE,我不想自己写代码改WebConfig,就直接去改spring源码了
CVE的利用点是
类的isInvalidPathorg.springframework.web.reactive.function.server.PathResourceLookupFunction
利用cleanPath可以对../做绕过,从而使此函数返回false但是url中包含../,具体可以看网上有很多分析,我没深究
这里只要把第二个条件删掉就可以了
return path.contains("..") ;
jbac(全部完成)
Go写的题,队友秒了,可以看 https://imsy.cc/posts/2025/07/20/ciscn2025-final/
总结
这次发挥好一些可以国一的,可惜第一天的CTF陷进去了,现在想想其实并不是很难,当时一看sleep和benchmark被办了就直接不考虑盲注了。。
第二天打完比赛走到哪桌都能听到骂逆向出题人的,整场比赛就一题0解逆向,无敌,队内的逆向大手子也表示无语
协会蝉联国一的记录也是断在咱这了
明年不知道能不能再战了,真有些遗憾
Comments 2 条评论
ota可以打h2 groovy,注意下jdk版本
@957685226 师傅我说的是远程用那个CVE读不到文件()不是要先读jwtsecret才能伪造superadmin么
不知道师傅用的哪个payload打通了