2

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>
mtfly
  • 35
  • 6

2 Answers2

1

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 fixed1; 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 suspect2 that you can't. At least not with Tomcat.


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.

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thank you for the post.But when i try to break at `public void appendBytes(MessageBytes mb)`, the IDE didn't even stop.Then i tried to use IDE's "force step in" to find the filter code.At last, I stoped at `private void write(MessageBytes mb)` in `package org.apache.coyote.http11`, class `Http11OutputBuffer`. – mtfly Sep 01 '20 at 03:16
  • And CRLF injection via header name is also impossible,It's handled by the same method. – mtfly Sep 01 '20 at 03:39
  • Yea ... well, like I said "And possibly other places as well". – Stephen C Sep 01 '20 at 07:04
0

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.

t.olev
  • 73
  • 5