Exemple #1
0
def setup_watch_queue(sid, **kwargs):
    """
    Starts a watch queue to get live results
    
    Variables:
    sid      => Submission ID
    
    Arguments: (optional)
    suffix    => suffix to be appended to the queue name
    
    Data Block:
    None
    
    Result example:
    {"wq_id": "c7668cfa-...-c4132285142e"} #ID of the watch queue
    """
    data = STORAGE.get_submission(sid)
    user = kwargs['user']

    if user and data and Classification.is_accessible(user['classification'],
                                                      data['classification']):
        watch_queue = reply_queue_name(request.args.get('suffix', "WQ"))
        SubmissionWrapper.watch(sid, watch_queue)
        return make_api_response({"wq_id": watch_queue})
    else:
        return make_api_response(
            "", "You are not allowed to access this submissions.", 403)
Exemple #2
0
def delete_submission(sid, **kwargs):
    """
    INCOMPLETE
    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.get_submission(sid)
    
    if submission and user \
            and Classification.is_accessible(user['classification'], submission['classification']) \
            and (submission['submission']['submitter'] == user['uname'] or user['is_admin']):
        with forge.get_filestore() as f_transport:
            STORAGE.delete_submission_tree(sid, transport=f_transport)
        STORAGE.commit_index('submission')
        return make_api_response({"success": True})
    else:
        return make_api_response("", "Your are not allowed to delete this submission.", 403)
Exemple #3
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.get_submission(sid)
    user = kwargs['user']

    if user and data and Classification.is_accessible(user['classification'],
                                                      data['classification']):
        return make_api_response(DispatchClient.get_outstanding_services(sid))
    else:
        return make_api_response(
            {}, "You are not allowed to access this submissions.", 403)
Exemple #4
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", "SRL"], ...],    # Each file = List of name/srl
     "errors": [],              # List of error keys (SRL.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
       "ignore_tag": false },     # Send all files to all service?
     "results": [],             # List of Results keys (SRL.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.get_submission(sid)
    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)
Exemple #5
0
def resubmit_submission_for_analysis(sid, *args, **kwargs):
    """
    Resubmit a submission for analysis with the exact same parameters as before

    Variables:
    sid         => Submission ID to re-submit

    Arguments:
    None

    Data Block:
    None

    Result example:
    {
     "submission":{},       # Submission Block
     "request": {},         # Request Block
     "times": {},           # Timing Block
     "state": "submitted",  # Submission state
     "services": {},        # Service selection Block
     "fileinfo": {}         # File information Block
    }
    """
    user = kwargs['user']
    submission = STORAGE.get_submission(sid)

    if submission:
        if not Classification.is_accessible(user['classification'], submission['classification']):
            return make_api_response("", "You are not allowed to re-submit a submission that you don't have access to",
                                     403)

        task = {k: v for k, v in submission['submission'].iteritems() if k not in STRIP_KW}
        task.update({k: v for k, v in submission['services'].iteritems() if k not in STRIP_KW})
        task['classification'] = submission['classification']
    else:
        return make_api_response({}, "Submission %s does not exists." % sid, status_code=404)

    task['submitter'] = user['uname']
    if 'priority' not in task:
        task['priority'] = 500

    names = []
    for name, _ in submission["files"]:
        names.append(name)

    task['description'] = "Resubmit %s for analysis" % ", ".join(names)

    with forge.get_filestore() as f_transport:
        return make_api_response(SubmissionWrapper.submit_multi(STORAGE, f_transport, submission["files"], **task))
Exemple #6
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: 
    None
    
    Data Block:
    None

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

    Result example:
    -- THE BUNDLE FILE BINARY --
    """
    user = kwargs['user']
    submission = STORAGE.get_submission(sid)

    if user and submission and Classification.is_accessible(
            user['classification'], submission['classification']):
        temp_target_file = None
        try:
            temp_target_file = bundle_create(sid, working_dir=WORKING_DIR)
            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, snf.message),
                404)
        except BundlingException as be:
            return make_api_response(
                "", "An error occured while bundling submission %s. [%s]" %
                (sid, be.message), 404)
        finally:
            try:
                if temp_target_file:
                    os.remove(temp_target_file)
            except:
                pass
    else:
        return make_api_response(
            "", "You are not allowed create a bundle for this submission...",
            403)
Exemple #7
0
def is_submission_completed(sid, **kwargs):
    """
    Check if a submission is completed
    
    Variables:
    sid         =>  Submission ID to lookup
    
    Arguments: 
    None 
    
    Data Block:
    None
    
    Result example:
    True/False
    """
    data = STORAGE.get_submission(sid)
    if data is None:
        return make_api_response("", "Submission ID %s does not exists." % sid, 404)

    return make_api_response(data.get("state", "submitted") == "completed")
