示例#1
0
def test_is_record_magic():
    assert not tls.is_tls_record_magic(b"POST /")
    assert not tls.is_tls_record_magic(b"\x16\x03")
    assert not tls.is_tls_record_magic(b"\x16\x03\x04")
    assert tls.is_tls_record_magic(b"\x16\x03\x00")
    assert tls.is_tls_record_magic(b"\x16\x03\x01")
    assert tls.is_tls_record_magic(b"\x16\x03\x02")
    assert tls.is_tls_record_magic(b"\x16\x03\x03")
    def ignore_connection(self, server_address: Optional[context.Address],
                          data_client: bytes) -> Optional[bool]:
        """
        Returns:
            True, if the connection should be ignored.
            False, if it should not be ignored.
            None, if we need to wait for more input data.
        """
        if not ctx.options.ignore_hosts and not ctx.options.allow_hosts:
            return False

        hostnames: List[str] = []
        if server_address is not None:
            hostnames.append(server_address[0])
        if is_tls_record_magic(data_client):
            try:
                ch = parse_client_hello(data_client)
                if ch is None:  # not complete yet
                    return None
                sni = ch.sni
            except ValueError:
                pass
            else:
                if sni:
                    hostnames.append(sni)

        if not hostnames:
            return False

        print("hostnames to check:", hostnames)
        print("ignore hosts options:", ctx.options.ignore_hosts)
        print("allow hosts options:", ctx.options.allow_hosts)
        if ctx.options.ignore_hosts:
            res = any(
                re.search(rex, host, re.IGNORECASE) for host in hostnames
                for rex in ctx.options.ignore_hosts)
            print("ignore hosts result (True means ignore):", res)
            return res
        elif ctx.options.allow_hosts:
            res = not any(
                re.search(rex, host, re.IGNORECASE) for host in hostnames
                for rex in ctx.options.allow_hosts)
            print("allow hosts result (True means ignore):", res)
            return res
        else:  # pragma: no cover
            raise AssertionError()
示例#3
0
    def _next_layer(self, context: context.Context, data_client: bytes,
                    data_server: bytes) -> Optional[layer.Layer]:
        if len(context.layers) == 0:
            return self.make_top_layer(context)

        if len(data_client) < 3 and not data_server:
            return None  # not enough data yet to make a decision

        # helper function to quickly check if the existing layer stack matches a particular configuration.
        def s(*layers):
            return stack_match(context, layers)

        # 1. check for --ignore/--allow
        ignore = self.ignore_connection(context.server.address, data_client)
        if ignore is True:
            return layers.TCPLayer(context, ignore=True)
        if ignore is None:
            return None

        # 2. Check for TLS
        client_tls = is_tls_record_magic(data_client)
        if client_tls:
            # client tls usually requires a server tls layer as parent layer, except:
            #  - a secure web proxy doesn't have a server part.
            #  - reverse proxy mode manages this itself.
            if (s(modes.HttpProxy) or s(modes.ReverseProxy)
                    or s(modes.ReverseProxy, layers.ServerTLSLayer)):
                return layers.ClientTLSLayer(context)
            else:
                # We already assign the next layer here os that ServerTLSLayer
                # knows that it can safely wait for a ClientHello.
                ret = layers.ServerTLSLayer(context)
                ret.child_layer = layers.ClientTLSLayer(context)
                return ret

        # 3. Setup the HTTP layer for a regular HTTP proxy or an upstream proxy.
        if (s(modes.HttpProxy) or
                # or a "Secure Web Proxy", see https://www.chromium.org/developers/design-documents/secure-web-proxy
                s(modes.HttpProxy, layers.ClientTLSLayer)):
            if ctx.options.mode == "regular":
                return layers.HttpLayer(context, HTTPMode.regular)
            else:
                return layers.HttpLayer(context, HTTPMode.upstream)

        # 4. Check for --tcp
        if any(
            (context.server.address and rex.search(context.server.address[0]))
                or (context.client.sni and rex.search(context.client.sni))
                for rex in self.tcp_hosts):
            return layers.TCPLayer(context)

        # 5. Check for raw tcp mode.
        very_likely_http = (context.client.alpn
                            and context.client.alpn in HTTP_ALPNS)
        probably_no_http = not very_likely_http and (
            not data_client[:3].isalpha(
            )  # the first three bytes should be the HTTP verb, so A-Za-z is expected.
            or data_server  # a server greeting would be uncharacteristic.
        )
        if ctx.options.rawtcp and probably_no_http:
            return layers.TCPLayer(context)

        # 6. Assume HTTP by default.
        return layers.HttpLayer(context, HTTPMode.transparent)
