Exemplo n.º 1
0
def format_result(user_classification,
                  r,
                  min_classification,
                  build_hierarchy=False):
    if not CLASSIFICATION.is_accessible(user_classification,
                                        min_classification):
        return None

    # Drop sections user does not have access and set others to at least min classification
    max_classification, r['result']['sections'] = filter_sections(
        r['result']['sections'], user_classification, min_classification)

    # Drop supplementary and extracted files that the user does not have access to
    for ftype in ['supplementary', 'extracted']:
        r['response'][ftype] = [
            x for x in r['response'][ftype] if CLASSIFICATION.is_accessible(
                user_classification, x['classification'])
        ]

    # Set result classification to at least min but no more then viewable result classification
    r['classification'] = CLASSIFICATION.max_classification(
        max_classification, min_classification)

    if build_hierarchy:
        try:
            section_hierarchy, _ = build_heirarchy_rec(r['result']['sections'])
            r['section_hierarchy'] = section_hierarchy['children']
        except InvalidSectionList:
            LOGGER.warning(
                f"Could not generate section hierarchy for {r['response']['service_name']} "
                f"service. Will use old display method.")

    return r
Exemplo n.º 2
0
def setup_watch_queue(sid, **kwargs):
    """
    Starts a watch queue to get live results

    Variables:
    sid      => Submission ID

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"wq_id": "D-c7668cfa-...-c4132285142e-WQ"} #ID of the watch queue
    """
    data = STORAGE.submission.get(sid, as_obj=False)
    user = kwargs['user']

    if user and data and Classification.is_accessible(user['classification'], data['classification']):
        wq_id = DispatchClient(datastore=STORAGE).setup_watch_queue(sid)
        if wq_id:
            return make_api_response({"wq_id": wq_id})
        return make_api_response("", "No dispatchers are processing this submission.", 404)
    else:
        return make_api_response("", "You are not allowed to access this submissions.", 403)
Exemplo n.º 3
0
def get_alert(alert_id, **kwargs):
    """
    Get the alert details for a given alert key

    Variables:
    alert_id         => ID of the alert to get the details for

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/alert/1234567890/

    Result example:
    {
        KEY: VALUE,   # All fields of an alert in key/value pair
    }
    """
    user = kwargs['user']
    data = STORAGE.alert.get(alert_id, as_obj=False)

    if not data:
        return make_api_response("", "This alert does not exists...", 404)

    if user and Classification.is_accessible(user['classification'], data['classification']):
        return make_api_response(data)
    else:
        return make_api_response("", "You are not allowed to see this alert...", 403)
Exemplo n.º 4
0
def get_workflow(workflow_id, **kwargs):
    """
    Load the user account information.

    Variables:
    workflow_id       => ID of the workflow

    Arguments:
    None

    Data Block:
    None

    Result example:
    {
     "name": "Workflow name",    # Name of the workflow
     "classification": "",       # Max classification for workflow
     "label": ['label1'],        # Labels for the workflow
     "priority": "LOW",          # Priority of the workflow
     "status": "MALICIOUS",      # Status of the workflow
     "query": "*:*"              # Query to match the data
    }
    """
    wf = STORAGE.workflow.get(workflow_id, as_obj=False)
    if wf:
        if CLASSIFICATION.is_accessible(kwargs['user']['classification'], wf['classification']):
            return make_api_response(wf)
        else:
            return make_api_response({},
                                     err="You're not allowed to view workflow ID: %s" % workflow_id,
                                     status_code=403)
    else:
        return make_api_response({},
                                 err="Workflow ID %s does not exist" % workflow_id,
                                 status_code=404)
Exemplo n.º 5
0
def request_replay(index, doc_id, **kwargs):
    """
    Request an alert or a submission to be transfered to another system

    Variables:
    index         =>    Type of document to be transfered (alert or submission)
    doc_id        =>    ID of the document to transfer

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"success": true}
    """
    user = kwargs['user']

    if index not in ['alert', 'submission']:
        return make_api_response(
            "", f"{index.upper()} is not a valid index for this API.", 400)

    index_ds = STORAGE.get_collection(index)
    doc = index_ds.get_if_exists(doc_id, as_obj=False)
    if not doc or not Classification.is_accessible(user['classification'],
                                                   doc['classification']):
        return make_api_response(
            "",
            f"You are not allowed to modify the {index} with the following ID: {doc_id}",
            403)

    operations = [(index_ds.UPDATE_SET, 'metadata.replay', REPLAY_REQUESTED)]
    return make_api_response({'success': index_ds.update(doc_id, operations)})
