您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關怎么突破JFinal黑名單機制實現任意文件上傳,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
JFinal是國產優秀的web框架,短小精悍強大,易于使用。近期團隊內一名小伙伴(LuoKe)在安全測試的時候報了一個很玄學的任意文件上傳,筆者本著知其然必知其所以然的態度去跟進了一下問題代碼,發現問題系統在處理上傳文件功能的時候使用了JFinal框架,于是去對該框架上傳文件處的代碼做了一下審計,發現了JFinal上傳文件的黑名單機制的存在被繞過的風險。目前該漏洞已上報至廠商并修復,下面意在和各位分享一下該漏洞的原理和發現過程。
isSafeFile(UploadFileuploadFile) //jfinal黑名單檢測函數,負責對jsp與jspx類型文件進行過濾
com.oreilly.servlet.MultipartRequest(request, uploadPath, maxPostSize, encoding,fileRenamePolicy) //jfinal處理上傳文件請求類,負責處理上傳請求中的文件與參數
注:漏洞發現場景由我這邊搭建的測試環境模擬,并非當時爆出漏洞的實際場景,如有疏漏,還請見諒。
某日下午,團隊內的安全測試組的LuoKe同學分享了一個很有意思的任意文件上傳大體情況如下
1、上傳txt類型文件,提示上傳成功。
2、上傳jsp文件,顯示上傳失敗。
3、提交如下數據包,顯示上傳失敗,但是給上傳目錄下,可以發現上傳成功。
剛看到這種情況,還是比較懵,因為但是比對了一下3個數據包,立馬可以明白一個問題,第三個數據包是不完整的,它的最末行缺少分割的boundary,為了驗證這個想法,我試了一下如下形式的數據包,
果然是上傳失敗,那就說明一個道理,此次繞過黑名單一定是和程序報錯有關系的。那接下來就是去跟進一下系統代碼,確認一下我們的猜想。
跟進代碼的時候發現,系統中處理上傳文件的代碼是如下形式:
UploadFile file = getFile("file", "test");
看了一下lib,發現這個函數是JFinal框架處理上傳文件的函數,那是不是代表這種利用方式是在JFinal框架中是具有通用性的,所以直接在本地搭了一個JFinal框架去看一下上傳文件的代碼。
首先去看一下黑名單處理函數
Upload/MultipartRequest.class 100-107
isSafeFile(UploadFile uploadFile) { String fileName = uploadFile.getFileName().trim().toLowerCase(); (!fileName.endsWith() && !fileName.endsWith()) { ; } { uploadFile.getFile().delete(); ; } }
可以發現在處理后綴為jsp和jspx類型的文件的時候,會做一步刪除操作“uploadFile.getFile().delete(); “,看到這一步的時候我就基本心如明鏡了,在這個地方做了刪除操作是不是就代表了,代碼在處理上傳文件的時候先是什么都不管的,上傳完成后再對有問題的文件做刪除。
那我們先去跟一下上傳文件的代碼
Servlet/MultipartRequest.class 84-108
((part = parser.readNextPart()) != ) { String name = part.getName(); (name == ) { IOException(); } String fileName; (part.isParam()) { ParamPart paramPart = (ParamPart)part; fileName = paramPart.getStringValue(); existingValues = (Vector).parameters.get(name); (existingValues == ) { existingValues = Vector(); .parameters.put(name, existingValues); } existingValues.addElement(fileName); } (part.isFile()) { FilePart filePart = (FilePart)part; fileName = filePart.getFileName(); (fileName != ) { filePart.setRenamePolicy(policy); filePart.writeTo(dir); .files.put(name, UploadedFile(dir.toString(), filePart.getFileName(), fileName, filePart.getContentType())); }
可以看到代碼會去輪詢上傳時候傳的每個參數,一旦是文件,就會直接上傳到給定的dir。
現在我們已經明確了,無論什么類型的文件都會上傳,但是在抵達黑名單函數后就會對jsp和jspx文件進行刪除,所以我們接下來要思考的問題就是:
如何讓代碼執行到上傳文件后,而又不去執行黑名單處理代碼。
總結剛剛我們在測試階段的分析,比較良好的做法就是想辦法讓程序執行到黑名單函數之前報錯,這樣代碼就會停止執行到黑名單函數。那我們去看一下代碼,
Upload/MultipartRequest.class 76-87
.multipartRequest = com.oreilly.servlet.MultipartRequest(request, uploadPath, maxPostSize, encoding, fileRenamePolicy); Enumeration files = .multipartRequest.getFileNames();(files.hasMoreElements()) { String name = (String)files.nextElement(); String filesystemName = .multipartRequest.getFilesystemName(name); (filesystemName != ) { String originalFileName = .multipartRequest.getOriginalFileName(name); String contentType = .multipartRequest.getContentType(name); UploadFile uploadFile = UploadFile(name, uploadPath, filesystemName, originalFileName, contentType); (.isSafeFile(uploadFile)) { .uploadFiles.add(uploadFile); } } }
從上傳文件
this.multipartRequest = new com.oreilly.servlet.MultipartRequest(request,uploadPath, maxPostSize, encoding, fileRenamePolicy);
到刪除黑名單文件
this.isSafeFile(uploadFile)
這段代碼之間我們還是有很多操作可以去做的。
我這邊的思路就是,首先保證上傳文件的參數正常,再在文件參數后去給一個該接口不存在的參數,于是在輪詢上傳參數的時候,第一個參數是文件,直接會被上傳到服務器,而去輪詢第二個參數的時候,系統就會“報參數不存在“的異常,從而停止程序的執行,繞過黑名單機制。
看到這些代碼也可以明白,第一版的時候LuoKe同學繞過黑名單成功的原因是因為提交的第二個參數缺少分割boundary導致的報錯,思路同樣可行。
下圖給出poc:
看一下后臺拋的異常:
1、 其實我猜測這個漏洞也還有其他可能的利用方式,比如我們常提到的資源競爭(寫一個寫木馬文件的jsp,在上傳的同事瘋狂訪問該上傳路徑,這樣就有可能在刪除文件之前訪問到jsp文件,并寫入木馬成功)。
2、 該漏洞歸根到底還是開發意識的問題,無論如何,處理上傳文件的時候還是應該牢記先校驗,再上傳。
看完上述內容,你們對怎么突破JFinal黑名單機制實現任意文件上傳有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。