web安全Spel表达式注入漏洞

Posted Coder_preston

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web安全Spel表达式注入漏洞相关的知识,希望对你有一定的参考价值。

引言

在练习靶场的时候遇到了spel表达式注入的题目,这篇文章主要是学习总结一下spel表达式的相关知识点,然后进一步学习spel表达式相关漏洞,了解如何利用改漏洞或者代码审计找到相关漏洞。
作为初学者,主要的学习要点如下:

  • 什么是spel表达式, 如何使用?
  • 如何利用spel表达式漏洞,以及相关的绕过方式。
  • spel表达式漏洞的防护。

学习spel表达式

笔者一开始想直接从spel表达式的漏洞入手,可是发现许多描述都不理解,我的java用的不是很多,也不知道表达式的作用是啥,于是我们先学习一下spel表达式使用的知识,再学习相关漏洞。

spel表达式,全称为Spring Expression language,直观的理解,它可以将字符串看作表达式并运行, 这个字符串可以是硬编码的字符串,也可以是外部传递过来的参数。 如果是由外部传过来的,就需要注意是否有可能造成表达式注入问题。例如,可以执行恶意构造的表达式或者执行类实例对象。

我们可以创建一个demo实例,来实践运行一下spel表达式。具体如下:

在IDEA中新建maven工程。
其中pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spel</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
    </dependencies>
</project>

class文件内容如下,可自行编辑spel表达式进行尝试。

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
//import org.springframework

public class SpELTest 
    public static void main(String[] args) 
        // 创建解析器:SpEL 使用 ExpressionParser 接口表示解析器,提供 SpelExpressionParser 默认实现
        ExpressionParser parser = new SpelExpressionParser();
        // 解析表达式:使用 ExpressionParser 的 parseExpression 来解析相应的表达式为 Expression 对象
        Expression expression = parser.parseExpression("('Hello' + ' FreeBuf').concat(#end)");
        // 构造上下文:准备比如变量定义等等表达式需要的上下文数据
        EvaluationContext context = new StandardEvaluationContext();
        // 这里, #end 可以看作一个变量,变量的值为"!"
        context.setVariable("end", "!");
        // 求值:通过 Expression 接口的 getValue 方法根据上下文获得表达式值
        System.out.println(expression.getValue(context));
        
    

这里分享几个表达式的使用:

  • 字符串,数字等表达式
    double double1 = parser.parseExpression("1.1E+2").getValue(double.class);
    int hex1 = parser.parseExpression("0xa").getValue(Integer.class);
    long hex2 = parser.parseExpression("0xaL").getValue(long.class);
    boolean true1 = parser.parseExpression("true").getValue(boolean.class);
    boolean false1 = parser.parseExpression("false").getValue(boolean.class);
    Object null1 = parser.parseExpression("null").getValue(Object.class);

  • 算数运算表达式
类型示例加减乘除int result1 = parser.parseExpression("1+2-3*4/2").getValue(Integer.class);
  • 关系表达式
boolean result3 = parser.parseExpression("2>1 and (NOT true or NOT false)").getValue(boolean.class);
boolean result4 = parser.parseExpression("2>1 && (NOT true || NOT false)").getValue(boolean.class);

  • 类类型表达式
    ExpressionParser parser = new SpelExpressionParser();
    //java.lang包类访问
    Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);
    System.out.println(result1);

    //其他包类访问
    String expression2 = "T(com.javacode2018.spel.SpelTest)";
    Class<SpelTest> value = parser.parseExpression(expression2).getValue(Class.class);
    System.out.println(value == SpelTest.class);

    //类静态字段访问
    int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);
    System.out.println(result3 == Integer.MAX_VALUE);

    //类静态方法调用
    int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class);
    System.out.println(result4);

靶场练习:spel表达式注入漏洞

spel表达式如果接收外来的参数, 一定要考虑对于非法输入的过滤, 否则会产生注入漏洞。 后续将会分享一下具体的靶场实例。

漏洞防护

和sql注入漏洞类似, 严格过滤不信任的数据。

参考文档

https://zhuanlan.zhihu.com/p/174786047

