应用安全系列之十六:Expression Language (EL) Injection

聂永怡
2023-12-01

本系列文章主旨在于介绍一些漏洞类型产生的基本原理,探索最基础的解决问题的措施。

关于什么是EL(Expression Language),不在这里详细叙述,可以参考 9 Expression Language (Release 7) 和 Overview of the EL - The Java EE 6 Tutorial

EL确实给实现带来了很多方便,例如:在JSLT中,可以直接显示一个对象的一个属性:<c:out value=”person.name”/> , 使用Java代码就需要显示为:<%=HTMLEncoder.encode(((Person)person).getName())%>。不过,带来便利的同时,也带来了一些风险。

EL的主要功能有:

  • 动态读取存储在JavaBean组件、各种数据结构和对象的应用数据
  • 动态将用户的数据写入form或者JavaBean组件
  • 动态调用公共的动态方法
  • 动态地执行算术运算

看到EL的这些功能,我们可能就知道,使用它是一件比较危险的事情,因为他可以读取或者写入数据,还可以动态调用公共的静态方法。EL注入主要是因为将不可信的数据传递给EL解释器,EL解释器将其中注入的一些恶意的代码解析并执行。而且,在一些框架(例如:SpringMVC)中EL标签被Evaluate两次,一个是应用服务器、另外一个就是Spring标签解析的实现。

例如:一个URL是:https://ww.test.com/info?msg=${applicationScope},对应的页面的代码中使用<spring:message text="" code="${param['msg']}"></spring:message>显示消息。由于msg的内容被Evaluate两次,所以会把applicaitonScope对象的toString的内容打印出来,如下:

{org.apache.catalina.jsp_classpath=/ home/test/ELInjection/target/ Test/WEB-INF/classes/: Test/WEB-INF/lib/aopalliance- 1.0.jar:/home/test/ELInjection/ target/Test/WEB-INF/lib/ commons-logging-1.1.1.jar ...
}

由于applicaitonScope对象中含有classpath、应用程序工作路径以及其他信息,这些信息可以被攻击者用来挖掘下一步攻击, 也可以通过注入${9999+1},如果查看结果显示为10000,那就可能存在EL注入。接着可以注入一些可以执行命令的串再试试,例如:

${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke("".getClass().forName("java.lang.Runtime")).exec("calc.exe")}

在进一步了解如何预防EL注入之前,首先需要了解哪些技术或者框架使用了EL,并且可能造成EL注入。

JSTLJSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
OGNL对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2等框架中,作用是对数据进行访问,它拥有类型转换、访问对象方法、操作集合对象等功能。
MVELMVEL是一个功能强大的基于Java应用程序的表达式语言。
SPELSpring Expression Language(缩写为SpEL)是一种强大的表达式语言。在Spring产品组合中,它是表达式计算的基础。它支持在运行时查询和操作对象图,它可以与基于XML和基于注解的Spring配置还有bean定义一起使用。

EL注入攻击可能造成的危害如下:

  • 泄露服务器端的信息,例如:答应applicaitonScope或者requestScope等全局变量的值;
  • 绕过Httponly,例如:param=${cookie["JSESSIONID"].value},将cookie的值写入HTML,这样JavaScript就可以读取cookie的值
  • 执行系统命令或者任意代码

可见EL注入的危害非常大,Struts2也经常因为ONGL而报出RCE相关的漏洞。

在使用这些技术之前,就需要小心,如何避免EL注入的问题。

  1. 最简单也是最安全的做法就是禁用EL表达式;
  2. 在使用任何数据作为EL的部分之前,对数据进行验证,保证没有${和#{;记住:不要使用替换的方法,将${替换为空会导致"$${{"----> "${",遇到错误就报错处理,不要尝试修复错误的输入;如果有明确取值范围的,使用白名单方法验证。
  3. Spring 3.1之后的版本,双重解析默认是关闭的,尽量使用新版本的第三方库;
  4. 使用编码方法将特殊字符进行编码,此方法和XSS的编码比较类似,需要根据输出的背景进行编码,否则,显示的时候,无法自动解码。

如果有不妥之处,希望可以留言指出。谢谢!

参考:

https://www.reshiftsecurity.com/el-injection-primer-for-java-developers/

CWE-917 : Expression Language (EL) Injection - kiuwan - Kiuwan documentation

https://owasp.org/www-community/vulnerabilities/Expression_Language_Injectionhttps://portswigger.net/kb/issues/00100f20_expression-language-injectionhttp://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/https://mindedsecurity.com/wp-content/uploads/2020/10/ExpressionLanguageInjection.pdf

 类似资料: