Hybrid Analysis Deprecated

Deprecated. Use CrowdStrike Falcon Sandbox v2 instead.

Forensics & Malware Analysis · Hybrid Analysis (Deprecated)

Details

IDHybrid Analysis
ProviderCrowdStrike
CategoryForensics & Malware Analysis
From Version5.0.0
Supported ModulesAgentix

README

Deprecated. Use the CrowdStrike Falcon Sandbox v2 integration instead.

Supported File Types

The maximum file upload size is 100 MB.

  • PE (.exe, .scr, .pif, .dll, .com, .cpl, and so on)
  • Microsoft Word (.doc, .docx, .ppt, .pps, .pptx, .ppsx, .xls, .xlsx, .rtf, .pub)
  • PDF
  • APK
  • JAR executables
  • Windows Script Component (.sct)
  • Windows Shortcut (.lnk)
  • Windows Help (.chm)
  • HTML Application (.hta)
  • Windows Script File (*.wsf)
  • Javascript (.js)
  • Visual Basic (*.vbs, *.vbe)
  • Shockwave Flash (.swf)
  • Perl (.pl)
  • PowerShell (.ps1, .psd1, .psm1)
  • Scalable Vector Graphics (.svg)
  • Python scripts (.py)
  • Perl scripts (.pl)
  • Linux ELF executables
  • MIME RFC 822 (*.eml)
  • Outlook (*.msg files)

Configure the Hybrid Analysis Integration on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Hybrid Analysis.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • Server URI: for example, https://216.128.82
    • API Key: Cortex XSOAR creates an API key, do not populate this field.
    • Secret Key (applicable for v1)
    • Do not validate server certificate (insecure)
    • Use system proxy settings
  4. Click Test to validate the URLs and token.

Use Cases

  • Submit sample files for analysis.
  • Get result data of sample files.
  • Search the Hybrid Analysis database.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details.

  1. Scan a file hash: hybrid-analysis-scan
  2. Submit a sample file: hybrid-analysis-submit-sample
  3. Search Hybrid Analysis: hybrid-analysis-search
  4. Detonate a file: hybrid-analysis-detonate-file
  5. Get the status of a file submission: hybrid-analysis-get-report-status
  6. Submit a website or file URL for quick analysis: hybrid-analysis-quick-scan-url
  7. Submit a website or file URL for analysis: hybrid-analysis-submit-url
  8. Get a list of scanners: hybrid-analysis-list-scanners
  9. Get scan results: hybrid-analysis-quick-scan-url-results

1. Scan a file hash


Returns summary information for a given MD5, SHA1 or SHA256 hash, and all reports generated for any environment ID.

Base Command

hybrid-analysis-scan

Input
Argument Name Description Required
file The MD5, SHA1, or SHA256 hash of the file. Required
malicious_threat_levels Threat level values, which will determine if the file is malicious. Optional

 

Context Output
Path Type Description
File.SHA256 string SHA256 hash of the file.
File.SHA1 string SHA1 hash of the file.
File.MD5 string MD5 hash of the file.
File.environmentId string The environment ID of the file.
File.analysis_start_time string The start time of the file analysis.
File.submitname string The submission name of the file.
File.classification_tags string A list of classification tags of the file.
File.vxfamily string The family classification of the file.
File.total_network_connections string The total number of network connections of the file.
File.total_processes string The total processes count of the file.
File.total_signatures string The total signatures count of the file.
File.hosts string A list of hosts of the file.
File.isinteresting string Whether the server found the file interesting.
File.domains string A list of domains related to the file.
File.isurlanalysis string Whether the file was analyzed by a URL.
File.Malicious.Vendor string For malicious files, the vendor that made the decision.
File.Malicious.Description string For malicious files, the reason that the vendor made the decision.
DBotScore.Indicator string The indicator.
DBotScore.Type string The indicator type.
DBotScore.Vendor string The DBot score vendor.
DBotScore.Score number The DBot score.

 

Command Example
 !hybrid-analysis-scan file=bb3bed4a07c472ad7a51c19634e33ad2c9769a27fa750f096d9cca5b5b9e4616
Human Readable Output

2. Submit a file sample


Submits a file from the investigation to the analysis server. The minimum required authorization is "default".

Base Command

hybrid-analysis-submit-sample

