RFD漏洞

前言:这篇参考了一位公司内的师傅的文章,所以这边简单的记录下,主要学习一下分号的绕过技巧

参考文章:https://www.blackhat.com/docs/eu-14/materials/eu-14-Hafif-Reflected-File-Download-A-New-Web-Attack-Vector.pdf
参考文章:https://github.com/spring-projects/spring-framework/commit/2bd1daa75ee0b8ec33608ca6ab065ef3e1815543
参考文章:https://github.com/spring-projects/spring-framework/commit/aec3a4c69e02d87f87258b0ab5c1d6c83f4cb44f

什么是RFD漏洞

RFD,即Reflected File Download反射型文件下载漏洞,是一个2014年来自BlackHat的漏洞,攻击者可以通过一个URL地址使用户下载一个恶意文件,从而危害用户的终端PC,不过这个漏洞危害上可能接近于self-xss,因为就算浏览器下载了,打开的话也还是需要自己点击打开,并不是自动打开,就比较鸡肋吧,想要利用的难度就比较高

想要实现RFD漏洞,还需要满足如下三个条件

  • 输入反射:用户输入被“反射”到响应内容,这个点的话就是说明能够控制文件的内容

  • 文件名可控: URL允许并接受用户的其他输入,攻击者将其用于将文件扩展名设置为可执行扩展名,那么后缀名就可以控制,比如sh,bat脚本之类就可以控制运行

  • 下载:响应被作为文件里的内容进行下载,这里可以控制Content-Type或者在自己的服务器上创建一个HTML文件,设置download属性,诱导点击下载。

CVE-2015-5211

pom.xml

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

这边直接可以来看org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters的部分

首先是获取返回值的类型 org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#getReturnValueType,我这边请求的是http://127.0.0.1:8080/spring/content.sh?content=test,所以这边拿到的就是字符串"test"

再接着就是进行内容协商机制的操作,首先是org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#getAcceptableMediaTypes,这个操作主要就是获取当前请求的accept的类型是什么,它会根据请求对象servletRequest来进行判断

其中会调用org.springframework.web.accept.ContentNegotiationManager#resolveMediaTypes,其中有contentNegotiationStrategies中两个策略通过resolveMediaTypes来进行匹配

其中的一个strategy是org.springframework.web.accept.PathExtensionContentNegotiationStrategy#getMediaTypeKey,分别获得请求过来的文件名和文件的后缀名

String filename = WebUtils.extractFullFilenameFromUrlPath(path);
String extension = StringUtils.getFilenameExtension(filename);

getProducibleMediaTypes函数根据当前的接口返回的类型returnValueClass来获取能够处理该返回类型的accpet字段

接着遍历getProducibleMediaTypes,将能够处理该returnValueClass的accept字段放入到compatibleMediaTypes

最后再通过遍历messageConverters数组来调用messageConverters的canWrite方法来查看是否能处理该compatibleMediaTypes的messageConverter

满足的messageConverter作为org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdviceChain#invoke的参数

最后再调用org.springframework.http.converter.HttpMessageConverter#write写入返回值,因为匹配到的是sh文件,最终就是以sh文件来进行输出

输出的结果如下所示

漏洞修复

参考地址:https://github.com/spring-projects/spring-framework/commit/2bd1daa75ee0b8ec33608ca6ab065ef3e1815543

把pom.xml文件修改到如下修复版本进行测试

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>

可以看到其中被修改的地方,在写入的时候又重新通过addContentDispositionHeader方法来校验了下后缀名,如下图所示

跟到addContentDispositionHeader中,可以发现调用了safeExtension方法

跟进safeExtension方法,首先会通过白名单判断,如果是白名单的话直接返回true

跟进safeExtension方法中会有个safeMediaType方法,最终还是会通过如下三个进行判断,如果不符合下面三个并且结尾不是+xml的话,那么最终还是返回false

如果还是之前的利用发包的话,那么最终为false的情况下就会被修改为f.txt来进行展示,如下图所示

CVE-2020-5421

CVE-2020-5421实际上就是对CVE-2015-5211的绕过

这边还需要在application.properties配置如下两条信息

spring.mvc.pathmatch.use-suffix-pattern=true
spring.mvc.contentnegotiation.favor-path-extension=true

如果不配置的话,默认请求的接口在当前版本不允许有后缀,如下图所示

主要的绕过点是在org.springframework.web.util.UrlPathHelper#getOriginatingRequestUri,还是经典的逻辑绕过配合;来进行绕过

这里分析下org.springframework.web.util.UrlPathHelper#getOriginatingRequestUri方法,这个就是对uri进行的处理,实际上会调用decodeAndCleanUriString方法

而这里的话org.springframework.web.util.UrlPathHelper#removeSemicolonContent方法就是对分号后面的进行处理

而如果我们让getOriginatingRequestUri拿到的requestUri的值是无后缀名的话,那么最终filename就是无后缀名的,那么在safeExtension方法中直接满足空返回为true

getOriginatingRequestUri中是通过removeSemicolonContent分号处理,所以这边就可以来进行绕过

访问:http://127.0.0.1:8080/spring/;jsessionid=/content.sh?content=123456,可以看到此时的ext后缀名就是null,那么此时safeExtension默认就是为true,则不会进入判断内

这边为什么要;jessionid呢?主要的原因是AbstractMessageConverterMethodProcessor类中初始化的时候对如下的两个属性进行了设置

导致在removeSemicolonContent调用的时候走的是removeJsessionid方法,如下图所示

漏洞修复

参考文章:https://github.com/spring-projects/spring-framework/commit/aec3a4c69e02d87f87258b0ab5c1d6c83f4cb44f

pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.11.RELEASE</version>
</dependency>

可以看到直接把removeSemicolonContent的功能直接给去掉了,如下图所示

posted @   zpchcbd  阅读(277)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2020-02-21 反汇编:函数指针
2020-02-21 反汇编:指针数组和数组指针
2020-02-21 反汇编:字符串的3种表达方式
点击右上角即可分享
微信分享提示