Exemple #1
0
    def __init__(self):
        Analyzer.__init__(self)
        self.region = self.get_param("config.region").lower()
        self.client_id = self.get_param("config.client_id", None,
                                        "No Threat Response client ID given.")
        self.client_password = self.get_param(
            "config.client_password", None,
            "No Threat Response client Password given.")
        self.extract_amp_targets = self.get_param("config.extract_amp_targets",
                                                  False)

        # Validate that the supplied region is valid
        if self.region and self.region not in ("us", "eu", "apjc"):
            self.error(
                "{} is not a valid Threat Response region. Must be 'us', 'eu', or 'apjc'"
                .format(self.region))

        # Set region to '' if 'us' was supplied
        if self.region == "us":
            self.region = ""

        # Create Threat Response client
        self.client = ThreatResponse(
            client_id=self.client_id,
            client_password=self.client_password,
            region=self.region,
        )
def get_module(module_name=MODULE_NAME):
    tr = ThreatResponse(CTR_CLIENT_ID, CTR_CLIENT_PASSWORD)

    modules = tr.int.module_instance.get()

    return next(
        (module for module in modules if module['name'] == module_name), None)
Exemple #3
0
def check_for_sighting(returned_observables_json):
    '''
    this function checks if there is a sighting for a specific observable
    '''
    ctr_client = ThreatResponse(
    client_id=config_file["ctr"]["client_id"],  
    client_password=config_file["ctr"]["client_password"],  
    region='us',  # can be change to eu or apjc
    )

    data = returned_observables_json

    response = ctr_client.enrich.observe.observables(data)
    
    #check if request was succesful
    if response:
        
        returned_data = response

        total_amp_sighting_count = 0
        total_umbrella_sighting_count = 0
        total_email_sighting_count = 0

        # run through all modules to check for sightings (currently checking the amp, umbrella and SMA modules)
        for module in returned_data['data']:
            if module['module'] == "AMP for Endpoints":
                # json key not always there, error checking...
                if 'sightings' in module['data']:
                    # store amount of sightings
                    total_amp_sighting_count = module['data']['sightings']['count']

            if module['module'] == "Umbrella":
                # json key not always there, error checking...
                if 'sightings' in module['data']:
                    # store amount of sightings
                    total_umbrella_sighting_count = module['data']['sightings']['count']

            if module['module'] == "SMA Email":
                # json key not always there, error checking...
                if 'sightings' in module['data']:
                    # store amount of sightings
                    total_email_sighting_count = module['data']['sightings']['count']

        # create dict to store information regarding the sightings

        total_sighting_count = total_amp_sighting_count + total_umbrella_sighting_count + total_email_sighting_count

        return_sightings = {
            'total_sighting_count': total_sighting_count,
            'total_amp_sighting_count': total_amp_sighting_count,
            'total_umbrella_sighting_count': total_umbrella_sighting_count,
            'total_email_sighting_count': total_email_sighting_count
        }

        return(return_sightings)

    else:
        print(f"Sighting check request failed...\n")
        return(response)
def add(client_id, client_password, settings_file):
    tr = ThreatResponse(client_id, client_password)

    settings = load_settings(settings_file)

    modules = tr.int.module_instance.get()

    module = _module(modules, settings)
    if module:
        template = 'Relay module "{name}" already exists!'
        message = template.format(**settings)
        raise ModuleAlreadyExistsError(message)

    tr.int.module_instance.post(settings)

    template = 'Relay module "{name}" has been successfully added!'
    return template.format(**settings)
def remove(client_id, client_password, settings_file):
    tr = ThreatResponse(client_id, client_password)

    settings = load_settings(settings_file)

    modules = tr.int.module_instance.get()

    module = _module(modules, settings)
    if not module:
        template = 'Relay module "{name}" does not exist!'
        message = template.format(**settings)
        raise ModuleDoesNotExistError(message)

    tr.int.module_instance.delete(module['id'])

    template = 'Relay module "{name}" has been successfully removed!'
    return template.format(**settings)
Exemple #6
0
    def connect(self):
        message = None

        try:
            tr = ThreatResponse(
                client_id=self._client_id,
                client_password=self._client_password,
                region=self._region
            )

            self.check_scopes(tr)
            return tr

        except RegionError as error:
            self.debug_print(repr(error))
            message = (
                'Please make sure that your Region is valid.'
            )

        except ScopeError as error:
            self.debug_print(repr(error))
            message = error.args[0]

        except HTTPError as error:
            self.debug_print(repr(error))
            if self.is_authentication_error(error.response):
                message = (
                    'Please make sure that your API credentials '
                    '(Client ID and Client Password) are valid.'
                )
            else:
                message = 'Unexpected HTTPError occurred.'

        except ConnectionError as error:
            self.debug_print(repr(error))
            message = 'Failed to connect to Cisco Threat Response.'

        except Exception as error:
            self.debug_print(repr(error))
            message = 'Unexpected error occurred.'

        raise Exception(message)
