1. 程式人生 > >重現Struts1的操縱classLoader漏洞

重現Struts1的操縱classLoader漏洞

注:本文僅限技術研究,探討,測試使用.

2014年4月29日爆出的struts的可操縱classLoader的漏洞, 橫跨struts1和struts2的所有版本。 影響面和問題的嚴重性幾乎可以和heartbleed相媲美。 struts2要嚴重一些,對於struts1,只是說在特定條件下可執行特殊操作。

因為專案中用的是struts1,所以主要精力集中在struts1上。既然要修復漏洞,首先得找出POC給老闆看,這類漏洞一般網上不會給出直接的POC,於是就動手搗鼓一番。建立一個簡單的struts1專案,包含一個Action和ActionForm即可。 啟用debug模式部署專案到tomcat等容器。然後在action的任意位置加一個斷點,然後通過瀏覽器訪問該action。既然說是"操縱classLoader",我馬上想到的是struts自動封裝表單用到反射,在斷點附近尋找ActionForm的class的classLoader的屬性列表,看看有誰的名字聽起來是可操縱的。最初我就發現了這個:clearReferencesHttpClientKeepAliveThread .於是有如下的url和截圖:
http://localhost:8080/Struts1/helloWorld.do?class.classLoader.clearReferencesHttpClientKeepAliveThread=false


http://localhost:8080/Struts1/helloWorld.do?class.classLoader.clearReferencesHttpClientKeepAliveThread=true


至此classLoader操作成功, 儘管clearReferencesHttpClientKeepAliveThread是一個暫時看起來不太危險的classLoader屬性。

我看到部分資料說該漏洞在jetty7 下可關閉jetty伺服器, 我也試了, 可以, 你可以把專案部署到jett7, 然後用如下url:
http://localhost:8080/Struts1/helloWorld.do?class.classloader.context.shutdown=true
一旦class.classloader.context.shutdown被輸入,則後續的所有請求都只能收到404,要想恢復的唯一辦法就是重啟jetty。
如圖:


還有更多的其他的POC比如在tomcat8下可下載任意檔案,在其他情況下可執行code等待,我就沒有一一證明。

因為struts1在該漏洞發出後, apache宣佈struts1即將EOL, 所以我們也不打算花太多精力搞個威猛的方案出來,用了一個filter來檢查請求引數是否包含“class.*”完事。程式碼片段如下:

public static final String classLoaderManipulatorParamReg = "(class\\.)|(class.classLoader\\.)" ;
public static final Pattern classLoaderManipulatorParamPattern = Pattern.compile(classLoaderManipulatorParamReg);

Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
	String key = params.nextElement();
	Matcher matcher = classLoaderManipulatorParamPattern.matcher(key);
	if(matcher.find()){
		System.out.println("suspicious parameters: " + key + ", removed from the parameter list.");
		req.setAttribute("msg", key+"=" + req.getParameter(key));
		request.getRequestDispatcher("unsafeRequest.jsp").forward(req, response);
		
		//logger.warn(this, "suspicious parameter: " + key);
		
		// 需替換尖括號以防止反射型的XSS漏洞
		String kvPair = (key+"=" + req.getParameter(key)).replaceAll("<", "& lt;").replaceAll(">","& gt;");
		
		/* 
		 * 這裡需要注意:如果用以下方式重定向到出錯頁面, 極有可能導致遞迴的filter呼叫從而進入死迴圈。
		 * request.getRequestDispatcher("unsafeRequest.jsp").forward(req, response);
		 * 如果你想走到一個單獨的出錯頁面來顯示錯誤資訊, 需要謹慎處理。
		 * 我們這裡就簡單的直接輸出出錯資訊到response.
		*/
		response.getWriter().write("Malicious parameter detected: " + kvPair);
		response.getWriter().flush();
		return;
	}
}



你可以在這裡下載struts1樣例程式: http://download.csdn.net/detail/sunxing007/7350433。如要重現POC, 請先把web.xml中SecurityFilter去掉。

轉載請註明來自: http://blog.csdn.net/sunxing007