Beispiel #1
0
    def process_sessions_remaining_content(self) -> List[Credentials]:

        from csl.core import logger
        remaining = [session for session in self if not session.credentials_being_built.is_empty()]

        if len(remaining) > 0:
            logger.info("Interesting things have been found but the tool weren't able validate them: ")
            # List things that haven't been reported (sometimes the success indicator has
            # not been captured and credentials stay in the session without being logged)
            for session in remaining:
                logger.info(session, str(session.credentials_being_built))

        return remaining
Beispiel #2
0
def _process_packet(packet: Packet, must_inspect_strings):

    # We only support tcp & udp packets for now
    if "tcp" not in packet and "udp" not in packet:
        return

    session = _sessions.get_session_of(packet)

    if len(packet.layers
           ) > 3:  # == tshark parsed something else than ETH, IP, TCP

        for layer in packet.layers[3:]:
            layer_name = layer.layer_name

            if hasattr(layer, "_ws_malformed_expert"):
                raise MalformedPacketException(
                    "[{}] session contains malformed packet in layer '{}'".
                    format(session, layer_name))

            # Not based on layer name, can be found in different layers
            if hasattr(layer, "nt_status") or (
                    hasattr(layer, "ntlmssp_identifier")
                    and layer.ntlmssp_identifier == "NTLMSSP"):
                session.protocol = layer_name.upper()
                are_credentials_valid = ntlmssp.analyse(session, layer)

                if are_credentials_valid:
                    session.validate_credentials()

            # Analyse the layer with the appropriate parser
            if layer_name in parsers:
                session.protocol = layer_name.upper()
                are_credentials_valid = parsers[layer_name].analyse(
                    session, layer)

                if are_credentials_valid:
                    session.validate_credentials()

    if must_inspect_strings:
        strings = utils.extract_strings_splitted_on_end_of_line_from(packet)
        emails_found = extract.extract_emails(strings)
        credit_cards_found = extract.extract_credit_cards(strings)

        for email in emails_found:
            logger.info(session, "Found email address: " + email)

        for credit_card in credit_cards_found:
            logger.info(
                session,
                "Credit card '{}' found: '{}'".format(credit_card.name,
                                                      credit_card.number))
Beispiel #3
0
def active_processing(interface: str,
                      must_inspect_strings=False,
                      tshark_filter=None,
                      debug=False,
                      decode_as=None,
                      pcap_output=None):

    global _sessions

    logger.DEBUG_MODE = debug
    _sessions = SessionList()

    _sessions.manage_outdated_sessions()
    signal.signal(signal.SIGINT, signal_handler)

    live = pyshark.LiveCapture(interface=interface,
                               bpf_filter=tshark_filter,
                               decode_as=decode_as,
                               output_file=pcap_output)
    logger.info("Listening on {}...".format(interface))

    if debug:
        live.set_debug()

    try:
        for packet in live.sniff_continuously():
            try:
                _process_packet(packet, must_inspect_strings)

            except MalformedPacketException as e:
                logger.error(str(e) + ", extractor will keep going")

            except Exception:
                traceback.print_exc()
                logger.error(
                    "An exception occurred but extractor will keep going.")

    except TSharkCrashException:
        logger.error("tshark crashed :( Please report the following error :")
        traceback.print_exc()
        signal_handler(None, None)
Beispiel #4
0
def process_pcap(filename: str,
                 must_inspect_strings=False,
                 tshark_filter=None,
                 debug=False,
                 decode_as=None) -> SessionList:

    global _sessions

    logger.DEBUG_MODE = debug
    _sessions = SessionList()

    pcap = pyshark.FileCapture(filename,
                               display_filter=tshark_filter,
                               decode_as=decode_as)
    logger.info("Processing packets in '{}'".format(filename))

    if debug:
        pcap.set_debug()

    start_time = time.time()

    for packet in pcap:
        try:
            _process_packet(packet, must_inspect_strings)

        except MalformedPacketException as e:
            logger.error(str(e) + ", extractor will keep going")

        except Exception:
            traceback.print_exc()
            logger.error(
                "An exception occurred but extractor will keep going.")

    _sessions.process_sessions_remaining_content()

    logger.info("Processed in {0:.3f} seconds.".format(time.time() -
                                                       start_time))
    pcap.close()
    return _sessions