def main():
    client_id = ''
    client_password = ''

    client = ThreatResponse(client_id=client_id,
                            client_password=client_password,
                            region='us')

    cleaup_modules(client)

    module_configs = get_module_type_configs()
    module_output = {}

    for module in module_configs:
        config = read_module_type_config(module)
        response = post_module_type(client, config)
        module_id = response['id']
        title = response['title']
        module_output.setdefault(module_id, title)
        save_module_id(module_id)
def test_python_module_negative_token(token, error):
    """Perform testing of availability perform request to the Threat response
    using invalid token

    ID: CCTRI-1579-4ca2a94f-db81-44c9-bf5b-53146cfd127a

    Steps:

        1. Inspect observable using empty token
        2. Inspect observable using invalid token

    Expectedresults: Inspect for provided observable doesn't returns expected
        values, because token is invalid

    Importance: Critical
    """
    with pytest.raises(error):
        assert ThreatResponse(token=token).inspect.inspect(
            {'content': '1.1.1.1'}) != [{
                'type': 'ip',
                'value': '1.1.1.1'
            }]
Exemple #9
0
def return_observables(tweet_text):
    '''
    this function will parse raw text and return the observables and types
    '''
    ctr_client = ThreatResponse(
    client_id=config_file["ctr"]["client_id"],  
    client_password=config_file["ctr"]["client_password"],  
    region='us',  # can be change to eu or apjc
    )

    data = {"content":tweet_text}

    response = ctr_client.inspect.inspect(data)

    #check if request was succesful
    if response:
        return(response) 
    elif response == []:
        print(f"No observables found for tweet:\n\n{tweet_text}\n")
        return False
    else:
        print(f"Error occured in inspecting tweet:\n\n{tweet_text}\n")
        return False
def edit(client_id, client_password, settings_file):
    tr = ThreatResponse(client_id, client_password)

    settings = load_settings(settings_file)

    modules = tr.int.module_instance.get()

    module = _module(modules, settings)
    if not module:
        template = 'Relay module "{name}" does not exist!'
        message = template.format(**settings)
        raise ModuleDoesNotExistError(message)

    diff = _diff(module, settings)
    if not diff:
        template = 'Relay module "{name}" has not been changed!'
        message = template.format(**settings)
        raise ModuleHasNotBeenChangedError(message)

    tr.int.module_instance.patch(module['id'], diff)

    template = 'Relay module "{name}" has been successfully edited!'
    return template.format(**settings)
Exemple #11
0
def return_non_clean_observables(returned_observables_json):
    '''
    this function returns only non clean observables (to remove noise)
    '''

    ctr_client = ThreatResponse(
    client_id=config_file["ctr"]["client_id"],  
    client_password=config_file["ctr"]["client_password"],  
    region='us',  # can be change to eu or apjc
    )

    # create empty list to store clean observables
    clean_observables = []
    
    # retrieve dispositions for observables
    response = ctr_client.enrich.deliberate.observables(returned_observables_json)

    disposition_observables = response

    # parse through json and search for observables with clean disposition (1)
    for module in disposition_observables['data']:
        module_name = module['module']
        if 'verdicts' in module['data'] and module['data']['verdicts']['count'] > 0:
            docs = module['data']['verdicts']['docs']
            for doc in docs:
                observable = doc['observable']
                # if the disposition is clean / 1 then add to separate list to remove from other list
                if doc['disposition'] == 1:
                    clean_observables.append(observable)
                    #print(f"Clean observable, omitting: {observable}\n")

    non_clean_observables = [i for i in returned_observables_json if not i in clean_observables or clean_observables.remove(i)]
    
    non_clean_observables_json = non_clean_observables

    return non_clean_observables_json
Exemple #12
0
def module_tool_client_token(module_token):
    return ThreatResponse(token=module_token)
Exemple #13
0
def module_tool_client():
    return ThreatResponse(client_id=settings.server.ctr_client_id,
                          client_password=settings.server.ctr_client_password)
