一、简述
2010年7月exploitdb爆出的《Struts2/XWork < 2.2.0 Remote Command Execution Vulnerability》,可以称之为神一样的漏洞,攻击者只要构造出合适的语句,就有很大的几率获得系统权限(System或者root,因为tomcat默认都会以这样的权限运行),而且时至今日存在这个漏洞的网站仍然大有存在。本文将从源码层面简单的分析Struts2漏洞形成的根本原因。
二、Ognl表达式实现代码执行
Ognl表达式是一种基于Java的功能强大的表达式。通过使用它,我们能够通过表达式存取Java对象树中的任意属性和调用Java对象树的方法,可以轻松解决在数据流转的过程中所碰到的各种问题。但是在实际使用中,编程人员更多使用的是Ognl的数据流转传输的功能,却忘记了Ognl表达式可以执行Java代码的功能。下面我们来通过一个常用的方法来看下它的实现过程。
public class Login extends ActionSupport{
public String execute() {
ActionContext AC = ActionContext.getContext();
Map Parameters = (Map)AC.getParameters();
String[] username = (String[])Parameters.get("username");
System.out.println(AC.getValueStack().findValue(username[0]));
return SUCCESS;
}
}
上面这段代码是我自己搭建的一个Struts2实现的简单java web功能的action部分的代码,具体功能就是,获得用户提交的username参数,然后从值栈(Value Stack)中找到符合参数值的内容,并打印。红色字体部分的findValue方法是关键点,下面我将在这句代码中加上断点,来跟踪分析它的行为。
跟踪进入OgnlValueStack文件中的findValue(String expr)方法,关键代码如下:
Object value = ognlUtil.getValue(expr, context, root);
继续深入追踪进入OgnlUtil文件,看到如下代码:
public Object getValue(String name, Map context, Object root) throws OgnlException {
return Ognl.getValue(compile(name), context, root);
}
红色部分为Ognl类自带的方法,其作用是根据表达式(参数1),在上下文(参数2)和指定类中(参数3)查找响应的内容,并返回,若没有则返回空。在查询的过程中,表达式会被执行,这使得攻击者有可乘之机,可以利用这个方法来执行一些恶意的行为。
三、利用实现
还是使用之前部分构造的代码,搭建一个可以用于web交互的测试平台。通过传递名为username的参数来看下这个函数的威力。提交如下url:
http://target:8080/Login.action?username='#_memberAccess["allowStaticMethodAccess"]=true,@java.lang.Runtime@getRuntime().exec('calc'))'
在目标服务器中,弹出了计算器
我们所传递的内容被作为参数传递给了AC.getValueStack().findValue,之后它的内容便被执行了。解释下传入的语句作用,首先是给#_memberAccess["allowStaticMethodAccess"]变量赋予true值,这个变量是Xwork用于管理Ognl权限类中的成员,它控制Ognl是否可以执行Java的静态方法。第二句调用Java方法执行系统调用,“@”是Ognl调用Java静态方法的标识。
四、总结
Ognl被用户Xwork和Struts框架的核心代码中,在这些框架中很多地方都存在findValue的调用,例如:Struts的校验框架,如果类型不匹配则默认也会调用findValue函数来检索用户输入的内容。2010年爆出的Struts2远程代码执行和其之后出现的代码执行问题,都和这个函数有关系。
findValue函数很像是PHP中的eval、assert函数,可以造成代码执行,但又是必须存在的函数。看Struts和Xwork修补它们漏洞的补丁也是,去对用户输入的内容进行过滤或检验。这方面的漏洞没有被大范围的发现和发掘,个人认为主要原因是因为,使用这些框架进行开发的源码大多是闭源的,外界很难获得,所以少有人去审计。但是,它的威胁性极其强大,本篇文章所涉及的不过是九牛一毛,相对于已经有完善审计方法的PHP,Java Web还算得上是尚未开发的处女地。