def get_heuristic(heuristic_id, **kwargs):
    """
    Get a specific heuristic's detail from the system

    Variables:
    heuristic_id  => ID of the heuristic

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"id": "AL_HEUR_001",               # Heuristics ID
     "filetype": ".*",                  # Target file type
     "name": "HEURISTICS_NAME",         # Heuristics name
     "description": ""}                 # Heuristics description
    """
    user = kwargs['user']

    h = STORAGE.heuristic.get(heuristic_id, as_obj=False)

    if not h:
        return make_api_response("", "Heuristic not found", 404)

    if user and Classification.is_accessible(user['classification'], h['classification']):
        # Always refresh stats when someone get a heuristic
        h.update({'stats': STORAGE.get_stat_for_heuristic(heuristic_id)})

        return make_api_response(h)
    else:
        return make_api_response("", "You are not allowed to see this heuristic...", 403)
def delete_submission(sid, **kwargs):
    """
    Delete a submission as well as all related
    files, results and errors

    Variables:
    sid         => Submission ID to be deleted

    Arguments:
    None

    Data Block:
    None

    Result example:
    {success: true}
    """
    user = kwargs['user']
    submission = STORAGE.submission.get(sid, as_obj=False)

    if not submission:
        return make_api_response("", f"There are not submission with sid: {sid}", 404)

    if Classification.is_accessible(user['classification'], submission['classification']) \
            and (submission['params']['submitter'] == user['uname'] or 'admin' in user['type']):
        STORAGE.delete_submission_tree_bulk(sid, Classification, transport=FILESTORE)
        STORAGE.submission.commit()
        return make_api_response({"success": True})
    else:
        return make_api_response("", "Your are not allowed to delete this submission.", 403)
Exemplo n.º 8
0
def create_bundle(sid, **kwargs):
    """
    Creates a bundle containing the submission results and the associated files

    Variables:
    sid         => ID of the submission to create the bundle for

    Arguments:
    use_alert   => The ID provided is from an alert and we will use it to create the bundle

    Data Block:
    None

    API call example:
    /api/v4/bundle/create/234f334-...-31232/

    Result example:
    -- THE BUNDLE FILE BINARY --
    """
    user = kwargs['user']
    use_alert = request.args.get('use_alert', 'false').lower() in ['true', '']
    if use_alert:
        data = STORAGE.alert.get(sid, as_obj=False)
    else:
        data = STORAGE.submission.get(sid, as_obj=False)

    if user and data and Classification.is_accessible(user['classification'],
                                                      data['classification']):
        temp_target_file = None
        try:
            temp_target_file = bundle_create(sid,
                                             working_dir=BUNDLING_DIR,
                                             use_alert=use_alert)
            f_size = os.path.getsize(temp_target_file)
            return stream_file_response(open(temp_target_file, 'rb'),
                                        "%s.al_bundle" % sid, f_size)
        except SubmissionNotFound as snf:
            return make_api_response(
                "", "Submission %s does not exist. [%s]" % (sid, str(snf)),
                404)
        except BundlingException as be:
            return make_api_response(
                "", "An error occured while bundling submission %s. [%s]" %
                (sid, str(be)), 404)
        finally:
            try:
                if temp_target_file:
                    os.remove(temp_target_file)
            except Exception:
                pass
    else:
        return make_api_response(
            "",
            f"You are not allowed create a bundle for this {'alert' if use_alert else 'submission'}...",
            403)