Exemple #8
0
def get_summary(sid, **kwargs):
    """
    Retrieve the executive summary of a given submission ID. This
    is a MAP of tags to SRL combined with a list of generated Tags.
    
    Variables:
    sid         => Submission ID to get the summary for
    
    Arguments: 
    None
    
    Data Block:
    None
    
    Result example:
    {"map": {                # Map of TAGS to SRL
       "TYPE__VAL": [          # Type and value of the tags
         "SRL"                   # List of related SRLs
         ...],
       "SRL": [                # SRL
         "TYPE__VAL"             # List of related type/value
         ...], ... } 
     "tags": {               # Dictionary of tags        
       "TYPE": {               # Type of tag
         "VALUE": {              # Value of the tag
           "usage": "",            # Usage
           "classification": ""    # Classification
           }, ...
         }, ...
    }
    """
    user = kwargs['user']
    data = STORAGE.get_submission(sid)
    if data is None:
        return make_api_response("", "Submission ID %s does not exists." % sid, 404)
    
    if user and Classification.is_accessible(user['classification'], data['classification']):
        return make_api_response(STORAGE.create_summary(data, user))
    else:
        return make_api_response("", "You are not allowed to view the data of this submission", 403)
Exemple #9
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/v3/submission/tree/12345678-1234-1234-1234-1234567890AB/
    
    Result example:
    {                                # Dictionary of file blocks
     "1f...11": {                    # File SRL (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.get_submission(sid)
    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']):
        output = STORAGE.create_file_tree(data)
        return make_api_response(output)
    else: 
        return make_api_response("", "You are not allowed to view the data of this submission", 403)
Exemple #10
0
def resubmit_for_dynamic(srl, *args, **kwargs): 
    """
    Resubmit a file for dynamic analysis
    
    Variables:
    srl         => Resource locator (SHA256)
    
    Arguments (Optional): 
    copy_sid    => Mimic the attributes of this SID.
    name        => Name of the file for the submission
    
    Data Block:
    None
    
    Result example:
    {
     "submission":{},       # Submission Block
     "request": {},         # Request Block
     "times": {},           # Timing Block
     "state": "submitted",  # Submission state
     "services": {},        # Service selection Block
     "fileinfo": {}         # File information Block
     }
    """
    user = kwargs['user']
    copy_sid = request.args.get('copy_sid', None)
    name = request.args.get('name', srl)
    
    if copy_sid:
        submission = STORAGE.get_submission(copy_sid)
    else:
        submission = None
        
    if submission:
        if not Classification.is_accessible(user['classification'], submission['classification']):
            return make_api_response("", "You are not allowed to re-submit a submission that you don't have access to",
                                     403)
            
        task = {k: v for k, v in submission['submission'].iteritems() if k not in STRIP_KW}
        task.update({k: v for k, v in submission['services'].iteritems() if k not in STRIP_KW})
        task['classification'] = submission['classification']
        
    else:
        params = STORAGE.get_user_options(user['uname'])
        task = {k: v for k, v in params.iteritems() if k not in STRIP_KW}
        task['selected'] = params["services"]
        task['classification'] = params['classification']

    task['sha256'] = srl
    with forge.get_filestore() as f_transport:
        if not f_transport.exists(srl):
            return make_api_response({}, "File %s cannot be found on the server therefore it cannot be resubmitted."
                                         % srl, status_code=404)

        task['path'] = name
        task['submitter'] = user['uname']
        if 'priority' not in task:
            task['priority'] = 500
        task['description'] = "Resubmit %s for Dynamic Analysis" % name
        if "Dynamic Analysis" not in task['selected']:
            task['selected'].append("Dynamic Analysis")

        submit_result = SubmissionWrapper.submit(f_transport, STORAGE, **task)

    return make_api_response(submit_result)
Exemple #11
0
def get_file_submission_results(sid, srl, **kwargs):
    """
    Get the all the results and errors of a specific file
    for a specific Submission ID
    
    Variables:
    sid         => Submission ID to get the result for
    srl         => Resource locator to get the result for
    
    Arguments (POST only): 
    extra_result_keys   =>  List of extra result keys to get
    extra_error_keys    =>  List of extra error keys to get
    
    Data Block:
    None
    
    Result example:
    {"errors": [],    # List of error blocks 
     "file_info": {}, # File information block (md5, ...)
     "results": [],   # List of result blocks
     "tags": [] }     # List of generated tags
    """
    user = kwargs['user']
    
    # Check if submission exist
    data = STORAGE.get_submission(sid)
    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']):
        # Prepare output
        output = {"file_info": {}, "results": [], "tags": [], "errors": []}
        
        # Extra keys - This is a live mode optimisation
        res_keys = data.get("results", [])
        err_keys = data.get("errors", [])
            
        if request.method == "POST" and request.json is not None and data['state'] != "completed":
            extra_rkeys = request.json.get("extra_result_keys", [])
            extra_ekeys = request.json.get("extra_error_keys", [])
        
            # Load keys 
            res_keys.extend(extra_rkeys)
            err_keys.extend(extra_ekeys)
            
        res_keys = list(set(res_keys))
        err_keys = list(set(err_keys))
    
        # Get File, results and errors
        temp_file = STORAGE.get_file(srl)
        if not Classification.is_accessible(user['classification'], temp_file['classification']):
            return make_api_response("", "You are not allowed to view the data of this file", 403)
        output['file_info'] = temp_file
        
        temp_results = STORAGE.get_results(set([x for x in res_keys if x.startswith(srl)]))
        results = []
        for r in temp_results:
            r = format_result(user['classification'], r, temp_file['classification'])
            if r:
                results.append(r)
        output['results'] = results 

        output['errors'] = STORAGE.get_errors(set([x for x in err_keys if x.startswith(srl)]))
        output['metadata'] = STORAGE.get_file_submission_meta(srl, user["access_control"])
        
        # Generate tag list
        temp = {}
        for res in output['results']:
            try:
                if res.has_key('result'):
                    if res['result'].has_key('tags'):
                        temp.update({"__".join([v["type"], v['value']]): v for v in res['result']['tags']})
            except:
                pass
        
        output["tags"] = temp.values()
        
        return make_api_response(output)
    else:
        return make_api_response("", "You are not allowed to view the data of this submission", 403)
Exemple #12
0
def get_full_results(sid, **kwargs):
    """
    Get the full results for a given Submission ID. The difference
    between this and the get results API is that this one gets the
    actual values of the result and error keys instead of listing 
    the keys.
    
    Variables:
    sid         => Submission ID to get the full results for
    
    Arguments: 
    None
    
    Data Block:
    None
    
    Result example:
    {"classification": "UNRESTRICTIED"  # Access control for the submission
     "error_count": 0,                  # Number of errors in this submission
     "errors": [],                      # List of error blocks (see Get Service Error)
     "file_count": 4,                   # Number of files in this submission
     "files": [                         # List of submitted files
       ["FNAME", "SRL"], ...],              # Each file = List of name/srl
     "file_infos": {                    # Dictionary of fil info blocks
       "234...235": <<FILE_INFO>>,          # File in block
       ...},                                # Keyed by file's SRL
     "file_tree": {                     # File tree of the submission
       "333...7a3": {                       # File tree item
        "children": {},                         # Recursive children of file tree item
        "name": ["file.exe",...]                # List of possible names for the file
        "score": 0                              # Score of the file
       },, ...},                            # Keyed by file's SRL
     "missing_error_keys": [],          # Errors that could not be fetched from the datastore
     "missing_result_keys": [],         # Results that could not be fetched from the datastore
     "results": [],                     # List of Results Blocks (see Get Service Result)
     "services": {                      # Service Block
       "selected": ["mcafee"],              # List of selected services
       "params": {},                        # Service specific parameters
       "excluded": []                       # List of excluded services
       },
     "state": "completed",              # State of the submission
     "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
       "ignore_tag": false },               # Send all files to all service?
     "times": {                         # Timing block
       "completed": "2014-...",             # Completed time
       "submitted": "2014-..."              # Submitted time
       }
    }
    """
    max_retry = 10

    def get_results(keys):
        out = {}
        res = {}
        retry = 0
        while keys and retry < max_retry:
            if retry:
                time.sleep(2 ** (retry - 7))
            res.update(STORAGE.get_results_dict(keys))
            keys = [x for x in keys if x not in res]
            retry += 1

        results = {}
        for k, v in res.iteritems():
            file_info = data['file_infos'].get(k[:64], None)
            if file_info:
                v = format_result(user['classification'], v, file_info['classification'])
                if v:
                    results[k] = v

        out["results"] = results
        out["missing_result_keys"] = keys

        return out

    def get_errors(keys):
        out = {}
        err = {}
        retry = 0
        while keys and retry < max_retry:
            if retry:
                time.sleep(2 ** (retry - 7))
            err.update(STORAGE.get_errors_dict(keys))
            keys = [x for x in err_keys if x not in err]
            retry += 1

        out["errors"] = err
        out["missing_error_keys"] = keys

        return out

    def get_file_infos(keys):
        infos = {}
        retry = 0
        while keys and retry < max_retry:
            if retry:
                time.sleep(2 ** (retry - 7))
            infos.update(STORAGE.get_files_dict(keys))
            keys = [x for x in keys if x not in infos]
            retry += 1

        return infos

    def recursive_flatten_tree(tree):
        srls = []

        for key, val in tree.iteritems():
            srls.extend(recursive_flatten_tree(val.get('children', {})))
            if key not in srls:
                srls.append(key)

        return list(set(srls))

    user = kwargs['user']
    data = STORAGE.get_submission(sid)
    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']):
        res_keys = data.get("results", [])
        err_keys = data.get("errors", [])

        data['file_tree'] = STORAGE.create_file_tree(data)
        data['file_infos'] = get_file_infos(recursive_flatten_tree(data['file_tree']))
        data.update(get_results(res_keys))
        data.update(get_errors(err_keys))

        return make_api_response(data)
    else:
        return make_api_response("", "You are not allowed to view the data of this submission", 403)