SSDeepSimilarity

This script finds similar files that can be related to each other by fuzzy hash (SSDeep).

python · Common Scripts

Source

import tempfile
import traceback

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

HEADERS = "ssdeep,1.1--blocksize:hash:hash,filename\n"

""" COMMAND FUNCTION """


def _handle_existing_outputs(anchor_hash: str, output_key: str, new_hashes_outputs: list):
    context = demisto.get(demisto.context(), f"{output_key}")
    if not context:
        context = []
    elif not isinstance(context, list):
        context = [context]
    context = list(filter(lambda item: item.get("SourceHash") == anchor_hash, context))

    if context:
        context = context[0].get("compared_hashes")

    new_hashes = [current_hash.get("hash") for current_hash in new_hashes_outputs]
    res = []

    for item in context:
        if item.get("hash") not in new_hashes:
            res.append(item)
    res += new_hashes_outputs
    return res


def _handle_inputs(args: dict):
    anchor_hash = args.get("ssdeep_hash")
    if not anchor_hash:
        raise ValueError("Please provide an hash to compare to.")
    hashes_to_compare = argToList(args.get("ssdeep_hashes_to_compare"))
    if not hashes_to_compare:
        raise ValueError("Please provide at least one hash to compare with.")

    output_key = args.get("output_key", "SSDeepSimilarity")
    return anchor_hash, hashes_to_compare, output_key


def _format_results(results: list) -> List[dict]:
    """
    Args:
        results: a list of results with the following format:
        ['"<hash>","<anchor_hash>",<score>']

    Returns: a list of dictionaries containing the hash and score

    """
    formatted_res = []

    # Remove last empty value returned from the process
    if not results[-1]:
        results = results[:-1]

    for result in results:
        result = result.split(",")
        formatted_res.append({"hash": result[0].strip('"'), "similarityValue": int(result[2])})
    return formatted_res


def run_ssdeep_command(anchor_hash: str, hashes_to_compare: str):
    with tempfile.NamedTemporaryFile() as anchor_hashes_file, tempfile.NamedTemporaryFile() as hashes_to_compare_file:
        anchor_hashes_file.write(bytes(anchor_hash, encoding="utf-8"))
        anchor_hashes_file.flush()
        hashes_to_compare_file.write(bytes(hashes_to_compare, encoding="utf-8"))
        hashes_to_compare_file.flush()
        stream = os.popen(f"ssdeep -k {anchor_hashes_file.name} {hashes_to_compare_file.name} -c -a")  # nosec
        return stream.read().split("\n")


def compare_ssdeep(anchor_hash: str, hashes_to_compare: list, output_key: str) -> CommandResults:
    hashes_list_to_file = HEADERS
    anchor_hash_to_file = f'{HEADERS}{anchor_hash},"{anchor_hash}"\n'

    for current_hash in hashes_to_compare:
        hashes_list_to_file += f'{current_hash},"{current_hash}"\n'
    res = run_ssdeep_command(anchor_hash_to_file, hashes_list_to_file)
    hashes_outputs = _format_results(res)
    hashes_outputs_merged = _handle_existing_outputs(anchor_hash, output_key, hashes_outputs)
    md = tableToMarkdown(anchor_hash, hashes_outputs)
    return CommandResults(
        outputs_prefix=output_key,
        readable_output=md,
        outputs_key_field="SourceHash",
        outputs={"SourceHash": anchor_hash, "compared_hashes": hashes_outputs_merged},
    )


""" MAIN FUNCTION """


def main():
    try:
        args = demisto.args()
        anchor_hash, hashes_to_compare, output_key = _handle_inputs(args)
        res = compare_ssdeep(anchor_hash, hashes_to_compare, output_key)
        return_results(res)

    except Exception as ex:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"Failed to compare ssdeep hashes. Error: {ex!s}")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()

README

This script finds similar files that can be related to each other by fuzzy hash (SSDeep).

Script Data


Name Description
Script Type python3
Tags  
Cortex XSOAR Version 5.5.0

Inputs


Argument Name Description
ssdeep_hash The SSDeep hash to check for similarity against.
ssdeep_hashes_to_compare A list of SSDeep hashes to check for similarity to the ssdeep_hash input.
output_key The context key to which the list of SSDeep hashes will be outputted.
In case used, the default outputs will not contain the results.
In order to get results, replace the SSDeepSimilarity in default outputs with the output_key provided.

Outputs


Path Description Type
SSDeepSimilarity.compared_hashes.similarityValue The difference calculation score between the ssdeep_hash and the compared hash. number
SSDeepSimilarity.compared_hashes.hash The hash compared to the ssdeep_hash. string

Please note the outputs are changed to use output_key instead of ‘SSDeepSimilarity’ if provided.