Exemplo n.º 9
0
def get_file_children(sha256, **kwargs):
    """
    Get the list of children files for a given file

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/file/children/123456...654321/

    Result example:
    [                           # List of children
     {"name": "NAME OF FILE",       # Name of the children
      "sha256": "123..DEF"},           # sha256 of the children
    ]
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if file_obj:
        if user and Classification.is_accessible(user['classification'],
                                                 file_obj['classification']):
            output = []
            response = STORAGE.result.grouped_search(
                "response.service_name",
                query=f"id:{sha256}* AND response.extracted:*",
                fl="*",
                rows=100,
                sort="created desc",
                access_control=user['access_control'],
                as_obj=False)

            processed_srl = []
            for r in response['items']:
                for extracted in r['items'][0]['response']['extracted']:
                    if extracted['sha256'] not in processed_srl:
                        processed_srl.append(extracted['sha256'])
                        output.append({
                            'sha256': extracted['sha256'],
                            'name': extracted['name']
                        })

            return make_api_response(output)
        else:
            return make_api_response({},
                                     "You are not allowed to view this file.",
                                     403)
    else:
        return make_api_response({}, "This file does not exists.", 404)
Exemplo n.º 10
0
def get_file_score(sha256, **kwargs):
    """
    Get the score of the latest service run for a given file.

    Variables:
    sha256         => A resource locator for the file (SHA256)

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/file/score/123456...654321/

    Result example:
    {"file_info": {},            # File info Block
     "result_keys": [<keys>]     # List of keys used to compute the score
     "score": 0}                 # Latest score for the file
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if not file_obj:
        return make_api_response([], "This file does not exists", 404)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        score = 0
        keys = []
        res = STORAGE.result.grouped_search(
            "response.service_name",
            f"id:{sha256}*",
            fl="result.score,id",
            sort="created desc",
            access_control=user["access_control"],
            rows=100,
            as_obj=False)
        for s in res['items']:
            for d in s['items']:
                score += d['result']['score']
                keys.append(d["id"])

        return make_api_response({
            "file_info": file_obj,
            "score": score,
            "result_keys": keys
        })
    else:
        return make_api_response([], "You are not allowed to view this file",
                                 403)