Beispiel #5
0
def analyse(session: Session, layer: Layer) -> bool:

    current_creds = session.credentials_being_built

    if hasattr(layer, "server_greeting"):

        if hasattr(layer, "version"):
            logger.info(session, "MySQL version: " + layer.version)

        if hasattr(layer, "salt"):
            current_creds.context["salt"] = layer.salt

        if hasattr(layer, "salt2"):
            current_creds.context["salt2"] = layer.salt2

    if hasattr(layer, "client_auth_plugin"):
        logger.info(session, "MySQL auth plugin: " + layer.client_auth_plugin)

    if hasattr(layer, "user"):
        current_creds.username = layer.user
        current_creds.hash = "".join(layer.passwd.split(":"))

    if hasattr(layer, "response_code"):
        response_code = int(layer.response_code, 16)

        if current_creds.username and response_code == 0:

            for item in current_creds.context:
                logger.found(
                    session,
                    "{} found: {}".format(item, current_creds.context[item]))

            logger.found(
                session,
                "credentials found: {} -- {}".format(current_creds.username,
                                                     current_creds.hash))
            return True

    return False
Beispiel #6
0
def analyse(session: Session, layer: Layer) -> bool:

    current_creds = session.credentials_being_built

    if hasattr(layer, "authtype"):
        # values signification can be found here https://www.postgresql.org/docs/8.2/protocol-message-formats.html
        auth_type = int(layer.authtype)

        if auth_type == 5:
            current_creds.context["auth_type"] = "md5"

        elif auth_type == 4:
            current_creds.context["auth_type"] = "crypt"

        elif auth_type == 3:
            current_creds.context["auth_type"] = "cleartext"

        elif auth_type == 10:
            current_creds.context["auth_type"] = "sasl"

        elif auth_type == 0 and current_creds.username:
            if current_creds.hash:
                logger.found(
                    session,
                    "credentials found ! Username: {} | Hash: {} | Salt: {}".
                    format(current_creds.username, current_creds.hash,
                           current_creds.context["salt"]))
            elif current_creds.password:
                logger.found(
                    session,
                    "credentials found ! Username: {} | Password: {}".format(
                        current_creds.username, current_creds.password))
            else:
                logger.found(
                    session,
                    "it seems that '{}' authenticated without password".format(
                        current_creds.username))

            if "database" in current_creds.context:
                logger.info("Targeting database '{}'".format(
                    current_creds.context["database"]))

            return True

    if hasattr(layer, "parameter_name"):

        # Sometimes tshark returns multiple fields with the same name
        parameter_names = layer.parameter_name.all_fields
        parameter_values = layer.parameter_value.all_fields

        for i in range(len(parameter_names)):

            parameter_name = parameter_names[i].show
            parameter_value = parameter_values[i].show

            if parameter_name == "user":
                current_creds.username = parameter_value

            elif parameter_name == "database":
                current_creds.context["database"] = parameter_value

            elif parameter_name == "server_version":
                logger.info(session, "PostgreSQL version: " + parameter_value)

    if hasattr(layer, "salt"):
        current_creds.context["salt"] = layer.salt.replace(":", "")

    elif hasattr(layer, "password"):

        if "auth_type" in current_creds.context and current_creds.context[
                "auth_type"] != "cleartext":
            current_creds.hash = layer.password
            auth_type = current_creds.context["auth_type"]

            # Remove the hash type from the hash string
            if current_creds.hash.startswith(auth_type):
                current_creds.hash = current_creds.hash[len(auth_type):]

        else:
            current_creds.password = layer.password

    return False