一文详解SpEL表达式注入漏洞

摘要:本文介绍了SpEL表达式以及常见的SpEL注入攻击,详细地介绍了部分漏洞攻击实例以及常用的漏洞检测与防御手段。

本文分享自华为云社区《SpEL表达式注入漏洞分析、检查与防御》,作者:华为云软件分析Lab。

在安全角度来看外部来源的数据,均应视为不可信数据,对外部数据,其包含的所有信息都须经过校验或者过滤,再向下游服务进行传递。若无防护手段,攻击者可以通过构造恶意输入,对服务进行攻击。程序中如果使用未经校验的输入构造SpEL语句,就有可能造成SpEL表达式注入漏洞。部分SpEL表达式注入漏洞CVSS3.x 评分极高,nvd认定为高危漏洞,具有高致命性。

1 SpEL表达式介绍

Spring表达式语言(Spring Expression Language,SpEL)是 Spring Framework的核心技术之一,其支持在运行时查询和操作对象图。SpEL语法类似于Unified Expression Language,但提供了更加丰富的功能,最特别的是方法调用与字符串模板功能。SpEL主要支持以下功能:

  • 文字表达式
  • 布尔和关系运算符
  • 正则表达式
  • 类表达式
  • 访问 properties, arrays, lists, maps
  • 方法调用
  • 关系运算符
  • 参数
  • 调用构造函数
  • Bean引用
  • 构造Array
  • 内嵌lists
  • 内嵌maps
  • 三元运算符
  • 变量
  • 用户定义的函数
  • 集合投影
  • 集合筛选
  • 模板表达式

SpEL功能强大,可以操作类和方法。

  • 引用方法:dog.run()
  • 引用静态方法:T(java.lang.Math).PI
  • 类实例化:使用new实例化对象,类名必须是全限定名,java.lang包内的除外如Integer、String等
  • 变量定义及赋值引用

在解析SpEL之后,获取表达式结果时,可以指定表达式的上下文对象:EvaluationContext

  • (默认)StandardEvaluationContext:支持全套SpEL语言和功能配置选项,功能强大但存在隐患
  • SimpleEvaluationContext:仅支持SpEL语法的子集,不包括Java类型引用,构造函数和bean引用,功能相对简单但是安全

2 SpEL表达式注入漏洞

历史报告的大部分SpEL漏洞大多涉及不受信任的用户输入的情况,恶意攻击者可能利用SpEL实现任意代码执行、拒绝服务等攻击,与SpEL相关的部分CVE漏洞见表 1。

表 1 部分SpEL注入CVE漏洞

常见的SpEL注入攻击流程如图 1所示,漏洞的基本条件有: 使用StandardEvaluationContext,2. 未对输入的SpEL进行校验,3. 对表达式调用了getValue()或setValue()方法。当满足上述条件时,就给了攻击者可乘之机。

图 1 常见的SpEL注入攻击流程

3 漏洞实例

3.1 CVE-2022-22963 Spring Cloud Function SpEL注入漏洞

3.1.1 基本信息

3.1.2 Spring Cloud Function 介绍

Spring Cloud Function 是基于 Spring Boot 的函数计算框架。它提供了一个通用的模型,用于在各种平台上部署基于函数的软件,包括像 Amazon AWS Lambda 这样的 FaaS(函数即服务,function as a service)平台。该项目致力于促进函数为主的开发单元,它抽象出所有传输细节和基础架构,并提供一个通用的模型,用于在各种平台上部署基于函数的软件。

3.1.3 CVE-2022-22963漏洞攻击路径

使用spring-cloud-function-web的Spring boot 应用,通过设置Message Headers来传达路由指令,也可以在请求头中指定spring.cloud.function.definition 或spring.cloud.function.routing-expression作为应用程序属性,允许使用 Spring 表达式语言。

当在application.properties中设置spring.cloud.function.definition=functionRouter从而将默认路由绑定具体函数由用户进行控制。

攻击者调用/functionRouter接口,并在请求头的spring.cloud.function.routing-expression中使用攻击性的SpEL语句,服务端就会解析SpEL并执行。