Exemplo n.º 11
0
def get_file_hex(sha256, **kwargs):
    """
    Returns the file hex representation

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    bytes_only   => Only return bytes with no formatting
    length       => Number of bytes per lines

    Data Block:
    None

    API call example:
    /api/v4/file/hex/123456...654321/

    Result example:
    <THE FILE HEX REPRESENTATION>
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    bytes_only = request.args.get('bytes_only',
                                  'false').lower() in ['true', '']
    length = int(request.args.get('length', '16'))

    if not file_obj:
        return make_api_response({}, "The file was not found in the system.",
                                 404)

    if file_obj['size'] > API_MAX_SIZE:
        return make_api_response(
            {}, "This file is too big to be seen through this API.", 403)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        data = FILESTORE.get(sha256)

        if not data:
            return make_api_response({},
                                     "This file was not found in the system.",
                                     404)

        if bytes_only:
            return make_api_response(dump(data).decode())
        else:
            return make_api_response(hexdump(data, length=length))
    else:
        return make_api_response({}, "You are not allowed to view this file.",
                                 403)
Exemplo n.º 12
0
def get_file_strings(sha256, **kwargs):
    """
    Return all strings in a given file

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    len       => Minimum length for a string

    Data Block:
    None

    Result example:
    <THE LIST OF STRINGS>
    """
    user = kwargs['user']
    hlen = request.args.get('len', "6")
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if file_obj['size'] > API_MAX_SIZE:
        return make_api_response(
            {}, "This file is too big to be seen through this API.", 403)

    if not file_obj:
        return make_api_response({}, "The file was not found in the system.",
                                 404)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        data = FILESTORE.get(sha256)

        if not data:
            return make_api_response({},
                                     "This file was not found in the system.",
                                     404)

        # Ascii strings (we use decode with replace on to create delimiters)
        pattern = "[\x1f-\x7e]{%s,}" % hlen
        string_list = re.findall(pattern, data.decode("ascii",
                                                      errors="replace"))

        # UTF-16 strings
        string_list += re.findall(pattern,
                                  data.decode("utf-16", errors="replace"))

        return make_api_response("\n".join(string_list))
    else:
        return make_api_response({}, "You are not allowed to view this file.",
                                 403)
Exemplo n.º 13
0
def get_submission(sid, **kwargs):
    """
    Get the submission details for a given Submission ID

    Variables:
    sid         => Submission ID to get the details for

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"files": [                 # List of source files
       ["FNAME", "sha256"], ...],    # Each file = List of name/sha256
     "errors": [],              # List of error keys (sha256.ServiceName)
     "submission": {            # Submission Block
       "profile": true,           # Should keep stats about execution?
       "description": "",         # Submission description
       "ttl": 30,                 # Submission days to live
       "ignore_filtering": false, # Ignore filtering services?
       "priority": 1000,          # Submission priority, higher = faster
       "ignore_cache": true,      # Force reprocess even is result exist?
       "groups": ["group", ...],  # List of groups with access
       "sid": "ab9...956",        # Submission ID
       "submitter": "user",       # Uname of the submitter
       "max_score": 1422, },      # Score of highest scoring file
     "results": [],             # List of Results keys (sha256.ServiceName.Version.Config)
     "times": {                 # Timing block
       "completed": "2014-...",   # Completed time
       "submitted": "2014-..."    # Submitted time
       },
     "state": "completed",      # State of the submission
     "services": {              # Service Block
       "selected": ["mcafee"],    # List of selected services
       "params": {},              # Service specific parameters
       "excluded": []             # List of excluded services
       }
    }
    """
    user = kwargs['user']
    data = STORAGE.submission.get(sid, as_obj=False)
    if data is None:
        return make_api_response("", "Submission ID %s does not exists." % sid, 404)

    if data and user and Classification.is_accessible(user['classification'], data['classification']):
        return make_api_response(data)
    else:
        return make_api_response("", "You are not allowed to view the data of this submission", 403)
Exemplo n.º 14
0
def set_verdict(alert_id, verdict, **kwargs):
    """
    Set the verdict of an alert based on its ID.

    Variables:
    submission_id   ->   ID of the alert to give a verdict to
    verdict         ->   verdict that the user think the alert is: malicious or non_malicious

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"success": True}   # Has the verdict been set or not
    """
    reverse_verdict = {
        'malicious': 'non_malicious',
        'non_malicious': 'malicious'
    }

    user = kwargs['user']

    if verdict not in ['malicious', 'non_malicious']:
        return make_api_response({"success": False}, f"'{verdict}' is not a valid verdict.", 400)

    document = STORAGE.alert.get(alert_id, as_obj=False)

    if not document:
        return make_api_response({"success": False}, f"There are no alert with id: {alert_id}", 404)

    if not Classification.is_accessible(user['classification'], document['classification']):
        return make_api_response({"success": False}, "You are not allowed to give verdict on alert with "
                                                     f"ID: {alert_id}", 403)

    resp = STORAGE.alert.update_by_query(f"sid:{document['sid']}", [
        ('REMOVE', f'verdict.{verdict}', user['uname']),
        ('APPEND', f'verdict.{verdict}', user['uname']),
        ('REMOVE', f'verdict.{reverse_verdict[verdict]}', user['uname'])
    ])

    STORAGE.submission.update(document['sid'], [
        ('REMOVE', f'verdict.{verdict}', user['uname']),
        ('APPEND', f'verdict.{verdict}', user['uname']),
        ('REMOVE', f'verdict.{reverse_verdict[verdict]}', user['uname'])
    ])

    return make_api_response({"success": resp != 0})
Exemplo n.º 15
0
def get_file_information(sha256, **kwargs):
    """
    Get information about the file like:
        Hashes, size, frequency count, etc...

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/file/info/123456...654321/

    Result example:
    {                                           # File information block
     "ascii": "PK..",                               # First 64 bytes as ASCII
     "classification": "UNRESTRICTED",              # Access control for the file
     "entropy": 7.99,                               # File's entropy
     "hex": "504b...c0b2",                          # First 64 bytes as hex
     "magic": "Zip archive data",                   # File's identification description (from magic)
     "md5": "8f31...a048",                          # File's MD5 hash
     "mime": "application/zip",                     # Mimetype of the file (from magic)
     "seen_count": 7,                               # Number of time we've seen this file
     "seen_first": "2015-03-04T21:59:13.204861Z",   # Time at which we first seen this file
     "seen_last": "2015-03-10T19:42:04.587233Z",    # Last time we've seen the file
     "sha256": "e021...4de2",                       # File's sha256 hash
     "sha1": "354f...fdab",                         # File's sha1 hash
     "size": 3417,                                  # Size of the file
     "ssdeep": "4:Smm...OHY+",                      # File's SSDEEP hash
     "tag": "archive/zip"                           # Type of file that we identified
    }
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if file_obj:
        if user and Classification.is_accessible(user['classification'],
                                                 file_obj['classification']):
            return make_api_response(file_obj)
        else:
            return make_api_response({},
                                     "You are not allowed to view this file.",
                                     403)
    else:
        return make_api_response({}, "This file does not exists.", 404)
