freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

    CVE-2020-5405 Spring Cloud Config Server 目录穿越
    2020-03-07 19:00:34

    事件背景

    Spring Cloud Config为分布式系统的外部配置提供客户端的服务端的支持。使用了它,开发人员就可以在一个中心仓库管理应用程序在所有环境中的外部配置。2020-02-26 Spring 收到漏洞报告, Spring Cloud Config Server 存在目录穿越漏洞。

    时间线

    2020-02-26 Spring 收到漏洞报告, Spring Cloud Config Server 存在目录穿越漏洞
    2020-03-03 Spring Cloud Config Server 更新 2.1.7 版本
    2020-03-04 Spring Cloud Config Server 更新 2.2.2 版本
    2020-03-06 斗象应急响应团队分析出漏洞POC

    漏洞挖掘

    根据描述该漏洞为目录穿越 2.2.0-2.2.1,2.1.0-2.1.6 都受到影响, 所以这里直接下载2.2.1和2.2.2的源码包进行对比

    https://github.com/spring-cloud/spring-cloud-config/releases

    解压后直接使用idea Ctrl+D 进行对比

    很多开源项目都会在test文件中写入本次更新涉及的漏洞点
    比如这次 spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-client/src/test/java/org/springframework/cloud/config/environment/EnvironmentTests.java

    显而易见的这个漏洞是用 (_) 来代替 / 进行目录穿越

    搭建环境

    这里启动 2.2.1环境, 使用idea 打开 (maven项目)
    \spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server
    这里如果速度慢可以修改成阿里源,启动成功后访问
    http://127.0.0.1:8888/foo/default/master/test.json

    补丁对比

    根据上一个目录穿越漏洞

    Spring Cloud Config Server 路径穿越与任意文件读取漏洞分析 – 【CVE-2019-3799】 – 先知社区
    https://xz.aliyun.com/t/4844

    这里可以构造一个路径进行尝试(看看报错)

    /foo/default/master/..(_)..(_)..(_)..(_)etc(_)passwd

    效果不佳,从文中可知请求格式如下

    GET /{name}/{profile}/{label}/{path}

    继续看对应实现源码

    org/springframework/cloud/config/server/resource/ResourceController.java

    这里可以知道请求的格式,这里决定了POC的基本结构

    继续对比可以可以看出, (_) 会在 [name/label] 时被处理成 /

    再根据新增的测试文件
    spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/GenericResourceRepositoryTests.java

    基本可以构造出来如下格式

    由于label中可以解析(_)

    根据提示 “Cannot clone or checkout repository” 以及 代码中的
    this.nativeRepository.setSearchLocations("file:./src/test/resources/test/local");
    这里考虑可能是得采用本地配置文件方式
    玩转Spring Cloud之配置中心(config server &config client) – 梦在旅途 – 博客园
    https://www.cnblogs.com/zuowj/p/10432445.html

    更改配置文件为

    configserver.yml

    info:
      component: Config Server
    spring:
      application:
        name: configserver
      autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
      profiles:
        active: native
      jmx:
        default_domain: cloud.config.server
      cloud:
        config:
          server:
            #如下是本地文件配置
            native:
              search-locations: classpath:/configs #配置文件存放的目录
    
    server:
      port: 8888
    management:
      context_path: /admin
    

    然后再resources目录下新建文件夹 configs
    随便放个配置文件

    configclient-dev.properties

    --configclient-dev.properties内容:
    
    demo-config-profile-env=dev-native
    zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190227
    zuowenjun.skills=.net,java,html,js,css,sql,python,vb--20190227
    zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;--20190227
    

    访问 http://127.0.0.1:8888/configclient/dev

    当native本地方式启动时, {label}无需指定(有用但是对这个漏洞没有影响), 所以这里可以采取{label}可以生效的方式git后端配置的请求格式进行访问

    Spring Cloud Config Server 启动后, GIT仓库中的配置文件会被自动转换成当前项目的web api,若需访问查看远程配置数据可以参照以下的规则:
    /{application}/{profile}[/{label}]
    [/{label}]/{application}-{profile}{.yml|.properties|.json}
    
    规则简单说明:{application}=配置消费方应用名称(即:config client的项目名,通俗讲:就是谁用这个配置就是谁的名字)
    
    {profile}=配置环境(如:dev开发环境,test测试环境,prod生产环境)
    
    {label}=仓库分支名(git或svn方式指定,native本地方式无需指定)
    
    .yml|.properties|.json表示指定的响应返回格式,{}表示必需,[]表示可选,|表示或的关系
    
    或者参考
    https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.2.RELEASE/reference/html/#_placeholders_in_git_uri
    
    https://www.cnblogs.com/zuowj/p/10432445.html
    

    当配置文件中的 search-locations 修改为 file:///c:/ 时,即可在在根目录进行文件读取

    configserver.yml

    info:
      component: Config Server
    spring:
      application:
        name: configserver
      autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
      jmx:
        default_domain: cloud.config.server
      profiles:
        active: native
      cloud:
        config:
          server:
            native:
              search-locations: file:///C:\TCC\Spring-cloud-config-server\spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server\src\main\resources\configs #配置文件存放的目录
    server:
      port: 8888
    management:
      context_path: /admin
    

    断点分析

    通过打断点,我们可以更清晰的看到漏洞的成因

    首先根据路由格式,进入 org.springframework.cloud.config.server.resource.ResourceController#retrieve(java.lang.String, java.lang.String, java.lang.String, org.springframework.web.context.request.ServletWebRequest, boolean) 函数中

    其中参数分别为我们传入的

    name = blah
    
    profile = local
    
    label = 马赛克
    
    path = Windows/win.ini
    

    然后进入org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne函数


    这里会对 Win[-{label}].ini 也就是 win-label.ini win.ini 在对应目录搜索,

    也就是 {search-locations} + {label} 即

    file:///C:\TCC\Spring-cloud-config-server\spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server\src\main\resources\configs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../..//

    也就是进入了C盘根目录, 即可读取文件

    无后缀文件读取

    但是因为org.springframework.cloud.config.server.resource.ResourceController#retrieve(org.springframework.web.context.request.ServletWebRequest, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)中存在对于后缀的匹配导致没有后缀的文件会读取失败

    46对应ascii码的.

    当没有获取到 “.” 的时候返回 null 导致后续 null.toLowerCase() 报错异常退出

    但是在windows中.当文件名后面加空格或者点号.也可以正确处理

    Naming Files, Paths, and Namespaces – Win32 apps | Microsoft Docs
    https://docs.microsoft.com/zh-cn/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN

    Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".
    

    所以在Windows中,我们可以使用文件名加点.的方式进行无后缀文件读取

    漏洞产生根本原因

    org.springframework.cloud.config.server.environment.NativeEnvironmentRepository#getLocations
    这里产生了直接拼接{label}的行为

    所以这里双重url编码/%252f还是可以用,因为最后拼接成的路径是URL类,支持%2f


    使用 %252f 请求

    Spring修复方式

    修复点在
    spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/GenericResourceRepository.java

    org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne函数加入了对路径的判断

    org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidEncodedLocation 会先对路径进行url解码

    org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidLocation 然后检测是否包含 ..

    检测方法

    Windows 可以检测 C:/Windows/win.ini
    Linux 可以检测 /etc/resolv.conf
    (这里测试Windows上file协议无法访问其他盘,如果Spring Cloud Config Server 搜索路径指定在 classpath,可以尝试读取META-INF/下面的文件,这里是个检测难点)

    作者:斗象能力中心 TCC – 小胖虎

    本文作者:, 转载请注明来自FreeBuf.COM

    被以下专辑收录,发现更多精彩内容
    + 收入我的专辑
    评论 按时间排序

    登录/注册后在FreeBuf发布内容哦

    相关推荐
    • 0 文章数
    • 0 评论数
    • 0 关注者
    登录 / 注册后在FreeBuf发布内容哦
    收入专辑