Input
Argument Name Description Required
entryId The War Room entry ID of the sample file. Required
environmentID The environment ID to which to submit the file. Run the vx-get-environments command to get all environment IDs. Required

 

Context Output
Path Type Description
HybridAnalysis.Submit.JobID string JobID of the submission.
HybridAnalysis.Submit.SHA256 string The SHA256 hash of the submission.
HybridAnalysis.Submit.EnvironmentID string The environment ID of the submission.

 

Command Example
 !hybrid-analysis-submit-sample entryId=413@13 environmentID=100
Human Readable Output

 

3. Search Hybrid Analysis


Performs a search on the database using the Hybrid Analysis search syntax.

Base Command

hybrid-analysis-search

Input
Argument Name Description Required
query The query to run, in the Hybrid Analysis query syntax. For more information, see `/faq#advanced-search-options`. For example: url:google, host:95.181.53.78. Optional
filename The full file name, including the file extension. Optional
filetype Filetype e.g. docx Optional
filetype_desc A description of the file type, for example, PE32 executable. Optional
env_id The environment ID. Optional
country The ISO code of the country by which to filter results, for example: swe. Optional
verdict The verdict by which to filter results. Can be "1- whitelisted", "2- no verdict", "3- "no specific threat", "4- suspicious", or "5- malicious". Optional
av_detect The AV multi-scan range (0-100) by which to filter results, for example: "50-70". Optional
vx_family The AV family substring by which to filter results, for example: "nemucod". Optional
tag The hashtag by which to filter results, for example: "ransomware". Optional
port The port by which to filter results. Optional
host The host (IP address) by which to filter results. Optional
domain The domain by which to filter results. Optional
url The HTTP request substring by which to filter results. Optional
similar_to Similar samples, for example: . Optional
context Sample context, for example: . Optional
imp_hash The import hash. Optional
ssdeep The ssdeep hash. Optional
authentihash The authentication hash. Optional
min_malicious_scanners The number of scanners that report the file as malicious to determine whether the file is malicious. Default is "2". Optional

 

Context Output
Path Type Description
HybridAnalysis.Search.SHA256 string The SHA256 hash of the search result.
HybridAnalysis.Search.SHA1 string The SHA1 hash of the search result.
HybridAnalysis.Search.MD5 string The MD5 hash of the search result.
HybridAnalysis.Search.environmentId string The environment ID of the search result.
HybridAnalysis.Search.start_time date The start time of the search result.
HybridAnalysis.Search.threatscore string The threat score of the search result, by server.
HybridAnalysis.Search.verdict string The verdict of the search result.
HybridAnalysis.Search.environmentDescription string The environment description of search result.
HybridAnalysis.Search.submitname string The submission name of the search result.
HybridAnalysis.Search.vxfamily string The family of search result.
HybridAnalysis.Search.threatscore string The threat score of the search result.
HybridAnalysis.Search.type_short string The type of search result, for example: "url" or "host".
HybridAnalysis.Search.size number The size of the search result.
File.Malicious.Vendor string For malicious files, the vendor that made the decision.
File.Malicious.Description string For malicious files, the reason that the vendor made the decision.
DBotScore.Indicator unknown The indicator.
DBotScore.Type unknown The indicator type.
DBotScore.Vendor unknown The DBotScore vendor.
DBotScore.Score unknown The DBot score.

 

Command Example
 !hybrid-analysis-search filename=fvp_setup_3.2.1.53fi.exe min_malicious_scanners=2
Human Readable Output

4. Detonate a file


Submits a file for detonation in Hybrid Analysis.

Base Command

hybrid-analysis-detonate-file

Input
Argument Name Description Required
entryId The War Room entry ID of the sample file you want to detonate. Required
environmentID The environment ID to which to submit the file for detonation. Run the vx-get-environments command to get all environment IDs. Default is 100, or other WINDOWS ID. Optional
delay The amount of time (in seconds) to wait between calls. Default is "3". Optional
timeout The total wait time (in seconds) before timeout. Default is "60". Optional
malicious_threat_levels A comma separated list of threat level values. Files that have a threat level
specified in the list will be considered malicious.
Optional

 