def main():
    '''Main script logic
    '''

    # Calculate now timestamp and store as file system friendly string
    now = datetime.now()
    start_time = datetime.strftime(now, '%Y-%m-%dT%H.%M.%S.%f')

    # Validate a SHA256 or file was provided
    user_input, input_type = validate_input()

    # AMP for Endpoints API Credentials
    amp_client_id = 'a1b2c3d4e5f6g7h8i9j0'
    amp_client_password = '******'
    amp_hostname = 'api.amp.cisco.com'

    # Instantiate AMP for Endpoints Session
    amp_session = requests.Session()
    amp_session.auth = (amp_client_id, amp_client_password)

    # Threat Response API Credentials
    tr_client_id = 'client-asdf12-34as-df12-34as-df1234asdf12'
    tr_client_password = '******'

    # Instantiate Threat Response Client
    client = ThreatResponse(
        client_id=tr_client_id,
        client_password=tr_client_password,
    )

    # Container to store SHA256s that have malicious disposition in AMP cloud
    malicious_hashes = set()

    if input_type == 'File':
        # Validate and store user provided hashes in a set
        validated_user_provided_hashes, invalid_user_provided_hashes = validate_file_contents(user_input)
        print() # New line so "Getting SCD Lists" is printed in its own section
    else:
        # Store the user provided SHA256
        validated_user_provided_hashes = {user_input}

    # Get Simple Custom Detaction File Lists
    print('Getting SCD Lists')
    scd_lists = get_scd_file_lists(amp_session, amp_hostname).json()
    data = scd_lists.get('data', [])

    # Present SCD Lists to user and ask which one to use
    for index, scd in enumerate(data, start=1):
        print(f'{index} - {scd["name"]}')
    index = ask_for_scd_index(len(data))

    # Name SCD Name and GUID
    scd_name = data[index]['name']
    scd_guid = data[index]['guid']

    # Query AMP for Endpoints to get list items for selected SCD List
    print(f'\nGetting SHA256s for: {scd_name}')
    scd_list_items = get_file_list_items(amp_session, amp_hostname, scd_guid)

    # Put the SHA256s from the SCD List into a set using set comprehension
    existing_list_items = {list_item.get("sha256") for list_item in scd_list_items}

    # Inform how many SCD List items were found
    print(f'SHA256s on {scd_name}: {len(existing_list_items)}')

    # Compare user provided hashes against the slected SCD List
    new_user_provided_hashes = compare_list_items(
        scd_name, existing_list_items, validated_user_provided_hashes
    )

    if not new_user_provided_hashes:
        sys.exit(f'\nAll of the provided SHA256s are already on {scd_name}\nBye!')

    # Build Threat Response Enrich Payloads using list comprehension
    enrich_payloads = [{"value": sha256, "type": "sha256"} for sha256 in new_user_provided_hashes]

    # Split payloads into list of lists with 20 items maximum
    item_count = len(enrich_payloads)
    if item_count > 20:
        print(f'\nSplitting into {math.ceil(item_count/20)} chunks of 20 or less and checking verdicts')
    else:
        print('\nChecking verdicts to remove any known malicious SHA256s')
    chunked_enrich_payloads = split_list(enrich_payloads)

    # Iterate over list and get Verdicts for list of SCD List items
    for payload_index, payload in enumerate(chunked_enrich_payloads, start=1):

        # Query Threat Response for verdcits
        print(f'  Checking verdicts for chunk {payload_index} of {len(chunked_enrich_payloads)}')
        verdicts = get_verdicts(client, payload)
        parse_verdicts(verdicts, malicious_hashes)

    # Inform how many malicious dispositions were returned
    print(f'Number of provided SHA256s with a malicious disposition: {len(malicious_hashes)}')

    non_malicious_user_provided_hashes = new_user_provided_hashes.difference(malicious_hashes)

    if not non_malicious_user_provided_hashes:
        sys.exit('\nProvided SHA256s are already malicious in the AMP File Reputation Database\nBye!')

    if not confirm_continue(
            f'\nDo you want to add {len(non_malicious_user_provided_hashes)}'
            f' SHA256(s) to {scd_name}? (y/n): '
    ):
        sys.exit("Bye!")

    # Iterate over remaining SHA256(s) and add to selected SCD List
    for sha256 in non_malicious_user_provided_hashes:
        print(f'Adding {sha256}', end=' ')
        response = add_list_item(amp_session, amp_hostname, scd_guid, sha256)
        if response.ok:
            print('- DONE!')
        else:
            print('- SOMETHING WENT WRONG!')
