From fd903673299c050b7b4137aabf6b9265df3d6233 Mon Sep 17 00:00:00 2001 From: iroiro123 Date: Sun, 21 Jun 2015 00:51:56 +0900 Subject: SSL Spoof mode --- libmproxy/cmdline.py | 12 +++++++++++- libmproxy/protocol/http.py | 11 ++++++++--- libmproxy/proxy/config.py | 16 ++++++++++++---- libmproxy/proxy/primitives.py | 15 +++++++++++++++ libmproxy/proxy/server.py | 19 +++++++++++++++++++ 5 files changed, 65 insertions(+), 8 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py index 5111fdd8..08639f6d 100644 --- a/libmproxy/cmdline.py +++ b/libmproxy/cmdline.py @@ -373,7 +373,17 @@ def common_options(parser): group.add_argument( "--spoof", action="store_true", dest="spoof_mode", default=False, - help="Use Host header to connect to HTTP server." + help="Use Host header to connect to HTTP servers." + ) + group.add_argument( + "--ssl-spoof", + action="store_true", dest="ssl_spoof_mode", default=False, + help="Use TLS SNI to connect to HTTPS servers." + ) + group.add_argument( + "--spoofed-port", + action="store", dest="spoofed_ssl_port", type=int, default=443, + help="Port number of upstream HTTPS servers in SSL spoof mode." ) group = parser.add_argument_group( diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 61782698..11436b30 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1336,13 +1336,18 @@ class HTTPHandler(ProtocolHandler): if h is None: raise http.HttpError( 400, - "Invalid request: No Host header" + "Invalid request: No host information" ) p = http.parse_url("http://" + h) - request.host = p[1] - request.port = p[2] + request.scheme = p[0] + request.host = p[1] + request.port = p[2] self.c.set_server_address((request.host, request.port)) flow.server_conn = self.c.server_conn + + if self.c.config.mode == "sslspoof": + # SNI is processed in server.py + return None return None diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 7305d72a..07dc5c89 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -4,7 +4,7 @@ import re from OpenSSL import SSL from netlib import http_auth, certutils, tcp from .. import utils, platform, version -from .primitives import RegularProxyMode, SpoofMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode +from .primitives import RegularProxyMode, SpoofMode, SSLSpoofMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode TRANSPARENT_SSL_PORTS = [443, 8443] CONF_BASENAME = "mitmproxy" @@ -51,7 +51,8 @@ class ProxyConfig: certforward=False, ssl_version_client="secure", ssl_version_server="secure", - ssl_ports=TRANSPARENT_SSL_PORTS + ssl_ports=TRANSPARENT_SSL_PORTS, + spoofed_ssl_port=None ): self.host = host self.port = port @@ -72,6 +73,8 @@ class ProxyConfig: self.mode = UpstreamProxyMode(upstream_server) elif mode == "spoof": self.mode = SpoofMode() + elif mode == "sslspoof": + self.mode = SSLSpoofMode(spoofed_ssl_port) else: self.mode = RegularProxyMode() @@ -128,7 +131,7 @@ def process_proxy_options(parser, options): body_size_limit = utils.parse_size(options.body_size_limit) c = 0 - mode, upstream_server = None, None + mode, upstream_server, spoofed_ssl_port = None, None, None if options.transparent_proxy: c += 1 if not platform.resolver: @@ -149,6 +152,10 @@ def process_proxy_options(parser, options): if options.spoof_mode: c += 1 mode = "spoof" + if options.ssl_spoof_mode: + c += 1 + mode = "sslspoof" + spoofed_ssl_port = options.spoofed_ssl_port if c > 1: return parser.error( "Transparent, SOCKS5, reverse and upstream proxy mode " @@ -218,7 +225,8 @@ def process_proxy_options(parser, options): certforward=options.certforward, ssl_version_client=options.ssl_version_client, ssl_version_server=options.ssl_version_server, - ssl_ports=ssl_ports + ssl_ports=ssl_ports, + spoofed_ssl_port=spoofed_ssl_port ) diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index f514d37f..b01ddde3 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -63,6 +63,21 @@ class SpoofMode(ProxyMode): return "spoof" +class SSLSpoofMode(ProxyMode): + http_form_in = "relative" + http_form_out = "relative" + + def __init__(self, sslport): + self.sslport = sslport + + def get_upstream_server(self, client_conn): + return None + + @property + def name(self): + return "sslspoof" + + class TransparentProxyMode(ProxyMode): http_form_in = "relative" http_form_out = "relative" diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index e1587df1..df890f7c 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -117,6 +117,20 @@ class ConnectionHandler: self.server_conn.address(), "info") self.conntype = "tcp" + + elif not self.server_conn and self.config.mode == "sslspoof": + port = self.config.mode.sslport + self.set_server_address(("-", port)) + self.establish_ssl(client=True) + host = self.client_conn.connection.get_servername() + if host is None: + raise ProxyError( + 400, + "Invalid request: No host information" + ) + self.set_server_address((host, port)) + self.establish_server_connection() + self.establish_ssl(server=True, sni=host) # Delegate handling to the protocol handler protocol_handler( @@ -308,6 +322,9 @@ class ConnectionHandler: host = upstream_cert.cn.decode("utf8").encode("idna") if self.server_conn.sni: sans.append(self.server_conn.sni) + # for ssl spoof mode + if hasattr(self.client_conn, "sni"): + sans.append(self.client_conn.sni) ret = self.config.certstore.get_cert(host, sans) if not ret: @@ -325,6 +342,8 @@ class ConnectionHandler: if not sn: return sni = sn.decode("utf8").encode("idna") + # for ssl spoof mode + self.client_conn.sni = sni if sni != self.server_conn.sni: self.log("SNI received: %s" % sni, "debug") -- cgit v1.2.3