Java EL and Spel表达式注入漏洞成因和一些细节
2023-10-14 22:56:46 Author: www.freebuf.com(查看原文) 阅读量:8 收藏

freeBuf

主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Preface

这里主要是对Java中的各种常见的表达式注入的各种类型和各种原理的一个较为全面的分析

EL(Expression-language)

brief

背景

EL是为了使JSP写起来更加简单, 它提供了在JSP中简化表达式的方法, 让JSP的代码更加简化

特点

可得到PageContext属性值.

可直接访问JSP的内置对象, 如page,request,session,application等.

运算符丰富, 有关系运算符、逻辑运算符、算术运算符等.

扩展函数可与JAVA类的静态方法对应.

简单使用

  • EL表达式的语法格式通过${}包裹

  • 在默认情况下,查找的范围为page, request, session, application

  • 存取数据的两种方式:.and[],通常情况下两种方式都可以使用,但是有两种特殊情况

    1. 如果属性名称包含有一些特殊字符,如. -等非字母和数字的,只能使用[xxx]包裹属性

    2. 如果需要动态取值,也只能通过[]获取属性

  • 隐式对象

    对象解释
    pageContextJSP页的上下文
    param获取请求参数,类似request.getParameter()
    paramValues类似request.getParameterValues()
    header获取请求头
    headerValues同paramValues
    cookie获取cookie
  • JSP中EL表达式的禁用

    1. 单个文件禁用

      <%@page isELIgnored="true" %>
      
    2. 全局禁用

      // web.xml
      <jsp-config>
          <jsp-property-group>
              <url-pattern>*.jsp</url-pattern>
              <el-ignored>true</el-ignored>
          </jsp-property-group>
      </jsp-config>
      

detail

一个小例子

@RequestMapping("/el")
@ResponseBody
public String ElTest(@RequestParam(required = false) String expression) {
    if (expression == null) {
        return "Send request with \"expression\" parameter!";
    }
    try {
        ExpressionFactoryImpl factory = new ExpressionFactoryImpl();
        StandardELContext context = new StandardELContext(factory);
        ValueExpression valueExpression = factory.createValueExpression(context, expression, String.class);
        valueExpression.getValue(context);
    } catch (Exception e) {
        return Util.printStack(e);
    }
    return "OK!";
}

在通过ExpressionFactoryImpl#createValueExpression方法根据expression这个传入的表达式构造一个ValueExpression对象

image-20231001221310507.png

进而通过ExpressionBuilder#createValueExpression方法来创建ValueExpression对象

image-20231001221708654.png

主要是通过build方法来将表达式拆分成一个一个的结点

image-20231001224624813.png

通过createNodeInternal方法通过AST解析成一个一个的结点

image-20231001234122605.png

el.parser包下的SimpleNode这个抽象类的实现类中定义了很多有关EL表达式中的结点类型

image-20231001235045662.png

类似于运算符结点,方法的参数结点等等

上面的内容主要是对${}包裹的表达式进行解析成一个一个的结点,之后就是对内容进行执行,之后将执行的结果返回到页面中

也就是通过ValueExpressionImpl#getValue方法来获取表达式执行后的值

image-20231002104307068.png

核心是在this.getNode().getValue方法的调用,这里是AstValue#getValue方法

image-20231002110620662.png

  1. 首先获取第一个子结点的值,并获取子结点的总个数

  2. 如果存在有次子结点,并且同时存在有次次结点且该结点为AstMethodParameters对象,之后获取该次次结点

  3. 之后通过调用resolver#invoke方法结合base / suffix / params进行计算


文章来源: https://www.freebuf.com/articles/web/380738.html
如有侵权请联系:admin#unsafe.sh