Exemple #15
0
def main():
    '''The main script logic
    '''

    # Warn user and verify that you want to continue
    print('-=== WARNING THIS SCRIPT WILL DELETE THINGS ===-')
    if not confirm_continue():
        sys.exit("Bye!")

    # Threat Response Credentials
    tr_client_id = 'client-asdf12-34as-df12-34as-df1234asdf12'
    tr_client_password = '******'

    # Instantiate Threat Response client
    client = ThreatResponse(client_id=tr_client_id,
                            client_password=tr_client_password)

    # Define CTIM entities to delete
    entities = [
        'actor', 'attack-pattern', 'campaign', 'casebook', 'coa', 'incident',
        'indicator', 'judgement', 'malware', 'relationship', 'sighting',
        'tool', 'weakness'
    ]

    # Store response from second confirmation to continue
    delete_objects = False

    for entity in entities:
        print(entity)

        # Build Private Intel search objects
        obj = build_object(client, entity, 'search')

        # Search Private Intel for entity
        # A time range can be submitted as the query to delete entities within that range
        # response = search(obj, 'timestamp:["2020-01-01T01:00:00.000Z" TO "2020-03-31T00:00:00.000Z"]')
        response = search(obj)

        # Extract IDs from response
        ids = extract_ids(response)

        # Print number of IDs found
        print('  Found:', len(ids))

        # Build Private Intel delete objects
        obj = build_object(client, entity, 'delete')

        # Warn user and verify that you want to continue
        if not delete_objects and len(ids) > 0:
            print(
                '\n-=== FINAL WARNING CONTINUING WILL DELETE EVERYTHING FOUND ===-'
            )
            print(
                '-===         WILL NOT ASK AGAIN FOR OTHER ENTITIES         ===-'
            )
            if not confirm_continue():
                sys.exit("Bye!")
            else:
                delete_objects = True

        # Delete the entities
        delete(obj, ids)  # UNCOMMENT TO DELETE STUFF
Exemple #16
0
def new_casebook(returned_observables_json,returned_sightings,user_name,tweet_text):
    '''
    this function post list of observables to new case in casebook
    '''
    ctr_client = ThreatResponse(
    client_id=config_file["ctr"]["client_id"],  
    client_password=config_file["ctr"]["client_password"],  
    region='us',  # can be change to eu or apjc
    )

    # create title and description for SOC researcher to have more context, if there are sightings, add high priority
    if returned_sightings['total_sighting_count'] == 0:
        casebook_title = " #opendir Tweet: " + user_name
    if returned_sightings['total_sighting_count'] != 0:
        casebook_title = "*HIGH PRIORITY* #opendir Tweet: " + user_name

    casebook_description = f"Twitter generated casebook from #opendir by: {user_name}, Tweet: {tweet_text}"
    casebook_datetime = datetime.now().isoformat() + "Z"

    # create right json format to create casebook
    casebook_json = {
        "title": casebook_title,
        "description": casebook_description,
        "observables": returned_observables_json,
        "type": "casebook",
        "timestamp": casebook_datetime   
    }

    # create CTR search url
    search_base_url = "https://visibility.amp.cisco.com/investigate?q="
    for observable in returned_observables_json:
        search_string_to_append = observable["type"] + "%3A" + observable["value"] + "%0A"
        search_base_url = search_base_url + search_string_to_append

    # post request to create casebook
    response = ctr_client.private_intel.casebook.post(casebook_json)
    if response:
        print(f"[201] Success, case added to Casebook added from #opendir Tweet by: {user_name}\n")
        
        # if Webex Teams tokens set, then send message to Webex room
        if config_file['webex']['access_token'] == '' or config_file['webex']['room_id'] == '':

            # user feed back
            print("Webex Teams not set.\n\n")
        else:            
            # instantiate the Webex handler with the access token
            teams = webexteamssdk.WebexTeamsAPI(config_file['webex']['access_token'])

            # post a message to the specified Webex room 
            try:
                if returned_sightings['total_sighting_count'] == 0:
                    webex_text = f"🚨🚨🚨 - **New case added to SecureX Casebook added from 🐦 *#OPENDIR*!** - 🚨🚨🚨\n\nTweet by {user_name}:\n\n---\n>{tweet_text}\n\n---\n\n**Investigate directly with SecureX threat response:** {search_base_url}"
                    message = teams.messages.create(config_file['webex']['room_id'], markdown=webex_text) 
                if returned_sightings['total_sighting_count'] != 0:
                    webex_text = f"🚨🚨🚨 - **New case added to SecureX Casebook added from 🐦 *#OPENDIR*!** - 🚨🚨🚨\n\nTweet by {user_name}:\n\n---\n>{tweet_text}\n\n---\n\n**HIGH PRIORITY**, Target Sightings have been identified! AMP targets: {str(returned_sightings['total_amp_sighting_count'])}, Umbrella targets: {str(returned_sightings['total_umbrella_sighting_count'])}, Email targets: {str(returned_sightings['total_email_sighting_count'])}.\n\n**Investigate directly with SecureX threat response:** {search_base_url}"
                    message = teams.messages.create(config_file['webex']['room_id'], markdown=webex_text)
            # error handling, if for example the Webex API key expired
            except Exception:
                print("Webex authentication failed... Please make sure Webex Teams API key has not expired. Please review developer.webex.com for more info.\n")
    else:
        print(f"Something went wrong while posting the casebook to CTR...\n")

    return response
