[BUG] docker rustls TLS version/cipher suite/`--insecure` mismatch handling

#1301 · closed · 2 comments

View on GitHub ↗

0x7274

**Describe the bug** This is clearly an edgecase, seemingly not yet discovered. My current suspicion is, that rustls seems to not honor if `--insecure` cert or if TLS versions | cipher suites mismatch. **To Reproduce** 1. feroxbuster docker image 2. transparent proxy to burpsuite with burpsuite certificate installed (works perfectly with curl, wget & other tools) 3. the site to scan 4. -> `--insecure` cert/TLS version/cipher suite mismatch (happens only on some sites where those mismatch) **Expected behavior** A more descriptive output why the handshake/connection failed -> currently most likely culprit being rustls having issues with `--insecure`/handling of the certificate provided (which should be ignored due to `--insecure` **Traceback / Error Output** Not verbose: `Could not connect to https://example.site/, skipping... => error sending request for url (https://example.site/) ERROR: Could not connect to any target provided` Verbose: `WRN 0.377 feroxbuster::utils Error while making request: error sending request for url (https://example.site/) WRN 0.377 feroxbuster::utils err: error sending request for url (https://example.site/) Could not connect to https://example.site/, skipping... => error sending request for url (https://example.site/) WRN 0.377 feroxbuster::heuristics error sending request for url (https://example.site/) INF 0.377 feroxbuster All scans complete! INF 0.377 feroxbuster::event_handlers::statistics Stats { kind: "statistics", timeouts: 0, requests: 2, expected_per_scan: 0, total_expected: 0, errors: 1, successes: 1, redirects: 0, client_errors: 0, server_errors: 0, total_scans: 0, initial_targets: 0, links_extracted: 0, extensions_collected: 0, status_200s: 1, status_301s: 0, status_302s: 0, status_401s: 0, status_403s: 0, status_429s: 0, status_500s: 0, status_503s: 0, status_504s: 0, status_508s: 0, wildcards_filtered: 0, responses_filtered: 0, resources_discovered: 0, url_format_errors: 0, redirection_errors: 0, connection_errors: 0, request_errors: 1, certificate_errors: 0, directory_scan_times: Mutex { data: [], poisoned: false, .. }, total_runtime: Mutex { data: [ 0.0, ], poisoned: false, .. }, json: false, targets: Mutex { data: [ "https://example.site/", ], poisoned: false, .. }, } ` **Environment (please complete the following information):** - feroxbuster version: feroxbuster/2.13.0 - docker **Additional context** There are some sites I tested, that work correctly & some sites don't -> it's currently quite difficult to better troubleshoot & the most likely culprits/differences are listed above (but ofc, maybe there is something I've overlooked) -> If this is generally already known or can't feasibly be fixed, please let me know, so I can build a workaround 👍

Comments

epi052

thanks for reporting this! the underlying http client (reqwest/hyper) no longer exposes exact lower level errors. i've looked into trying to dig out better errors for tls issues in the past and have come up empty handed. I'll take another look to see if this might be a different case, but i'm not terribly hopeful

0x7274

> thanks for reporting this! > > the underlying http client (reqwest/hyper) no longer exposes exact lower level errors. i've looked into trying to dig out better errors for tls issues in the past and have come up empty handed. I'll take another look to see if this might be a different case, but i'm not terribly hopeful @epi052 I've found the exact issue and it's reqwest/hyper as you suspected, but request/hyper is doing what its supposed to do, according to the RFC specs - Burpsuite was/is the culprit! Closing this issue. I really hope nobody else has this issue or decided to waste time on this, otherwise: # Full Issue Description ## Issue Connection Chain simplified: `feroxbuster -> {iptables -> redsocks ->} Burp Suite -> example.site` (Issue also replicates without redsocks using feroxbuster `--proxy`) 1. DNS: example.site -> 203.x.x.77 2. TCP: feroxbuster -> 203.x.x.77:443 -> iptables -> redsocks 3. redsocks -> Burp: CONNECT 203.x.x.77:443 4. TLS (feroxbuster <-> Burp): ALPN negotiates h2 5. TLS (Burp -> upstream): connects to real server 6. HTTP req: feroxbuster -> Burp (HTTP/2 GET /) 7. HTTP req: Burp -> upstream (HTTP/1.1 GET /) 8. HTTP res: upstream -> Burp (HTTP/1.1 200 + Keep-Alive header) 9. HTTP res: Burp -> feroxbuster (HTTP/2 200 + Keep-Alive header) -> FAIL -> `Keep-Alive` is hop-by-hop -> ILLEGAL in HTTP/2 - RFC 9113 §8.2.2 (https://www.rfc-editor.org/rfc/rfc9113.html#name-connection-specific-header-) which is also mentioned on some other sites: (eg. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Keep-Alive) -> Burp SHOULD strip it when converting h1 response to h2 frame! But as it doesn't: 10. hyper/h2 rejects -> PROTOCOL_ERROR -> feroxbuster "Could not connect" ## Trace & replication I've spent quite some time debugging & nearly went mad.... 1. Build the container (I've added my required proxies during troubleshooting, this is not required) `docker start pentest-proxy-burp 2>&1; Start-Sleep -Seconds 3; docker run -d --name ferox-trace --network "container:pentest-proxy-burp" --entrypoint "" 0x7274/feroxbuster:latest sleep infinity 2>&1` 2. Install strace & curl `docker exec -u root ferox-trace sh -c "apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.17/main strace curl openssl 2>&1 | tail -3"` 3. Capture trace `docker exec ferox-trace sh -c "curl -v -k --proxy http://host.docker.internal:8080 https://example.site/ -o /dev/null 2>&1"` In the end of the affected site's trace, it stated the prohibited HTTP 2 Headers: ``` % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Host host.docker.internal:8080 was resolved. * IPv6: (none) * IPv4: 192.168.65.254 * Trying 192.168.65.254:8080... * Connected to host.docker.internal (192.168.65.254) port 8080 * CONNECT tunnel: HTTP/1.1 negotiated * allocate connect buffer * Establish HTTP proxy tunnel to example.site:443 > CONNECT example.site:443 HTTP/1.1 > Host: example.site:443 > User-Agent: curl/8.9.0 > Proxy-Connection: Keep-Alive > < HTTP/1.1 200 Connection established < * CONNECT phase completed * CONNECT tunnel established, response 200 * ALPN: curl offers h2,http/1.1 } [5 bytes data] * TLSv1.3 (OUT), TLS handshake, Client hello (1): } [512 bytes data] * TLSv1.3 (IN), TLS handshake, Server hello (2): { [122 bytes data] * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): { [41 bytes data] * TLSv1.3 (IN), TLS handshake, Certificate (11): { [1968 bytes data] * TLSv1.3 (IN), TLS handshake, CERT verify (15): { [264 bytes data] * TLSv1.3 (IN), TLS handshake, Finished (20): { [52 bytes data] * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): } [1 bytes data] * TLSv1.3 (OUT), TLS handshake, Finished (20): } [52 bytes data] * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / RSASSA-PSS * ALPN: server accepted h2 * Server certificate: * subject: C=PortSwigger; O=PortSwigger; OU=PortSwigger CA; CN=example.site * start date: Apr 15 13:56:09 2026 GMT * expire date: Apr 15 13:56:09 2027 GMT * issuer: C=PortSwigger; ST=PortSwigger; L=PortSwigger; O=PortSwigger; OU=PortSwigger CA; CN=PortSwigger CA * SSL certificate verify result: self-signed certificate in certificate chain (19), continuing anyway. * Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption } [5 bytes data] * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://example.site/ * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: example.site] * [HTTP/2] [1] [:path: /] * [HTTP/2] [1] [user-agent: curl/8.9.0] * [HTTP/2] [1] [accept: */*] } [5 bytes data] > GET / HTTP/2 > Host: example.site > User-Agent: curl/8.9.0 > Accept: */* > * Request completely sent off { [5 bytes data] * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): { [226 bytes data] < HTTP/2 200 < date: Wed, 29 Apr 2026 15:07:02 GMT < server: Apache < strict-transport-security: max-age=31536000; includeSubDomains < x-content-type-options: nosniff < expires: Thu, 01 Dec 1994 16:00:00 GMT < cache-control: max-age=0, private, must-revalidate < x-content-type-options: nosniff < content-length: 4061 < content-type: text/html; charset=ISO-8859-1 < reporting-endpoints: csp-report-default="https://example.site/csp-report/report" < report-to: { "group": "csp-report-default", "max-age": 120, "endpoints": [ { "url": "https://example.site/csp-report/report" } ] } < content-security-policy-report-only: default-src 'none'; frame-ancestors 'none'; report-uri https://example.site/csp-report/report; report-to csp-report-default * Invalid HTTP header field was received: frame type: 1, stream: 1, name: [keep-alive], value: [timeout=4, max=5] } [5 bytes data] * HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1) 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 * Connection #0 to host host.docker.internal left intact curl: (92) Invalid HTTP header field was received: frame type: 1, stream: 1, name: [keep-alive], value: [timeout=4, max=5] ```