Context Output
Path Type Description
File.SHA256 string The SHA256 hash of the file.
File.SHA1 string The SHA1 hash of the file.
File.MD5 string The MD5 of the file.
File.environmentalId string The environmental ID of the file.
File.analysis_start_time string The start time of the file.
File.submitname string The submission name of the file.
File.classification_tags string A list of classification tags of the file.
File.vxfamily string The family classification of the file.
File.total_network_connections string The total number of network connections of the file.
File.total_processes string The total processes count of the file.
File.total_signatures string The total signatures count of the file.
File.hosts string A list of hosts of the file.
File.isinteresting string Whether the server found the file interesting.
File.domains string A list of domains related to the file.
File.isurlanalysis string Whether the file was analyzed by a URL.
File.Malicious.Vendor string For malicious files, the vendor that made the decision.
File.Malicious.Description string For malicious files, the reason that the vendor made the decision.
DBotScore.Indicator string The indicator.
DBotScore.Type string The indicator type.
DBotScore.Vendor string The DBot score vendor.
DBotScore.Score number The DBot score.

 

5. Get the status of a file submission


Returns the state of the file submission.

Base Command

hybrid-analysis-get-report-status

Input
Argument Name Description Required
jobID The job ID of the submission. Optional
sha256 The submission SHA256. Optional
environmentID The environment ID of the submission. Optional
 
Context Output
Path Type Description
HybridAnalysis.Submit.State string The state of the process.
HybridAnalysis.Submit.SHA256 string The SHA256 hash of the submission.
HybridAnalysis.Submit.JobID string The job ID of the submission.
HybridAnalysis.Submit.EnvironmentID string The environment ID of the submission.

 

6. Submit a website or file URL for quick analysis


Submits the URL of a website, or the URL that contains the file, for analysis.

Base Command

hybrid-analysis-quick-scan-url

Input
Argument Name Description Required
scan_type The type of scan. Run the hybrid-analysis-list-scanners command to view available scanners. Optional
url The website URL, or the URL that contains the file to submit. Required

 

Context Output
Path Type Description
HybridAnalysis.URL.Data string The URL.
HybridAnalysis.URL.ScanID string The scan ID.
HybridAnalysis.URL.SHA256 string The SHA256 hash of the URL.
HybridAnalysis.URL.Finished boolean Whether the scan completed.
File.Name string The URL.
File.SHA256 string The SHA256 hash of the file.
HybridAnalysis.URL.SubmissionType string The type of the submission. Can be "file" or "url".

 

Command Example
 !hybrid-analysis-quick-scan-url url=www.google.com
Human Readable Output

7. Submit a website or file URL for analysis


Submits the URL of a website or the URL that contains the file, for analysis.

Base Command

hybrid-analysis-submit-url

Input
Argument Name Description Required
url The URL of the file to submit. Required
environmentID The environment ID to which to submit the file. Run the vx-get-environments command to get all environment IDs. Required

 

Context Output
Path Type Description
HybridAnalysis.Submit.JobID string The job ID of the submission.
HybridAnalysis.Submit.SHA256 string The SHA256 of the submission.
HybridAnalysis.Submit.EnvironmentID number The environment ID of the submission.
HybridAnalysis.Submit.SubmissionType string The type of the submission. Can be "file" or "url".

 

Command Example
!hybrid-analysis-submit-url environmentID=100 url=www.google.com
Human Readable Output

8. Get a list of scanners


Returns a list of available scanners.

Base Command

hybrid-analysis-list-scanners

Input

 There are no input arguments for this command.

Context Output
Path Type Description
HybridAnalysis.Scanner.Available unknown Whether the scanner is available.
HybridAnalysis.Scanner.Name unknown The scanner name.
HybridAnalysis.Scanner.Description unknown The scanner description.

 

Command Example
 !hybrid-analysis-list-scanners
Human Readable Output

9. Get scan results


Returns the scan results of the given URL ID.

Base Command

hybrid-analysis-quick-scan-url-results

Input
Argument Name Description Required
scanID The scan ID of the scanned URL. Required
min_malicious_scanners The number of scanners that report the file as malicious to determine whether the file is malicious. Default is "2". Optional

 

Context Output
Path Type Description
HybridAnalysis.URL.ScanID string The scan ID.
HybridAnalysis.URL.SHA256 string The SHA256 hash of the indicator.
HybridAnalysis.URL.Finished boolean Whether the process completed.
HybridAnalysis.URL.Scanner.Name string The scanner name.
HybridAnalysis.URL.Scanner.Positives number The number of positive results.
HybridAnalysis.URL.Scanner.Status string The status of the file.
HybridAnalysis.URL.Whitelist.ID string The type of ID.
HybridAnalysis.URL.Whitelist.Value boolean Whether the indicator is on the allow list.
File.SHA256 string The SHA256 hash of the file.

 