示例#4
0
    def _next_layer(self, context: context.Context, data_client: bytes, data_server: bytes) -> Optional[layer.Layer]:
        if len(context.layers) == 0:
            return self.make_top_layer(context)

        if len(data_client) < 3 and not data_server:
            return None

        client_tls = is_tls_record_magic(data_client)

        def s(*layers):
            return stack_match(context, layers)

        top_layer = context.layers[-1]

        # 1. check for --ignore/--allow
        ignore = self.ignore_connection(context.server.address, data_client)
        if ignore is True:
            return layers.TCPLayer(context, ignore=True)
        if ignore is None:
            return None

        # 2. Check for TLS
        if client_tls:
            # client tls requires a server tls layer as parent layer
            # reverse proxy mode manages this itself.
            # a secure web proxy doesn't have a server part.
            if isinstance(top_layer, layers.ServerTLSLayer) or s(modes.ReverseProxy) or s(modes.HttpProxy):
                return layers.ClientTLSLayer(context)
            else:
                return layers.ServerTLSLayer(context)

        # 3. Setup the HTTP layer for a regular HTTP proxy or an upstream proxy.
        if any([
            s(modes.HttpProxy),
            # or a "Secure Web Proxy", see https://www.chromium.org/developers/design-documents/secure-web-proxy
            s(modes.HttpProxy, layers.ClientTLSLayer),
        ]):
            if ctx.options.mode == "regular":
                return layers.HttpLayer(context, HTTPMode.regular)
            else:
                return layers.HttpLayer(context, HTTPMode.upstream)

        # 4. Check for --tcp
        if any(
                (context.server.address and rex.search(context.server.address[0])) or
                (context.client.sni and rex.search(context.client.sni))
                for rex in self.tcp_hosts
        ):
            return layers.TCPLayer(context)

        # 5. Check for raw tcp mode.
        very_likely_http = (
                context.client.alpn and context.client.alpn in HTTP_ALPNS
        )
        probably_no_http = not very_likely_http and (
                not data_client[:3].isalpha()  # the first three bytes should be the HTTP verb, so A-Za-z is expected.
                or data_server  # a server greeting would be uncharacteristic.
        )
        if ctx.options.rawtcp and probably_no_http:
            return layers.TCPLayer(context)

        # 6. Assume HTTP by default.
        return layers.HttpLayer(context, HTTPMode.transparent)
    def _next_layer(self, top_layer):
        try:
            d = top_layer.client_conn.rfile.peek(3)
        except exceptions.TcpException as e:
            raise exceptions.ProtocolException(str(e))
        client_tls = tls.is_tls_record_magic(d)

        # 1. check for filter
        skipped_url = ""
        is_filtered = False

        if True:  #self.config.check_filter:
            if not top_layer.server_conn.address is None:
                is_filtered = (self.config.check_filter(
                    top_layer.server_conn.address)
                               or selfc.SelfCShared.isTrusted(
                                   top_layer.server_conn.address[0]))
            if is_filtered:
                skipped_url = top_layer.server_conn.address[0]

            if not is_filtered and client_tls:
                try:
                    client_hello = tls.ClientHello.from_file(
                        self.client_conn.rfile)
                except exceptions.TlsProtocolException as e:
                    self.log("Cannot parse Client Hello: %s" % repr(e),
                             "error")
                else:
                    sni_str = client_hello.sni and client_hello.sni.decode(
                        "idna")
                    if not sni_str is None:
                        is_filtered = self.config.check_filter(
                            (sni_str,
                             443)) or selfc.SelfCShared.isTrusted(sni_str)
                    if is_filtered:
                        skipped_url = sni_str
            if is_filtered:
                print("####### MITM Skip, Trusted: " + skipped_url)
                return protocol.RawTCPLayer(top_layer, ignore=True)

        # 2. Always insert a TLS layer, even if there's neither client nor server tls.
        # An inline script may upgrade from http to https,
        # in which case we need some form of TLS layer.
        if isinstance(top_layer, modes.ReverseProxy):
            return protocol.TlsLayer(top_layer, client_tls,
                                     top_layer.server_tls,
                                     top_layer.server_conn.address[0])
        if isinstance(top_layer, protocol.ServerConnectionMixin):
            return protocol.TlsLayer(top_layer, client_tls, client_tls)
        if isinstance(top_layer, protocol.UpstreamConnectLayer):
            # if the user manually sets a scheme for connect requests, we use this to decide if we
            # want TLS or not.
            if top_layer.connect_request.scheme:
                server_tls = top_layer.connect_request.scheme == "https"
            else:
                server_tls = client_tls
            return protocol.TlsLayer(top_layer, client_tls, server_tls)

        # 3. In Http Proxy mode and Upstream Proxy mode, the next layer is fixed.
        if isinstance(top_layer, protocol.TlsLayer):
            if isinstance(top_layer.ctx, modes.HttpProxy):
                return protocol.Http1Layer(top_layer, http.HTTPMode.regular)
            if isinstance(top_layer.ctx, modes.HttpUpstreamProxy):
                return protocol.Http1Layer(top_layer, http.HTTPMode.upstream)

        # 4. Check for other TLS cases (e.g. after CONNECT).
        if client_tls:
            return protocol.TlsLayer(top_layer, True, True)

        # 4. Check for --tcp
        if self.config.check_tcp(top_layer.server_conn.address):
            return protocol.RawTCPLayer(top_layer)

        # 5. Check for TLS ALPN (HTTP1/HTTP2)
        if isinstance(top_layer, protocol.TlsLayer):
            alpn = top_layer.client_conn.get_alpn_proto_negotiated()
            if alpn == b'h2':
                return protocol.Http2Layer(top_layer,
                                           http.HTTPMode.transparent)
            if alpn == b'http/1.1':
                return protocol.Http1Layer(top_layer,
                                           http.HTTPMode.transparent)

        # 6. Check for raw tcp mode
        is_ascii = (
            len(d) == 3 and
            # expect A-Za-z
            all(65 <= x <= 90 or 97 <= x <= 122 for x in d))
        if self.config.options.rawtcp and not is_ascii:
            return protocol.RawTCPLayer(top_layer)

        # 7. Assume HTTP1 by default
        return protocol.Http1Layer(top_layer, http.HTTPMode.transparent)