Beispiel #7
0
def analyse(session: Session, layer: Layer) -> bool:

    current_creds = session.credentials_being_built

    if hasattr(layer, "request_uri"):

        extension = layer.request_uri.split(".")[-1]

        if extension in HTTP_IGNORED_EXTENSIONS:
            return False

        if hasattr(layer,
                   "request_full_uri") and layer.request_full_uri.startswith(
                       "http://ocsp."):  # Ignore Certificate Status Protocol
            return False

        if hasattr(layer, "authorization"):
            tokens = layer.authorization.split(" ")

            if len(tokens) == 2 and tokens[0] == "Basic":
                try:
                    credentials = base64.b64decode(tokens[1]).decode()
                    colon_index = credentials.find(":")
                    current_creds.username = credentials[:colon_index]
                    current_creds.password = credentials[colon_index + 1:]
                    session[
                        "authorization_header_uri"] = layer.request_full_uri
                except UnicodeDecodeError:
                    logger.error("HTTP Basic auth failed: " + tokens)

            elif len(tokens) == 2 and tokens[0] == "NTLM":
                pass  # Already handled by the NTLMSSP module

            else:
                logger.info(
                    session, "Authorization header found: '{}'".format(
                        layer.authorization))

        # POST parameters
        if hasattr(layer, "file_data"):
            post_content = layer.file_data

            if len(post_content) <= HTTP_AUTH_MAX_LOGIN_POST_LENGTH:
                logger.info(session,
                            "POST data found: '{}'".format(post_content))
                post_parameters = parse_qs(post_content)

                # We don't want to interfere with the Authorization header potentially being built
                credentials = Credentials()

                credentials.context["Method"] = "POST"
                credentials.context["URL"] = layer.request_full_uri

                logger.info(session, "context: " + str(credentials.context))

                for parameter in post_parameters:
                    if parameter in HTTP_AUTH_POTENTIAL_USERNAMES:
                        credentials.username = post_parameters[parameter][0]
                    elif parameter in HTTP_AUTH_POTENTIAL_PASSWORDS:
                        credentials.password = post_parameters[parameter][0]

                if credentials.username:
                    logger.found(
                        session, "credentials found: {} -- {}".format(
                            credentials.username, credentials.password))
                    session.credentials_list.append(credentials)

                    # We return false to prevent the manager from validating the credentials being built
                    return False

        # GET parameters
        elif hasattr(layer, "request_uri_query"):
            get_parameters = parse_qs(layer.request_uri_query)

            # We don't want to interfere with the Authorization header potentially being built
            credentials = Credentials()

            credentials.context["Method"] = "GET"
            credentials.context["URL"] = layer.request_full_uri

            for parameter in get_parameters:
                if parameter in HTTP_AUTH_POTENTIAL_USERNAMES:
                    credentials.username = get_parameters[parameter][0]
                elif parameter in HTTP_AUTH_POTENTIAL_PASSWORDS:
                    credentials.password = get_parameters[parameter][0]

            if credentials.username:
                logger.found(
                    session, "credentials found: {} -- {}".format(
                        credentials.username, credentials.password))
                logger.info(session, "context: " + str(credentials.context))
                session.credentials_list.append(credentials)

                # We return false to prevent the manager from validating the credentials being built
                return False

    elif hasattr(layer, "response_for_uri"):

        if session["authorization_header_uri"] == layer.response_for_uri:

            # If auth failed + prevent duplicates
            if layer.response_code == "401" or current_creds in session.credentials_list:
                session.invalidate_credentials_and_clear_session()

            else:
                logger.found(
                    session, "basic auth credentials found: {} -- {}".format(
                        current_creds.username, current_creds.password))
                return True

    return False
Beispiel #8
0
        if args.listen:
            ip_filter = "host " + args.filter

    decode_map = None

    if args.map:
        decode_map = {}

        for map in args.map:
            tokens = map.split(":")

            if len(tokens) != 2:
                parser.error("Invalid port mapping")

            decode_map["tcp.port==" + tokens[0]] = tokens[1]
            logger.info("extractor will decode traffic on '{}' as '{}'".format(*tokens))

    if args.output:

        if os.path.isfile(args.output):
            parser.error(args.output + " already exists")

        logger.OUTPUT_FILE = open(args.output, "w")

    if args.listen:

        if os.geteuid() != 0:
            print("You must be root to listen on an interface.")
            exit(1)

        if args.listen_output and os.path.isfile(args.listen_output):