From 14d8c91250aeb0e1e8d76b83bfa15c00c8091700 Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Wed, 22 Feb 2017 21:49:31 +0530 Subject: [PATCH 1/5] Adds --keep-host-header option (#2039) --- mitmproxy/options.py | 2 ++ mitmproxy/proxy/protocol/http.py | 2 +- mitmproxy/tools/cmdline.py | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mitmproxy/options.py b/mitmproxy/options.py index 2467b9dda..ff17fbbfd 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -72,6 +72,7 @@ class Options(optmanager.OptManager): upstream_bind_address: str = "", mode: str = "regular", no_upstream_cert: bool = False, + keep_host_header: bool = False, http2: bool = True, http2_priority: bool = False, @@ -162,6 +163,7 @@ class Options(optmanager.OptManager): self.upstream_bind_address = upstream_bind_address self.mode = mode self.no_upstream_cert = no_upstream_cert + self.keep_host_header = keep_host_header self.http2 = http2 self.http2_priority = http2_priority diff --git a/mitmproxy/proxy/protocol/http.py b/mitmproxy/proxy/protocol/http.py index a7d56f24b..a351ad666 100644 --- a/mitmproxy/proxy/protocol/http.py +++ b/mitmproxy/proxy/protocol/http.py @@ -290,7 +290,7 @@ class HttpLayer(base.Layer): request.first_line_format = "relative" # update host header in reverse proxy mode - if self.config.options.mode == "reverse": + if self.config.options.mode == "reverse" and not self.config.options.keep_host_header: f.request.host_header = self.config.upstream_server.address.host # Determine .scheme, .host and .port attributes for inline scripts. For diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index bb0bb17a1..18db3c8f0 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -112,6 +112,7 @@ def get_common_options(args): replacements=args.replacements, replacement_files=args.replacement_files, setheaders=args.setheaders, + keep_host_header=args.keep_host_header, server_replay=args.server_replay, scripts=args.scripts, stickycookie=stickycookie, @@ -387,6 +388,11 @@ def proxy_options(parser): action="store", type=str, dest="upstream_bind_address", help="Address to bind upstream requests to (defaults to none)" ) + group.add_argument( + "--keep-host-header", + action="store_true", dest="keep_host_header", + help="Keep the host header as proxy addres" + ) def proxy_ssl_options(parser): From 2e90373e4b484b94d0306b9764c7416b6156304f Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Wed, 22 Feb 2017 23:32:16 +0530 Subject: [PATCH 2/5] Updates help msg and docs for --keep-host-header --- docs/features/reverseproxy.rst | 5 +++-- mitmproxy/tools/cmdline.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/features/reverseproxy.rst b/docs/features/reverseproxy.rst index 85ad33e8a..f58fad951 100644 --- a/docs/features/reverseproxy.rst +++ b/docs/features/reverseproxy.rst @@ -31,7 +31,8 @@ Host Header In reverse proxy mode, mitmproxy automatically rewrites the Host header to match the upstream server. This allows mitmproxy to easily connect to existing endpoints on the -open web (e.g. ``mitmproxy -R https://example.com``). +open web (e.g. ``mitmproxy -R https://example.com``). But this behaviour can be +be disabled by passing ``--keep-host-header`` on the console. However, keep in mind that absolute URLs within the returned document or HTTP redirects will NOT be rewritten by mitmproxy. This means that if you click on a link for "http://example.com" @@ -39,4 +40,4 @@ in the returned web page, you will be taken directly to that URL, bypassing mitm One possible way to address this is to modify the hosts file of your OS so that "example.com" resolves to your proxy's IP, and then access the proxy by going directly to example.com. -Make sure that your proxy can still resolve the original IP, or specify an IP in mitmproxy. \ No newline at end of file +Make sure that your proxy can still resolve the original IP, or specify an IP in mitmproxy. diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index 18db3c8f0..11558cc3a 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -391,7 +391,7 @@ def proxy_options(parser): group.add_argument( "--keep-host-header", action="store_true", dest="keep_host_header", - help="Keep the host header as proxy addres" + help="Reverse Proxy: Keep the original host header instead of rewriting it to the reverse proxy target." ) From 317d183ba4eb78a16605da5e866726e8231a75fb Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Thu, 23 Feb 2017 16:19:18 +0530 Subject: [PATCH 3/5] Changes dns_spoofing example to use --keep-host-header --- examples/complex/dns_spoofing.py | 11 +++-------- test/mitmproxy/test_examples.py | 2 -- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/complex/dns_spoofing.py b/examples/complex/dns_spoofing.py index acda303d8..2fd6b699b 100644 --- a/examples/complex/dns_spoofing.py +++ b/examples/complex/dns_spoofing.py @@ -13,6 +13,8 @@ Usage: -s dns_spoofing.py # Used as the target location if neither SNI nor host header are present. -R http://example.com/ + # To avoid auto rewriting of host header by the reverse proxy target. + --keep-host-header mitmdump -p 80 -R http://localhost:443/ @@ -29,13 +31,6 @@ parse_host_header = re.compile(r"^(?P[^:]+|\[.+\])(?::(?P\d+))?$") class Rerouter: - def requestheaders(self, flow): - """ - The original host header is retrieved early - before flow.request is replaced by mitmproxy new outgoing request - """ - flow.metadata["original_host"] = flow.request.host_header - def request(self, flow): if flow.client_conn.ssl_established: flow.request.scheme = "https" @@ -46,7 +41,7 @@ class Rerouter: sni = None port = 80 - host_header = flow.metadata["original_host"] + host_header = flow.request.host_header m = parse_host_header.match(host_header) if m: host_header = m.group("host").strip("[]") diff --git a/test/mitmproxy/test_examples.py b/test/mitmproxy/test_examples.py index f3603fca8..668d0d4a2 100644 --- a/test/mitmproxy/test_examples.py +++ b/test/mitmproxy/test_examples.py @@ -114,13 +114,11 @@ class TestScripts(tservers.MasterTest): # Rewrite by reverse proxy mode f.request.scheme = "https" - f.request.host = "mitmproxy.org" f.request.port = 443 m.request(f) assert f.request.scheme == "http" - assert f.request.host == original_host assert f.request.port == 80 assert f.request.headers["Host"] == original_host From 3da8532bed3305b01e3f3ab556f9dbc652177c6b Mon Sep 17 00:00:00 2001 From: Nikhil Soni Date: Thu, 2 Mar 2017 15:59:44 +0530 Subject: [PATCH 4/5] Adds test for --keep-host-header --- test/mitmproxy/proxy/test_server.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index 0be772a41..46beea41d 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -482,6 +482,26 @@ class TestHTTPSNoCommonName(tservers.HTTPProxyTest): class TestReverse(tservers.ReverseProxyTest, CommonMixin, TcpMixin): reverse = True + def test_host_header(self): + self.config.options.keep_host_header = True + p = self.pathoc() + with p.connect(): + resp = p.request("get:/p/200:h'Host'='example.com'") + assert resp.status_code == 200 + + req = self.master.state.flows[0].request + assert req.host_header == "example.com" + + def test_overridden_host_header(self): + self.config.options.keep_host_header = False # default value + p = self.pathoc() + with p.connect(): + resp = p.request("get:/p/200:h'Host'='example.com'") + assert resp.status_code == 200 + + req = self.master.state.flows[0].request + assert req.host_header == "127.0.0.1" + class TestReverseSSL(tservers.ReverseProxyTest, CommonMixin, TcpMixin): reverse = True From 50ebdf3081d4cf3b16532c4a8bdea6bfa94cbbba Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 4 Mar 2017 11:42:30 +0100 Subject: [PATCH 5/5] update docs wording --- docs/features/reverseproxy.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/reverseproxy.rst b/docs/features/reverseproxy.rst index f58fad951..57b353ae1 100644 --- a/docs/features/reverseproxy.rst +++ b/docs/features/reverseproxy.rst @@ -31,8 +31,8 @@ Host Header In reverse proxy mode, mitmproxy automatically rewrites the Host header to match the upstream server. This allows mitmproxy to easily connect to existing endpoints on the -open web (e.g. ``mitmproxy -R https://example.com``). But this behaviour can be -be disabled by passing ``--keep-host-header`` on the console. +open web (e.g. ``mitmproxy -R https://example.com``). You can disable this behaviour +by passing ``--keep-host-header`` on the console. However, keep in mind that absolute URLs within the returned document or HTTP redirects will NOT be rewritten by mitmproxy. This means that if you click on a link for "http://example.com"