Command Example
!hybrid-analysis-quick-scan-url-results scanID=5d6cf460028838eb26d56dc4
Human Readable Output

Configuration parameters

  • serverUrl — Server URL (e.g. https://216.3.128.82) (required)
  • apiKey — API Key
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (9)

  • hybrid-analysis-detonate-file Deprecated

    Submits a file for detonation in Hybrid Analysis.

  • hybrid-analysis-get-report-status Deprecated

    Returns the state of the file submission.

  • hybrid-analysis-list-scanners Deprecated

    Returns a list of available scanners.

  • hybrid-analysis-quick-scan-url Deprecated

    Submits the URL of a website, or the URL that contains the file, for analysis.

  • hybrid-analysis-quick-scan-url-results Deprecated

    Returns the scan results of the given URL ID.

  • hybrid-analysis-scan Deprecated

    Returns summary information for a given MD5, SHA1 or SHA256 hash, and all reports generated for any environment ID.

  • hybrid-analysis-search Deprecated

    Performs a search on the database using the Hybrid Analysis search syntax.

  • hybrid-analysis-submit-sample Deprecated

    Submits a file from the investigation to the analysis server. The minimum required authorization is "default".

  • hybrid-analysis-submit-url Deprecated

    Submits The URL of a website or the URL that contains the file, for analysis.

var serverUrl = params.serverUrl;
var insecure = params.insecure;
var proxy = params.proxy;
var version = params.version;
var apiKey;
var integrationContext = getIntegrationContext();
var licenseID = getLicenseID();
var HEADERS = {
    'User-Agent': ['Hybrid Analysis'],
    'accept': ['application/json'],
    'Content-Type': ['application/x-www-form-urlencoded'],
    'DemistoLicense': [licenseID]
};

if (params.apiKey) {
    apiKey = params.apiKey;
} else if (integrationContext.apiKey) {
    apiKey = integrationContext.apiKey;
} else {
    apiKey = generateKey();
}

HEADERS['api-key'] = [apiKey];

// handle '/' at the end of serverUrl
if (serverUrl[serverUrl.length - 1] === '/') {
    serverUrl = serverUrl.substring(0, serverUrl.length - 1);
}

function generateKey() {
    HEADERS['api-key'] = [integrationContext.masterApiKey];
    var cmdUrl = '/api/v2/key/create';
    var response = sendRequest('POST', cmdUrl, 'uid=DemistoLimitedEdition');
    key = response.api_key;
    integrationContext.apiKey = key;
    setIntegrationContext(integrationContext);
    return key;
}

function entryError(errorCode, text) {
    var error = 'Hybrid Analysis returned an error (' + errorCode + ') - ' + text;
    return {Type: entryTypes.error, ContentsFormat: formats.text, Contents: error};
}

//Originally, there was a mismatch between some context fields and their corresponding YML outputs.
//For example: the context field name was 'environment_id' while the corresponding YML output was 'environmentId'.
//This function gets a context entry and adds the existing YML outputs into the context, with the values of the original fields from context.
//The old context fields are not being deleted in order to prevent braking backwards compatibility.
function addYMLOutputsToContext(contextEntry) {
     Object.keys(contextEntry).forEach(function(key) {
            switch (key) {
                case 'environment_id':
                    contextEntry.environmentId = contextEntry['environment_id'];
                    break;
                case 'submit_name':
                    contextEntry.submitname = contextEntry['submit_name'];
                    break;
                case 'vx_family':
                    contextEntry.vxfamily = contextEntry['vx_family'];
                    break;
                case 'interesting':
                    contextEntry.isinteresting = contextEntry['interesting'];
                    break;
                case 'url_analysis':
                    contextEntry.isurlanalysis = contextEntry['url_analysis'];
                    break;
            }
        });
    return contextEntry;
}

 //  get threat level and calculate Dbot score by the following rule: 0=No Threat, 1=Suspicious, 2=Malicious, 3=Unknown
function threatLevelToDbotScore(threatLevel, maliciousThreatLevels) {
    var dbotScore = 0;
    if (maliciousThreatLevels.indexOf(threatLevel) !== -1){
        dbotScore = 3;
    }

    else {
        switch (threatLevel) {
            case 0:
                dbotScore = 1;
                break;
            case 1:
                dbotScore = 2;
                break;
            case 2:
                dbotScore = 2;
                break;
            case 3:
                dbotScore = 0;
                break;
        }
    }
    return dbotScore;
}


// return a function that maps object keys by mapper (or capitlize keys if key is not exists in mapper)
function mapObject(mapper, isContextMapper, maliciousThreatLevels) {
    return function(obj) {
        var res = {};
        Object.keys(obj).forEach(function(key) {
            // map key or capitalize if not exists
            var newKey = mapper[key] || key;
            res[newKey] = obj[key];
            if (maliciousThreatLevels && obj.threat_level && maliciousThreatLevels.indexOf(obj.threat_level) !== -1 && isContextMapper) {
                res.Malicious = {
                    Vendor: 'Hybrid Analysis',
                    Description: 'Score above ' + obj.threat_score
                };
            }
        });
        if (isContextMapper)
            res = addYMLOutputsToContext(res);
        return res;
    };
}


function createTableEntry(name, rawResponse, table, context, headers) {
    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: rawResponse,
        ReadableContentsFormat: formats.markdown,
        HumanReadable: tableToMarkdown(name, table, headers, undefined, headerTransform=undefined, removeNull=true),
        EntryContext: context
    };
}