Exemplo n.º 16
0
def get_file_results_for_service(sha256, service, **kwargs):
    """
    Get the all the file results of a specific file and a specific query.

    Variables:
    sha256         => A resource locator for the file (SHA256)

    Arguments:
    all         => if all argument is present, it will return all versions
                    NOTE: Max to 100 results...

    Data Block:
    None

    API call example:
    /api/v4/file/result/123456...654321/service_name/

    Result example:
    {"file_info": {},            # File info Block
     "results": {}}              # Full result list for the service
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if not file_obj:
        return make_api_response([], "This file does not exists", 404)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        res = STORAGE.result.search(f"id:{sha256}.{service}*",
                                    sort="created desc",
                                    fl="*",
                                    rows=100 if "all" in request.args else 1,
                                    access_control=user["access_control"],
                                    as_obj=False,
                                    use_archive=True)

        results = []
        for r in res['items']:
            result = format_result(user['classification'], r,
                                   file_obj['classification'])
            if result:
                results.append(result)

        return make_api_response({"file_info": file_obj, "results": results})
    else:
        return make_api_response([], "You are not allowed to view this file",
                                 403)
Exemplo n.º 17
0
def filter_sections(sections, user_classification, min_classification):
    max_classification = min_classification

    # Filtering section you do not have access to
    temp_sections = [
        s for s in sections if CLASSIFICATION.is_accessible(
            user_classification, s['classification'])
    ]
    final_sections = []
    for section in temp_sections:
        # TODO: Depth analysis should be done before returning sections
        try:
            # Recalculation max classification using the currently accessible sections
            section['classification'] = CLASSIFICATION.max_classification(
                section['classification'], min_classification)
            max_classification = CLASSIFICATION.max_classification(
                section['classification'], max_classification)
        except InvalidClassification:
            continue

        if section['body_format'] in [
                "GRAPH_DATA", "URL", "JSON", "KEY_VALUE"
        ] and isinstance(section['body'], str):
            # Loading JSON formatted sections
            try:
                section['body'] = json.loads(section['body'])
            except ValueError:
                pass

        # Changing tags to a list
        section['tags'] = tag_dict_to_list(section['tags'])
        final_sections.append(section)

    # Telling the user a section was hidden
    if len(sections) != len(final_sections):
        hidden_section = dict(
            body=
            "One of the sections produced by the service has been removed because you do not have enough "
            "priviledges to see its results. \n\nContact system administrators for more information.",
            title_text="WARNING: Service sections have been sanitized",
            depth=0,
            classification=CLASSIFICATION.UNRESTRICTED,
            tags={},
            heuristic=None,
            body_format="TEXT")
        final_sections.insert(0, hidden_section)

    return max_classification, final_sections
Exemplo n.º 18
0
def get_file_image_datastream(sha256, **kwargs):
    """
    Returns the image file as a datastream

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/file/image/123456...654321/

    Result example:
    data:image/png;base64,...
    """
    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if not file_obj:
        return make_api_response({}, "The file was not found in the system.",
                                 404)

    if not file_obj.get('is_section_image',
                        False) or not file_obj['type'].startswith("image/"):
        return make_api_response(
            {}, "This file is not allowed to be downloaded as a datastream.",
            403)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        data = FILESTORE.get(sha256)

        if not data:
            return make_api_response({},
                                     "This file was not found in the system.",
                                     404)

        return make_api_response(
            f"data:{file_obj['type']};base64,{base64.b64encode(data).decode()}"
        )
    else:
        return make_api_response({}, "You are not allowed to view this file.",
                                 403)
Exemplo n.º 19
0
def get_user_favorites(username, **kwargs):
    """
    Loads the user's favorites.

    Variables:
    username    => Name of the user you want to get the avatar for

    Arguments:
    None

    Data Block:
    None

    Result example:
    {                   # Dictionary of
     "<name_of_query>":   # Named queries
        "*:*",              # The actual query to run
     ...
    }
    """
    user = kwargs['user']

    favorites = {
        "alert": [],
        "search": [],
        "signature": [],
        "submission": [],
        "error": []
    }
    res_favorites = STORAGE.user_favorites.get(username, as_obj=False)

    if res_favorites:
        if username == "__global__" or username != user['uname']:
            for key in favorites.keys():
                for fav in res_favorites[key]:
                    if 'classification' in fav:
                        if CLASSIFICATION.is_accessible(
                                user['classification'], fav['classification']):
                            favorites[key].append(fav)
                    else:
                        favorites[key].append(fav)
        else:
            favorites.update(res_favorites)

    return make_api_response(favorites)
Exemplo n.º 20
0
def change_priority(alert_id, **kwargs):
    """
    Change the priority of a given alert

    Variables:
    alert_id      => ID of the alert to change the priority

    Arguments:
    "HIGH"        => New priority for the alert

    Data Block:
    None

    API call example:
    /api/v4/alert/priority/12345...67890/

    Result example:
    {"success": true}
    """
    user = kwargs['user']
    try:
        priority = request.json
        priority = priority.upper()
        if priority not in PRIORITIES:
            raise ValueError("Not in priorities")
    except ValueError:
        return make_api_response({"success": False}, err="Invalid priority received.", status_code=400)

    alert = STORAGE.alert.get(alert_id, as_obj=False)

    if not alert:
        return make_api_response({"success": False},
                                 err="Alert ID %s not found" % alert_id,
                                 status_code=404)

    if not Classification.is_accessible(user['classification'], alert['classification']):
        return make_api_response("", "You are not allowed to see this alert...", 403)

    if priority != alert.get('priority', None):
        return make_api_response({
            "success": STORAGE.alert.update(alert_id, [(STORAGE.alert.UPDATE_SET, 'priority', priority)])})
    else:
        return make_api_response({"success": True})
Exemplo n.º 21
0
def change_status(alert_id, **kwargs):
    """
    Change the status of a given alert

    Variables:
    alert_id       => ID of the alert to change the status

    Arguments:
    None

    Data Block:
    "MALICIOUS"      => New status for the alert

    API call example:
    /api/v4/alert/status/12345...67890/

    Result example:
    {"success": true}
    """
    user = kwargs['user']
    try:
        status = request.json
        status = status.upper()
        if status not in STATUSES:
            raise ValueError("Not in priorities")
    except ValueError:
        return make_api_response({"success": False}, err="Invalid status received.", status_code=400)

    alert = STORAGE.alert.get(alert_id, as_obj=False)

    if not alert:
        return make_api_response({"success": False},
                                 err="Alert ID %s not found" % alert_id,
                                 status_code=404)

    if not Classification.is_accessible(user['classification'], alert['classification']):
        return make_api_response("", "You are not allowed to see this alert...", 403)

    if status != alert.get('status', None):
        return make_api_response({
            "success": STORAGE.alert.update(alert_id, [(STORAGE.alert.UPDATE_SET, 'status', status)])})
    else:
        return make_api_response({"success": True})
Exemplo n.º 22
0
def add_labels(alert_id, **kwargs):
    """
    Add one or multiple labels to a given alert

    Variables:
    alert_id           => ID of the alert to add the label to

    Arguments:
    None

    Data Block:
    ["LBL1", "LBL2"]   => List of labels to add as comma separated string

    API call example:
    /api/v4/alert/label/12345...67890/

    Result example:
    {"success": true}
    """
    user = kwargs['user']
    try:
        labels = set(request.json)
    except ValueError:
        return make_api_response({"success": False}, err="Invalid list of labels received.", status_code=400)

    alert = STORAGE.alert.get(alert_id, as_obj=False)

    if not alert:
        return make_api_response({"success": False}, err="Alert ID %s not found" % alert_id, status_code=404)

    if not Classification.is_accessible(user['classification'], alert['classification']):
        return make_api_response("", "You are not allowed to see this alert...", 403)

    cur_label = set(alert.get('label', []))
    label_diff = labels.difference(labels.intersection(cur_label))
    if label_diff:
        return make_api_response({
            "success": STORAGE.alert.update(alert_id, [(STORAGE.alert.UPDATE_APPEND_IF_MISSING, 'label', lbl)
                                                       for lbl in label_diff])})
    else:
        return make_api_response({"success": True})
Exemplo n.º 23
0
def get_file_ascii(sha256, **kwargs):
    """
    Return the ascii values for a file where ascii chars are replaced by DOTs.

    Variables:
    sha256       => A resource locator for the file (sha256)

    Arguments:
    None

    Data Block:
    None

    Result example:
    <THE ASCII FILE>
    """

    user = kwargs['user']
    file_obj = STORAGE.file.get(sha256, as_obj=False)

    if file_obj['size'] > API_MAX_SIZE:
        return make_api_response(
            {}, "This file is too big to be seen through this API.", 403)

    if not file_obj:
        return make_api_response({}, "The file was not found in the system.",
                                 404)

    if user and Classification.is_accessible(user['classification'],
                                             file_obj['classification']):
        data = FILESTORE.get(sha256)

        if not data:
            return make_api_response({},
                                     "This file was not found in the system.",
                                     404)

        return make_api_response(data.translate(FILTER_ASCII).decode())
    else:
        return make_api_response({}, "You are not allowed to view this file.",
                                 403)
Exemplo n.º 24
0
def generate_ontology_file(results, user, updates={}, fnames={}):
    # Load ontology files
    sio = StringIO()
    for r in results:
        for supp in r.get('response', {}).get('supplementary', {}):
            if supp['name'].endswith('.ontology'):
                try:
                    ontology = json.loads(FILESTORE.get(supp['sha256']))
                    sha256 = ontology['header']['sha256']
                    c12n = ontology['header']['classification']
                    if sha256 == r['sha256'] and Classification.is_accessible(
                            user['classification'], c12n):
                        # Update the ontology with the live values
                        ontology['header'].update(updates)

                        # Set filenames if any
                        if sha256 in fnames:
                            ontology['header']['filenames'] = fnames[sha256]
                        elif 'filenames' in ontology['header']:
                            del ontology['header']['filenames']

                        # Make sure parent is not equal to current hash
                        if 'parent' in ontology['header'] and ontology[
                                'header']['parent'] == sha256:
                            del ontology['header']['parent']

                        sio.write(
                            json.dumps(
                                ontology, indent=None, separators=(',', ':')) +
                            '\n')
                except Exception as e:
                    LOGGER.warning(
                        f"An error occured while fetching ontology files: {str(e)}"
                    )

    # Flush and reset buffer
    sio.flush()

    return sio
Exemplo n.º 25
0
def take_ownership(alert_id, **kwargs):
    """
    Take ownership of a given alert

    Variables:
    alert_id    => ID of the alert to send to take ownership

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/alert/ownership/12345...67890/

    Result example:
    {"success": true}
    """
    user = kwargs['user']

    alert = STORAGE.alert.get(alert_id, as_obj=False)

    if not alert:
        return make_api_response({"success": False},
                                 err="Alert ID %s not found" % alert_id,
                                 status_code=404)

    if not Classification.is_accessible(user['classification'], alert['classification']):
        return make_api_response({"success": False}, "You are not allowed to see this alert...", 403)

    current_owner = alert.get('owner', None)
    if current_owner is None:
        return make_api_response({
            "success": STORAGE.alert.update(alert_id, [(STORAGE.alert.UPDATE_SET, 'owner', user['uname'])])})
    else:
        return make_api_response({"success": False},
                                 err="Alert is already owned by %s" % current_owner,
                                 status_code=403)
Exemplo n.º 26
0
def get_file_tree(sid, **kwargs):
    """
    Get the file hierarchy of a given Submission ID. This is
    an N deep recursive process but is limited to the max depth
    set in the system settings.

    Variables:
    sid         => Submission ID to get the tree for

    Arguments:
    None

    Data Block:
    None

    API call example:
    /api/v4/submission/tree/12345678-1234-1234-1234-1234567890AB/

    Result example:
    {                                # Dictionary of file blocks
     "1f...11": {                    # File sha256 (sha256)
       "score": 923,                 # Score for the file
       "name": ["file.exe",...]      # List of possible names for the file
       "children": {...}             # Dictionary of children file blocks
       }, ...

    """
    user = kwargs['user']

    data = STORAGE.submission.get(sid, as_obj=False)
    if data is None:
        return make_api_response("", "Submission ID %s does not exists." % sid, 404)

    if data and user and Classification.is_accessible(user['classification'], data['classification']):
        return make_api_response(STORAGE.get_or_create_file_tree(data, config.submission.max_extraction_depth,
                                                                 cl_engine=Classification,
                                                                 user_classification=user['classification']))
    else:
        return make_api_response("", "You are not allowed to view the data of this submission", 403)
Exemplo n.º 27
0
def delete_signature(signature_id, **kwargs):
    """
    Delete a signature based of its ID

    Variables:
    signature_id    =>     Signature ID

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"success": True}  # Signature delete successful
    """
    user = kwargs['user']
    data = STORAGE.signature.get(signature_id, as_obj=False)
    if data:
        if not Classification.is_accessible(
                user['classification'],
                data.get('classification', Classification.UNRESTRICTED)):
            return make_api_response(
                "", "Your are not allowed to delete this signature.", 403)

        ret_val = STORAGE.signature.delete(signature_id)

        _reset_service_updates(data['type'])
        event_sender.send(
            data['type'], {
                'signature_id': signature_id,
                'signature_type': data['type'],
                'source': data['source'],
                'operation': Operation.Removed
            })
        return make_api_response({"success": ret_val})
    else:
        return make_api_response("", f"Signature not found. ({signature_id})",
                                 404)
Exemplo n.º 28
0
def get_signature(signature_id, **kwargs):
    """
    Get the detail of a signature based of its ID and revision

    Variables:
    signature_id    =>     Signature ID

    Arguments:
    None

    Data Block:
    None

    Result example:
    {}
    """
    user = kwargs['user']
    data = STORAGE.signature.get(signature_id, as_obj=False)

    if data:
        if not Classification.is_accessible(
                user['classification'],
                data.get('classification', Classification.UNRESTRICTED)):
            return make_api_response(
                "", "Your are not allowed to view this signature.", 403)

        # Always refresh stats when someone get a signature
        data.update({
            'stats':
            STORAGE.get_stat_for_signature(signature_id, data['source'],
                                           data['name'], data['type'])
        })

        return make_api_response(data)
    else:
        return make_api_response("", f"Signature not found. ({signature_id})",
                                 404)
Exemplo n.º 29
0
def filter_sections(sections, user_classification, min_classification):
    max_classification = min_classification

    # Filtering section you do not have access to
    temp_sections = [
        s for s in sections if CLASSIFICATION.is_accessible(
            user_classification, s['classification'])
    ]
    final_sections = []
    for section in temp_sections:
        try:
            # Recalculation max classification using the currently accessible sections
            section['classification'] = CLASSIFICATION.max_classification(
                section['classification'], min_classification)
            max_classification = CLASSIFICATION.max_classification(
                section['classification'], max_classification)
        except InvalidClassification:
            continue

        final_sections.append(fix_section_data(section))

    # Telling the user a section was hidden
    if len(sections) != len(final_sections):
        hidden_section = dict(
            body=
            "One of the sections produced by the service has been removed because you do not have enough "
            "priviledges to see its results. \n\nContact system administrators for more information.",
            title_text="WARNING: Service sections have been sanitized",
            depth=0,
            classification=CLASSIFICATION.UNRESTRICTED,
            tags=[],
            heuristic=None,
            body_format="TEXT")
        final_sections.insert(0, hidden_section)

    return max_classification, final_sections
Exemplo n.º 30
0
def outstanding_services(sid, **kwargs):
    """
    List outstanding services and the number of file each
    of them still have to process.

    Variables:
    sid      => Submission ID

    Arguments:
    None

    Data Block:
    None

    Result example:
    {"MY SERVICE": 1, ... } # Dictionnary of services and number of files
    """
    data = STORAGE.submission.get(sid, as_obj=False)
    user = kwargs['user']

    if user and data and Classification.is_accessible(user['classification'], data['classification']):
        return make_api_response(DispatchClient(datastore=STORAGE).outstanding_services(sid))
    else:
        return make_api_response({}, "You are not allowed to access this submissions.", 403)