示例#6
0
    def _next_layer(self, top_layer):
        logging.info('root_context._next_layer(%s)', top_layer)
        try:
            d = top_layer.client_conn.rfile.peek(3)
        except exceptions.TcpException as e:
            logging.info('ignoring protocol: %s', e)
            raise exceptions.ProtocolException(str(e))
        client_tls = tls.is_tls_record_magic(d)
        host, port = '(unknown)', '(unknown)'

        # 1. check for filter
        if self.config.check_filter:
            if top_layer.server_conn.address:
                host, port = top_layer.server_conn.address
            is_filtered = self.config.check_filter(
                top_layer.server_conn.address)
            logging.info('_next_layer: %s is_filtered: %s',
                         vars(top_layer.server_conn), is_filtered)
            if not is_filtered and client_tls:
                try:
                    client_hello = tls.ClientHello.from_file(
                        self.client_conn.rfile)
                except exceptions.TlsProtocolException as e:
                    self.log("Cannot parse Client Hello: %s" % repr(e),
                             "error")
                else:
                    sni_str = client_hello.sni and client_hello.sni.decode(
                        "idna")
                    host, port = (sni_str, 443)
                    is_filtered = self.config.check_filter((host, port))
            logging.info('is_filtered: %s', is_filtered)
            if is_filtered:
                if self.config.options.block_not_ignore:
                    self.log(
                        '-> {}:{} {} blocked'.format(host, port,
                                                     datetime.now()), 'info')
                    raise exceptions.Kill(
                        f'blocked https request to filtered host {host}')
                else:
                    return protocol.RawTCPLayer(top_layer, ignore=True)
            else:
                self.log(
                    '-> {}:{} {} allowed'.format(host, port, datetime.now()),
                    'info')

        # 2. Always insert a TLS layer, even if there's neither client nor server tls.
        # An inline script may upgrade from http to https,
        # in which case we need some form of TLS layer.
        if isinstance(top_layer, modes.ReverseProxy):
            return protocol.TlsLayer(top_layer, client_tls,
                                     top_layer.server_tls,
                                     top_layer.server_conn.address[0])
        if isinstance(top_layer, protocol.ServerConnectionMixin):
            return protocol.TlsLayer(top_layer, client_tls, client_tls)
        if isinstance(top_layer, protocol.UpstreamConnectLayer):
            # if the user manually sets a scheme for connect requests, we use this to decide if we
            # want TLS or not.
            if top_layer.connect_request.scheme:
                server_tls = top_layer.connect_request.scheme == "https"
            else:
                server_tls = client_tls
            return protocol.TlsLayer(top_layer, client_tls, server_tls)

        # 3. In Http Proxy mode and Upstream Proxy mode, the next layer is fixed.
        if isinstance(top_layer, protocol.TlsLayer):
            if isinstance(top_layer.ctx, modes.HttpProxy):
                return protocol.Http1Layer(top_layer, http.HTTPMode.regular)
            if isinstance(top_layer.ctx, modes.HttpUpstreamProxy):
                return protocol.Http1Layer(top_layer, http.HTTPMode.upstream)

        # 4. Check for other TLS cases (e.g. after CONNECT).
        if client_tls:
            return protocol.TlsLayer(top_layer, True, True)

        # 4. Check for --tcp
        if self.config.check_tcp(top_layer.server_conn.address):
            return protocol.RawTCPLayer(top_layer)

        # 5. Check for TLS ALPN (HTTP1/HTTP2)
        if isinstance(top_layer, protocol.TlsLayer):
            alpn = top_layer.client_conn.get_alpn_proto_negotiated()
            if alpn == b'h2':
                return protocol.Http2Layer(top_layer,
                                           http.HTTPMode.transparent)
            if alpn == b'http/1.1':
                return protocol.Http1Layer(top_layer,
                                           http.HTTPMode.transparent)

        # 6. Check for raw tcp mode
        is_ascii = (
            len(d) == 3 and
            # expect A-Za-z
            all(65 <= x <= 90 or 97 <= x <= 122 for x in d))
        if self.config.options.rawtcp and not is_ascii:
            return protocol.RawTCPLayer(top_layer)

        # 7. Assume HTTP1 by default
        return protocol.Http1Layer(top_layer, http.HTTPMode.transparent)