function sendRequest(method, endpoint, body) {
    var requestUrl = serverUrl + endpoint;
    var res = http(
        requestUrl,
        {
            Method: method,
            Headers: HEADERS,
            Body: body
        },
        insecure,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
    }

    var body;
    try {
        body = JSON.parse(res.Body);
    } catch (ex) {
        throw 'Error parsing response - ' + res.Body + ' - ' + ex;
    }

    return body;
}

function scan(hash) {
   return sendRequest('POST', '/api/v2/search/hash', 'hash='+hash);

}
function scanToEntry(res, hash, maliciousThreatLevels) {
    var response = res;

    // create table from response
    var tableMapper = {
       threatlevel: 'threat level',
       total_network_connections: 'total network connections',
       targeturl: 'target url',
       classification_tags: 'classification tags',
       threatscore: 'threat score',
       total_processes: 'total processes',
       submitname: 'submit name',
       environmentDescription: 'environment description',
       isinteresting: 'interesting',
       environmentId: 'environment id',
       isurlanalysis: 'url analysis',
       analysis_start_time: 'analysis start time',
       total_signatures: 'total signatures'
    };

    var table = response.map(mapObject(tableMapper, false, maliciousThreatLevels));
    // create context from response
    var context = {};

    var contextMapper = {
        sha1: 'SHA1',
        sha256: 'SHA256',
        md5: 'MD5'
    };

    context[outputPaths.file] = response.map(mapObject(contextMapper, true, maliciousThreatLevels));

    // add DbotScore to context
    response.forEach(function(res) {
        var dbotScore = threatLevelToDbotScore(res.threat_level, maliciousThreatLevels);
        context["DBotScore"] = {
            "Indicator": hash,
            "Type": "File",
            "Vendor": "Hybrid Analysis",
            "Score": dbotScore
        };
    });

    return createTableEntry('Scan Results:', response, table, context);
}

function submitFile (entryId, environmentId) {
    var requestUrl = serverUrl + '/api/v2/submit/file';

    // submit file
    var res = httpMultipart(
                requestUrl, // URL
                entryId, // Optional - FilePath / EntryID
                {
                    Method: 'POST',
                    Headers: HEADERS
                },
                { // Multipart Contents
                    environment_id: environmentId // For API v2
                },
                insecure,
                proxy
            );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Multipart Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
    }
    var body;

    try {
        body = JSON.parse(res.Body);
    } catch (ex) {
        throw 'Error parsing response - ' + res.Body + ' - ' + ex;
    }

    return body;
}

function submitFileMsg(response) {
    var result = {
        'JobID':  response.job_id,
        'SHA256': response.sha256,
        'EnvironmentID': response.environment_id
    };
    var context = {
        'HybridAnalysis.Submit(val.JobID && val.JobID == obj.JobID)': result
    };
    return createTableEntry('Submission information:', result, result, context);
}

