英文:
How can i change this code to be vulnerable of CRLF injection?
问题
我创建了一个简单的Spring Web项目,项目中只有一个控制器(Controller),其代码如下:
package com.example.sbtest.controller;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MainController {
@RequestMapping("/crlf")
@ResponseBody
public void CRLFInjectVuln(HttpServletResponse response, @RequestParam("id") String id) {
response.addHeader("test", id);
}
}
然后我尝试使用类似以下的 curl 命令触发 CRLF 注入漏洞:
curl -vvvv "http://127.0.0.1:8080/crlf" --data "id=x\r\nLocation:%20https://www.google.com"
curl -vvvv "http://127.0.0.1:8080/crlf" --data "id=x%0d%0aLocation:%20https://www.google.com"
但是所有的响应都好像 CRLF 被替换为空格:
HTTP/1.1 200
Cookies: Location: https://www.google.com
Content-Length: 0
Date: Mon, 31 Aug 2020 09:27:58 GMT
因此,我想知道如何编写一个容易受到 CRLF 注入攻击的代码?是因为 Tomcat 或 Spring 过滤了我的输入参数,所以这个攻击方式不起作用吗?但我已经追踪了整个代码,没有找到类似于过滤的代码。
我的 pom.xml 文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sbtest</artifactId>
<version>0.1</version>
<name>sbtest</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
英文:
I create a simple spring web project, and there is only one Controller in the project, its code is:
package com.example.sbtest.controller;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MainController {
@RequestMapping("/crlf")
@ResponseBody
public void CRLFInjectVuln(HttpServletResponse response, @RequestParam("id") String id) {
response.addHeader("test", id);
}
}
Then i tried to trigger the CRLF inject vuln with curl like these commands:
curl -vvvv "http://127.0.0.1:8080/crlf" --data "id=x\r\nLocation:%20https://www.google.com"
curl -vvvv "http://127.0.0.1:8080/crlf" --data "id=x%0d%0aLocation:%20https://www.google.com"
But all of them returned as through the CRLF was replaced to space:
HTTP/1.1 200
Cookies: Location: https://www.google.com
Content-Length: 0
Date: Mon, 31 Aug 2020 09:27:58 GMT
So, how could i write a piece of code that are vulnerable of CRLF injection?
Could it because of the Tomcat or the Spring filtered my input parameter, so this didn't work? But i tracked down all the way through the code, didn't get any code seem like a filter.
My pom.xml file is:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sbtest</artifactId>
<version>0.1</version>
<name>sbtest</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
答案1
得分: 1
> 这可能是因为Tomcat或Spring过滤了我的输入参数,所以这没生效?
根据 https://security.stackexchange.com/questions/172908/vulnerable-crlf-environment,对于某些版本的Tomcat来说是的。
实际上,可能是所有版本的Tomcat,自从修复了 CVE-2012-3544 之后<sup>1</sup>;即Tomcat 6.x 版本在 6.0.36 之后,以及 Tomcat 7.x 版本在 7.0.29 之后。
> 我一直追踪代码,没有找到任何看起来像过滤器的代码。
我进行了一些代码挖掘。当Tomcat输出堆栈将响应头值写入输出流时,它会将ASCII控制字符(除了TAB)和DEL转换为空格。这是在AjpMessage
类的public void appendBytes(MessageBytes mb)
方法中完成的。(可能还有其他地方也会这样做。)
> 我怎样更改这段代码以使其易受CRLF注入攻击?
我怀疑<sup>2</sup>你不能。至少在Tomcat中不行。
<sup>1 - CVE指的是一种特定的CRLF注入攻击,该攻击是通过一个Tomcat漏洞变得可能的,而不是通过Web应用程序对响应头的不安全使用来实现的。你尝试的注入方式无法利用该漏洞。</sup>
<sup>2 - 我没有检查通过头部名称是否可能进行注入,但很难理解为什么普通的Web应用程序需要将请求参数值用作响应头名称或包含在其中。</sup>
英文:
> Could it because of the Tomcat or the Spring filtered my input parameter, so this didn't work?
According to https://security.stackexchange.com/questions/172908/vulnerable-crlf-environment, the answer is yes for some versions of Tomcat.
In fact, probably for all versions of Tomcat since CVE-2012-3544 was fixed<sup>1</sup>; i.e. Tomcat 6.x after 6.0.36 and 7.x after 7.0.29.
> I tracked down all the way through the code, didn't get any code seem like a filter.
I did some code digging. When the Tomcat output stack writes response header values to the output stream, it converts ASCII control characters (apart from TAB) and DEL into spaces. This is done in the public void appendBytes(MessageBytes mb)
method in the AjpMessage
class. (And possibly other places as well.)
> How can I change this code to be vulnerable of CRLF injection?
I suspect<sup>2</sup> that you can't. At least not with Tomcat.
<sup>1 - The CVE refers to a specific CRLF injection attack that was made possible by a Tomcat bug, not by a webapp's unsafe use of response headers. Your attempted injection would not have worked to exploit that bug.</sup>
<sup>2 - I didn't check whether injection might be possible via the header name, but it is hard to see why a normal webapp would need to use request parameter values as (or in) response header names.</sup>
答案2
得分: 0
Tomcat(9.0.37)例如,使用Http11Processor类来准备响应(参见其prepareResponse()方法),该方法调用Http11OutputBuffer - 请参阅sendHeader()方法的实现。它调用私有的write()方法,该方法将换行字符替换为空格。
Undertow和Jetty也有它们自己的方法来清理标头。
英文:
Tomcat (9.0.37), for example, uses the Http11Processor class to prepare the response (see its prepareResponse() method) which calls Http11OutputBuffer - see the sendHeader() method implementation. It calls the private write() method which substitute the new line characters with space.
Undertow and Jetty have their own ways to sanitize the headers too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论