def main():
    '''Main script logic
    '''

    # Calculate now timestamp and store as file system friendly string
    now = datetime.now()
    start_time = datetime.strftime(now, '%Y-%m-%dT%H.%M.%S.%f')

    # AMP for Endpoints API Credentials
    amp_client_id = 'a1b2c3d4e5f6g7h8i9j0'
    amp_client_password = '******'
    amp_hostname = 'api.amp.cisco.com'

    # Instantiate AMP for Endpoints Session
    amp_session = requests.Session()
    amp_session.auth = (amp_client_id, amp_client_password)

    # Threat Response API Credentials
    tr_client_id = 'client-asdf12-34as-df12-34as-df1234asdf12'
    tr_client_password = '******'

    # Instantiate Threat Response Client
    client = ThreatResponse(
        client_id=tr_client_id,
        client_password=tr_client_password,
    )

    # Container to store SHA256s that have malicious disposition in AMP cloud
    malicious_hashes = []

    # Get Simple Custom Detaction File Lists
    scd_lists = get_scd_file_lists(amp_session, amp_hostname).json()
    data = scd_lists.get('data', [])

    # Present SCD Lists to user and ask which one to process
    for index, scd in enumerate(data, start=1):
        print(f'{index} - {scd["name"]}')
    index = ask_for_scd_index(len(data))

    # Name SCD Name and GUID
    scd_name = data[index]['name']
    scd_guid = data[index]['guid']

    # Get List items for selected SCD List
    print(f'\nGetting SHA256s for: {scd_name}')
    scd_list_items = get_file_list_items(amp_session, amp_hostname, scd_guid)

    # Build Threat Response Enrich Payloads using list comprehension
    enrich_payloads = [
        {"value": list_item.get("sha256"), "type": "sha256"} for list_item in scd_list_items
    ]

    # Inform how many SCD List items were found
    item_count = len(enrich_payloads)
    print(f'SHA256s on {scd_name}: {item_count} \n')
    if not enrich_payloads:
        sys.exit()

    # Split payloads into list of lists with 20 items maximum
    if item_count > 20:
        print(f'Splitting into {math.ceil(item_count/20)} chunks of 20 or less and checking verdicts')
    else:
        print('Checking verdicts')
    chunked_enrich_payloads = split_list(enrich_payloads)

    # Iterate over list and get Verdicts for list of SCD List items
    for payload_index, payload in enumerate(chunked_enrich_payloads, start=1):

        # Query Threat Response for verdcits
        print(f'  Checking verdicts for chunk {payload_index} of {len(chunked_enrich_payloads)}')
        verdicts = get_verdicts(client, payload)
        parse_verdicts(verdicts, malicious_hashes)

    # Inform how many malicious dispositions were returned
    print(f'Number of SHA256s on {scd_name} with a malicious disposition: {len(malicious_hashes)}')

    # Verify there are SHA256s with malicious dispositions and confirm the user wants to delete them
    if malicious_hashes:
        file_name = f'{replace_space(scd_name)}_{scd_guid}_{start_time}.txt'
        print(f'\nSaving SHA256s to file:\n  {file_name}')
        save_list_items(file_name, malicious_hashes)
        if not confirm_continue(
                f'\nDo you want to remove these SHA256s from {scd_name}? (y/n): '
        ):
            sys.exit("Bye!")
    else:
        sys.exit()

    # Delete SHA256s with malicious disposition from selected SCD List
    for sha256 in malicious_hashes:
        print(f'Deleting {sha256}', end=' ')
        response = delete_list_item(amp_session, amp_hostname, scd_guid, sha256)
        if response.ok:
            print('- DONE!')
        else:
            print('- SOMETHING WENT WRONG!')