摘要
在Ognl表达式中,会将被括号“()”包含的变量内容当做Ognl表达式执行。Ognl表达式的这一特性,引发出一种新的攻击思路。通过将恶意代码存储到变量中,然后在调用Ognl表达式的函数中使用这个变量来执行恶意的代码,从而实现攻击。
本文将会以CVE-2011-3923漏洞作为示例,描述这种利用思路的具体过程。但是,本文的内容绝不仅仅局限于这个漏洞,在实际的审计过程中,这种思路可以用来发现很多类似的漏洞。
背景介绍与原理分析
这个漏洞和CVE-2010-1870很相似,都是是通过Ognl表达式执行java,来达到远程代码执行的效果。我们先来回顾下CVE-2010-1870漏洞,它是攻击者通过get方法提交Ognl表达式,直接来调用java的静态方法来实现代码执行。这个问题爆出来后,struts官方加强了对于用户提交内容的审核,禁止使用“#”、“\”等特殊字符作为参数提交。
那么这样我们就没有办法远程执行Ognl表达式了吗?当然不,Ognl给我们提供了另一种执行它的方法,我们来看下官方文档中一部分的内容:
Ognl表达式给我们提供了“#fack()”这样调用上下文对象方法的功能,我们需要留意的是红色文字,大概的意思如下:如果你想要调用上下文环境中对象的方法,可以使用“(fact)()”这种格式来书写。
而在测试过程中发现,(one)(two)这种形式的Ognl表达式,会先将one当做另一个Ognl表达式先执行一遍,然后再继续他后面的工作。这样的话,如果程序在调用某一可以执行Ognl表达式的函数时,我们通过变量将恶意的表达式传入,那么,struts所做的那些过滤便成为了一扇“透明的门”。
0x03 实例模拟与跟踪
在正常的调用中,我们找到了setValue这个函数,它的作用是根据Ognl表达式对目标进行赋值,在这个过程中Ognl表达式会执行。而struts2中通过在继承ActionSupport的类中,设置setter和getter方法,可以实现用户通过get和post方法直接为私有成员变量赋值。这种方法便会用到setValue这个函数。下面我们来搭建一个这样的类:
package action;
import ognl.Ognl;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport{
private String tang3;
public void settang3(String tang3) {
this.tang3 = tang3;