2023香山杯
2023香山杯
WEB
PHP_unserialize_pro
签到题,比较简单的反序列化
1 |
|
pop链
1 |
|
这里过滤了flag字符,利用more+正则匹配[0-z]绕过
1 |
|
sharedBox
hint:kkfileview2.2.1 的漏洞利用
环境配置
项目地址:https://github.com/kekingcn/kkFileView
git下来后回退到2.2.1版本
因为我本地是windows,所以还要下载OpenOffice
https://www.openoffice.org/download/
下载安装完根据readme运行FilePreviewApplication的main方法
漏洞分析
访问http://localhost:8012
原题的kkfileview部署在/fileview/
下,本地在/
,原题用的linux,本地为windows
存在3个路由
/onlinePreview
、picturesPreview
、/getCorsFile
主要漏洞点:
/onlinePreview
,在线浏览功能,这里有一个xss和ssrf的漏洞
picturesPreview
,图片预览,有xss漏洞
/getCorsFile
,任意文件读取和ssrf漏洞
具体分析:
- xxxxxxxxxx import gmpy2from Crypto.Util.number import n = 121027298948349995679677982412648544403333177260975245569073983061538581058440163574922807151182889153495253964764966037308461724272151584478723275142858008261257709817963330011376266261119767294949088397671360123321149414700981035517299807126625758046100840667081332434968770862731073693976604061597575813313r = getPrime(6)e = 65537a = 11001240791308496565411773845509754352597481464288272699325231395472137144610774645372812149675141360600469640492874223541765389441131365669731006263464699c = 42256117129723577554705402387775886393426604555611637074394963219097781224776058009003521565944180241032100329456702310737369381890041336312084091995865560402681403775751012856436207938771611177592600423563671217656908392901713661029126149486651409531213711103407037959788587839729511719756709763927616470267p = gmpy2.next_prime(a - r)q = gmpy2.next_prime(gmpy2.next_prime(a) + r)phi_n = (p-1)(q-1)d = gmpy2.invert(e,phi_n)m = pow(c,d,n)print(long_to_bytes(m))Python
支持file和http协议,而且没有过滤,造成ssrf
/getCorsFile
下断点
跟进到getInputStreamFromUrl
这里没有过滤传入的字符,造成了任意文件读取
可以参考:https://github.com/kekingcn/kkFileView/issues/128
题目分析
在题目的环境中对getCorsFile
进行了限制,直接访问的话会返回
403
那么就由此有了一个思路:onlinePreview接口ssrf请求到getCorsFile
,然后任意文件读取
即http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/getCorsFile?urlPath=file:///C:/Windows/win.ini
但是,我们来看看实际效果
文件类型不支持,那么从源码里看看它为什么不支持,以及支持什么格式的文件
下个断点
跟进到这一段,经过getFileNameFromURL
处理后得到文件名为getCorsFile
最终传入判断后返回不支持
那么这也说明了无后缀文件是无法读取的,那看看支持的文件格式
看到这里,返回有picture、pdf、media等,但是这些肯定不支持文本形式的flag
然后注意到simText
类型
支持txt
、jsp
等
现在引入一个知识点
spring boot的路径匹配
而源码中的版本恰好是1.5.8
那么就有了一个思路:
http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/getCorsFile.txt?urlPath=file:///C:/Windows/win.ini
这样就会解析成
http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/getCorsFile?urlPath=file:///C:/Windows/win.ini
然后服务端又是怎么处理这个多出来的.txt
呢
可以看到file目录下多了getCorsFile.txt
,里面的内容就是要读的文件的内容
那么这个是怎么实现的呢
onlinePreview 最后调用了 filePreviewHandle
,然后调用了
downLoad
downLoad
中利用saveBytesToOutStream
将读的内容写入文件
这里解释了为什么会多一个getCorsFile.txt.txt
最后就是怎么读取getCorsFile.txt
正常思路
http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/getCorsFile.txt
但是刚刚提到spring
boot特性会将getCorsFile.txt
解析为getCorsFile
所以用%01
、%02
等不可见字符(猜测是不可见字符,本地测试是可以的)绕过http://localhost:8012/%01getCorsFile.txt
题解
综合上述
将文件写入
http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/getCorsFile.txt?urlPath=file:///C:/Windows/win.ini
读文件
http://localhost:8012/onlinePreview?url=http://127.0.0.1:8012/%09getCorsFile.txt
比赛环境已经关了,赛题的后续利用无法复现了
最后贴个lxxxin师傅的题解,参考:https://www.yuque.com/dat0u/ctf/lbp2gfi6gttxsymb
最终Payload如下,题目应该是在nginx或者/onlinePreview路由处对proc、fd关键字做了匹配,由于是SSRF,会发起两次http请求,因此可以通过双重URL编码绕过
1
2
GET /fileview/onlinePreview?url=http://localhost:8012/getCorsFile.jsp?urlPath=file:///%2570%2572%256f%2563/29/%2566%2564/6 HTTP/1.1
Host: 101.201.35.76:22873绕过后,读取的文件内容会保存在getCorsFile.jsp中,用%09、%02等字符绕过一下读取文件即可
1
2
GET /fileview/%09getCorsFile.jsp HTTP/1.1
Host: 101.201.35.76:22873比赛的时候,/flag提示我们要RCE,但是这题可以通过非预期读取/proc/29/fd/6获取到flag
预期应该是读/root/flag.java文件,然后再往下走......,这里因为赛后靶机关了,也就没机会尝试了,具体的flag.java代码如下,感兴趣的师傅可以自行尝试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class flag {
public static void main(String[] args) {
Connection conn = null;
Properties prop = new Properties();
InputStream input = null;
try {
input = Files.newInputStream(Paths.get("/tmp/config.properties"));
while(true){
// 连接到SQLite数据库
// 创建一个属性对象
prop.load(input);
// 创建一个Connection对象,并传入属性对象
conn = DriverManager.getConnection("jdbc:sqlite:/tmp/mydatabase.db", prop);
// 设置密码
Statement stmt = conn.createStatement();
stmt.close();
Thread.sleep(5000);
}
// 接下来,你可以在此处执行其他操作
} catch (SQLException e) {
System.out.println(e.getMessage());
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
}
}启动文件(/root/start.sh)如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/bin/bash
FLAG_PATH=/tmp/config.properties
FLAG_MODE=M_SED
if [ ${ICQ_FLAG} ];then
case $FLAG_MODE in
"M_ECHO")
echo -n ${ICQ_FLAG} > ${FLAG_PATH}
FILE_MODE=755
chmod ${FILE_MODE} ${FLAG_PATH}
;;
"M_SED")
#sed -i "s/flag{x*}/${ICQ_FLAG}/" ${FLAG_PATH}
sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
;;
"M_SQL")
# sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
# mysql -uroot -proot < ${FLAG_PATH}
;;
*)
;;
esac
echo [+] ICQ_FLAG OK
unset ICQ_FLAG
else
echo [!] no ICQ_FLAG
fi
unset ICQ_FLAG
rm -rf /etc/profile.d/pouchenv.sh
rm -rf /etc/instanceInfo
rm -rf /start.sh
/usr/sbin/nginx
/usr/sbin/crond
/usr/sbin/rsyslogd
javac /root/flag.java
nohup java -classpath /root/sqlite-jdbc-3.41.2.2.jar:/root/ flag >/dev/null &
nohup java -jar /root/upload.jar >/dev/null &
sleep 1;
rm /tmp/config.properties
java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=/opt/kkFileView-2.2.1/config/application.properties -jar /opt/kkFileView-2.2.1/bin/kkFileView-2.2.1.jar &
exec tail -f /dev/null
参考
https://www.xx5xx.top/Writeup/WEB/2023%E9%A6%99%E5%B1%B1%E6%9D%AF-sharedBox/
https://www.yuque.com/dat0u/ctf/lbp2gfi6gttxsymb
https://www.cnblogs.com/xbbth/p/17446987.html
https://github.com/kekingcn/kkFileView/issues/128
MISC
PINTU
图片像素rgb值转2进制再转成字符串发现提示
然后图片高度隐写,8进制转10进制再转成ascii,发现是每两个字符为一组(因为中间有空格分隔)
再转一次ascii码,得到一串字符串
1 |
|
base32->base64换表->base64
拿到一张rgb很混乱的图片,Piet隐写
用工具npiet
下载:https://www.bertnase.de/npiet/
1 |
|