漏洞攻击图示如图 2所示。

图 2 CVE-2022-22963漏洞攻击路径

3.1.4 CVE-2022-22963漏洞修复方式

该漏洞主要从四处进行了修复,(1)声明一个SimpleEvaluationContext,专用作来自header的SpEL的解析 ;(2)新增一个布尔变量isViaHeader,用于标记当前Expression是否来自Header;(3)如果是从Header中获取的spring.cloud.function.routing-expression表达式,isViaHeader为true ;(4)isViaHeader为true时,expression.getValue指定使用headerEvalContext。如图 3所示。

图 3 CVE-2022-22963漏洞修复

3.2 CVE-2022-22980 Spring Data MongoDB SpEL 表达式注入漏洞

3.2.1 基本信息

3.2.2 Spring Data for MongoDB 介绍

Spring Data for MongoDB是Spring Data的一个子模块。 目标是为MongoDB提供一个相近的一致的基于Spring的编程模型。其核心功能是映射POJO到Mongo的DBCollection中的文档,并且提供Repository 风格数据访问层。主要特性有:

• Spring 配置支持:使用基于 Java 的 @Configuration 类或基于 XML 命名空间的配置来驱动 Mongo 实例和副本

• MongoTemplate 辅助类:可提高执行常见 Mongo 操作的效率,包括文档和 POJO 之间的集成对象映射

• 异常处理:异常转换为 Spring 的可移植的数据访问异常层次结构

• 功能丰富的对象映射与 Spring 的转换服务集成

• 基于注释的映射元数据、并且可扩展以支持其他元数据格式

• 持久化和映射生命周期事件

• 使用 MongoReader/MongoWriter 抽象的低级映射

• 基于 Java 的查询、条件和更新 DSL

• Repository 接口的自动实现,包括对自定义查询方法的支持

• QueryDSL 集成以支持类型安全的查询,以及地理空间整合

• Map-Reduce 集成

• JMX 管理和监控

• 对存储库的 CDI 支持

• GridFS 支持

3.2.3 CVE-2022-22980漏洞攻击路径

图 4 CVE-2022-22980漏洞攻击路径

3.2.4 CVE-2022-22980复现

1)实验代码:learnjavabug

2)运行服务,com.threedr3am.bug.spring.data.mongodb.Application#main

3)Postman发送请求,如图 5所示

图 5 Postman填写参数示例

4)现象:计算器程序被执行

3.2.5 CVE-2022-22980修复方式

Spring Data for MongoDB在修复此漏洞时,重新实现evaluator,指定EvaluationContext类型,如图 6所示。

图 6 CVE-2022-22980修复方式

4 检测与防御手段

(1)对于SpEL表达式注入漏洞漏洞,可以使用静态分析工具进行代码检查,可以有效规避部分问题。

(2)在此类场景中,对于用户输入,应当仔细校验,检查用户输入的合法性,保障其内容为正常数据。且在端侧与服务侧均应对用户数据进行校验,对非受信用户输入数据进行净化,避免用户输入任意内容。

(3)及时更新Spring Framework版本,避免因版本老旧而被利用的问题发生。

(4)使用源码静态分析工具进行白盒自动化检测,在代码合入阶段、静态分析监控阶段及时发现相关问题。

文章来自:PaaS技术创新Lab,PaaS技术创新Lab隶属于华为云,致力于综合利用软件分析、数据挖掘、机器学习等技术,为软件研发人员提供下一代智能研发工具服务的核心引擎和智慧大脑。

PaaS技术创新Lab主页链接:PaaS技术创新Lab-华为云

点击关注,第一时间了解华为云新鲜技术~

以上是关于web安全Spel表达式注入漏洞的主要内容,如果未能解决你的问题,请参考以下文章

Java安全-注入漏洞(SQL注入命令注入表达式注入模板注入)

小白科普Web安全基础之SQL注入XSS文件上传漏洞详解

网络安全学习-WEB安全常见漏洞

Web安全——SQL注入漏洞

第三天--注入攻击:Web安全之SQL注入漏洞专题

WEB安全基础入门—操作系统命令注入(shell 注入)