function searchQuery(query, minMaliciousScanners) {
    body = '';
        if (args.query) {
            args.query.split(',').forEach(function(keyValue){
               splittedObject = keyValue.split(/:(.+)/); // Split by first ':' only
               key = splittedObject[0];
               value = splittedObject[1];
               body += key + '=' + value + '&'
            });
        } else {
        // Build Crowd Strike query syntax from arguments, i.e. key:value
            for (var key in args) {
                if (key != 'min_malicious_scanners') {
                    body += key + '=' + args[key] + '&';
                }
            }
        }
    var res = sendRequest('POST', '/api/v2/search/terms', body);

    var result = res.result;

    // create table from search result
    var tableMapper = {
       environmentDescription: 'environment description',
       start_time: 'start time',
       submitname: 'submit name',
       threatscore: 'threat score',
       type_short: 'type short',
    };

    var table = result.map(mapObject(tableMapper, false, null));

    // create context from search result
    var contextMapper = {
        job_id: 'JobID',
        sha256: 'SHA256',
        environment_id: 'EnvironmentID'
    };

    var context = {
        'HybridAnalysis.Search((val.JobID && val.JobID == obj.JobID) || (val.SHA256 && val.SHA256 == obj.SHA256))': result.map(mapObject(contextMapper, true, null))
    };

    //dbotScore pre-calculation
    var unknownCounter = 0;
    var maliciousCounter = 0;
    result.forEach(function(key) {
        if (key.verdict == null){
            unknownCounter++;
        }
        else if (key.verdict == 'malicious'){
            maliciousCounter++;
        }
    });

    // add DbotScore to context
    if (result.length != 0){
        var dbotScore = calculateDbotScore(unknownCounter, maliciousCounter, minMaliciousScanners, res.count);
        context["DBotScore"] = {
          "Indicator": res.search_terms[0].value,
            "Type": "File",
            "Vendor": "Hybrid Analysis",
            "Score": dbotScore
            };
    }

    return createTableEntry('Search results:', result, table, context);
}


//Return the state of the submission
function reportState(){

    var jobID = args.jobID;
    var sha256 = args.sha256;
    var environmentID = args.environmentID;

    var hybridAnalysisID = '';

    if (jobID) {
        hybridAnalysisID = jobID;
    } else if (sha256 && environmentID) {
        hybridAnalysisID = '{0}:{1}'.format(sha256, environmentID);
    } else {
        throw 'Job ID or SHA-256 and environment ID must be provided.'
    }

    var commandURL = '/api/v2/report/{0}/state'.format(hybridAnalysisID);

    var response = sendRequest('GET', commandURL);

    var state = response.state

    var output = 'Submission state: ' + state;

    var context = {
        'HybridAnalysis.Submit(val.JobID && val.JobID == obj.JobID)': {
            State: state,
            SHA256: sha256,
            JobID: jobID,
            EnvironmentID: environmentID
        }
    };

    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: response,
        ReadableContentsFormat: formats.markdown,
        HumanReadable: output,
        EntryContext: context
    };
}


function detonateFile(entryId, environmentId, malicious_threat_levels, delay, timeout) {
    var file = submitFile(entryId, environmentId);
    var hash = file.sha256;

    delayTime = parseInt(delay);
    timeOut = parseInt(timeout);
    var waitTime = delayTime;

    wait(delayTime);
    while (waitTime<timeOut) {
        var res = scan(hash);
        if (res.length > 0) {
            return scanToEntry(res, hash, malicious_threat_levels);
        } else {
            waitTime = waitTime + delayTime;
            wait(delayTime);
        }
    }
    throw ('Timeout due to no answer after ' + timeOut + ' seconds.');

}

//Dbot score calculation for a response without 'threat_level' field
function calculateDbotScore(unknownCounter, maliciousCounter,minMaliciousScanners, numOfScanners){
    var dbotScore = 0;

    if (maliciousCounter >= minMaliciousScanners)
        dbotScore = 3;
    else if (maliciousCounter >= 1)
        dbotScore = 2;
    else if (unknownCounter == numOfScanners)
        dbotScore = 0;
    else if (maliciousCounter == 0) // some scanners found it clean and no scanner found it malicious
        dbotScore = 1;

    return dbotScore;
}


function createFileContext (url, response, dbotScore, baseContext, urlContext, DbotContext, maliciousContext){
    var fileName = url.replace(/^.*[\\\/]/, '');
    DbotContext.Indicator = fileName;
    var fileContext = {
        'Name': fileName,
        'SHA256': response.sha256
    };
    if (dbotScore == 3) {
        fileContext.Malicious = maliciousContext;
    }

    context= {
        'HybridAnalysis.URL(val.ScanID && val.ScanID == obj.ScanID)' : baseContext,
        'URL(val.Data && val.Data == obj.Data)' : urlContext,
        'File(val.SHA256 && val.SHA256 == obj.SHA256)' : fileContext,
        'DBotScore' : DbotContext
    }
    return context;
}


// create the context, different between file and url context
function createQuickScanContext(response, scanners, dbotScore, maliciousDescription){

    var baseContext = {
        'ScanID': response.id,
        'SHA256': response.sha256,
        'Scanner' : scanners,
        'Finished': response.finished
    };

    var DbotContext = {
        'Vendor': 'Hybrid Analysis',
        'Score': dbotScore,
        'Type': 'URL'
    }

    var url = getIntegrationContext()[response.id];
    var urlContext = {'Data' : url};

    if (dbotScore == 3){
        var maliciousContext = {
            Vendor: 'Hybrid Analysis',
            Description: 'The following scanners reported this URL as malicious: ' + maliciousDescription
        };
        urlContext.Malicious = maliciousContext;
    }

    var context = {};

    if (getIntegrationContext()[url] == 'file_url') {
        context = createFileContext (url, response, dbotScore, baseContext, urlContext, DbotContext, maliciousContext);
    }

    else {
        DbotContext.Indicator = url;
        context = {
            'HybridAnalysis.URL(val.ScanID && val.ScanID == obj.ScanID)' : baseContext,
            'URL(val.Data && val.Data == obj.Data)' : urlContext,
            'DBotScore' : DbotContext
        }
    }

    return context;
}


function createQuickScanHumanReadable (response, scannersContext, headers){
    var mdTable = {
        'ScanID': response.id,
        'SHA256': response.sha256,
        'Finished': response.finished
    };
    var md = '### Scan Results:\n' + tableToMarkdown(null, mdTable, ['ScanID', 'SHA256', 'Finished'], undefined, headerTransform=undefined, removeNull=true);
    var scanTable = '##### scanners:\n' + tableToMarkdown(null, scannersContext, headers, undefined, headerTransform=undefined, removeNull=true);
    var humanReadable = md + scanTable;

    return humanReadable;
}


    // create scanners entry context and calculate counters
function createScannersContext (response) {
    var unknownCounter = 0;
    var maliciousCounter = 0;
    var maliciousDescription = "";
    var scannersContext = [];

    response.scanners.forEach(function(key) {
        scannersContext.push(
            {
                'Name': key.name,
                'Status': key.status,
                'Positives': key.positives
            });
        if (key.status == 'unknown' || key.status =='no-result' || key.status == 'not-supported')
            unknownCounter++;
        else if (key.status == 'malicious'){
            maliciousCounter++;
            maliciousDescription = maliciousDescription + ', ' + key.name;
        }
    });

    maliciousDescription = maliciousDescription.substr(2); // remove the first ", "
    var res = {
        'scannersContext' : scannersContext,
        'unknownCounter' : unknownCounter,
        'maliciousCounter' : maliciousCounter,
        'maliciousDescription' : maliciousDescription
    }

    return res;
}


//create table entry from response after 'quick-scan-url-results' command
function quickScanResultToEntry(response, minMaliciousScanners) {

    var scannersResult = createScannersContext (response);
    var scannersContext = scannersResult['scannersContext'];
    var unknownCounter = scannersResult['unknownCounter'];
    var maliciousCounter = scannersResult['maliciousCounter'];
    var maliciousDescription = scannersResult['maliciousDescription'];

    var dbotScore = calculateDbotScore(unknownCounter, maliciousCounter, minMaliciousScanners, response.scanners.lenght);

    var context = createQuickScanContext (response, scannersContext, dbotScore, maliciousDescription);
    var humanReadable = createQuickScanHumanReadable (response, scannersContext);

    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: response,
        ReadableContentsFormat: formats.markdown,
        HumanReadable: humanReadable,
        EntryContext: context
    };
}

function createContext (response, hybridContext) {
    var url = hybridContext.URL;
    if (response.submission_type == 'page_url') {
        var context = {
            'HybridAnalysis.URL(val.ScanID && val.ScanID == obj.ScanID)': hybridContext,
            'URL(val.Data && val.Data == obj.Data)':{
                'Data': url
            }
        }
    }

    else {
        var filename = url.replace(/^.*[\\\/]/, '');
        var context = {
            'HybridAnalysis.URL(val.ScanID && val.ScanID == obj.ScanID)': hybridContext,
            'URL(val.Data && val.Data == obj.Data)':{
                'Data': url
            },
            'File(val.SHA256 && val.SHA256 == obj.SHA256)' : {
                'SHA256': response.sha256,
                'Name': filename,
            }
        }
    }

    return context;
}


//create table entry from response after 'quick-scan-url/file' command
function quickScanToEntry(response, url) {
    var ScanID = response.id;
    var hybridContext = {
        'URL': url,
        'ScanID': response.id,
        'SHA256': response.sha256,
        'Finished': response.finished,
        'SubmissionType' : response.submission_type
    };

    var context = createContext(response, hybridContext)

    // adding { ScanID : url } to the integration context for future use
    var addToContext = {};
    addToContext[ScanID] = url;
    addToContext[url] = response.submission_type;
    setIntegrationContext(addToContext);

    var headers = ['ScanID', 'URL', 'Finished', 'SHA256', 'SubmissionType']
    return createTableEntry('Scan information:', response, hybridContext, context, headers);
}


//Quick Scan commands
function quickScanUrl(scan_type, url, endpoint) {
    var body = 'scan_type=' + scan_type + '&url=' + encodeURIComponent(url);
    return sendRequest('POST', endpoint, body);
}


function quickScanId(id) {
    return sendRequest('GET', '/api/v2/quick-scan/' + id );
}


function scanStates(headers) {
    var result = sendRequest('GET', '/api/v2/quick-scan/state');
    var scannersContext = [];
    result.forEach(function(key) {// create scanner entry
        scannersContext.push(
            {
                'Name': key.name,
                'Available': key.available,
                'Description': key.description
            }
        );
    });

    return {
        Type: entryTypes.note,
        ContentsFormat: formats.json,
        Contents: result,
        ReadableContentsFormat: formats.markdown,
        HumanReadable: '### Scanner:\n' + tableToMarkdown(null, scannersContext, ['Name', 'Available', 'Description'], undefined, headerTransform=undefined, removeNull=true),
        EntryContext: {'HybridAnalysis.Scanner(val.Name && val.Name == obj.Name) :' : scannersContext}
    };

}


//Sandbox Submission commands
function submitUrl(url, environment_id, endpoint) {
    var body= 'url=' + url + '&environment_id=' + environment_id;
    return sendRequest('POST', endpoint, body);
}


switch (command) {
    case 'test-module':
        var res = quickScanUrl('all', 'www.google.com', '/api/v2/quick-scan/url');
        if (res != null && res.submission_type == 'page_url') {
           return 'ok';
        }
        return 'the response is: ' + JSON.stringify(res) ;
    case 'hybrid-analysis-scan':
        var res = scan(args.file);
        return scanToEntry(res, args.file, args.malicious_threat_levels);
    case 'hybrid-analysis-submit-sample':
        var response = submitFile(args.entryId, args.environmentID);
        return submitFileMsg(response);
    case 'hybrid-analysis-search':
        return searchQuery(args.query, args.min_malicious_scanners);
    case 'hybrid-analysis-detonate-file':
        return detonateFile(args.entryId, args.environmentID, args.malicious_threat_levels, args.delay, args.timeout);
    case 'hybrid-analysis-get-report-status':
        return reportState();
    //Quick Scan commands
    case 'hybrid-analysis-quick-scan-url':
        var res = quickScanUrl(args.scan_type, args.url, '/api/v2/quick-scan/url');
        return quickScanToEntry(res, args.url);
    case 'hybrid-analysis-quick-scan-url-results':
        var res = quickScanId(args.scanID);
        return quickScanResultToEntry(res, args.min_malicious_scanners);
    case 'hybrid-analysis-list-scanners':
        return scanStates();
    //Sandbox Submission commands
    case 'hybrid-analysis-submit-url':
        var response = submitUrl(args.url, args.environmentID, '/api/v2/submit/url' );
        return submitFileMsg(response);
}