AutoFocus V2 Deprecated

Deprecated. Use the Unit 42 Intelligence integration instead.

Data Enrichment & Threat Intelligence · AutoFocus by Palo Alto Networks

Details

IDAutoFocus V2
ProviderPalo Alto Networks
CategoryData Enrichment & Threat Intelligence
From Version5.0.0
Docker Imagedemisto/python3:3.12.8.3296088
Supported ModulesAgentix Cortex Cloud Cloud Runtime Security Cloud Posture Security XSIAM EDR

README

Use the AutoFocus v2 integration to contextualize threat intelligence and bring speed, consistency, and precision to threat investigation.
TIM customers that upgraded to version 6.2 or above, can have the API Key pre-configured in their main account so no additional input is needed. To use this feature, upgrade your license so it includes the license key.

Use Cases

  • Query samples / sessions
  • Get sample analysis
  • Get session details
  • Get tag details
  • Get top tags

Get Your API Key

To get your API key, you need to add an authorization code, and then activate the API.

Add your authorization code

  1. Go to the Palo Alto Networks support site.
  2. Select Assets > Site Licenses tab.
  3. Select Add Site License.
  4. Enter the authorization code.

Activate the API

  1. in Site Licenses, select Enable.
  2. Click the API Key link.

Use the API key when configuring the integration.
For more information on activating the license see Activating AutoFocus Licenses.

Configure AutoFocus V2 on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for AutoFocus V2.
  3. Click Add instance to create and configure a new integration instance.

    Parameter Description Example
    Name A meaningful name for the integration instance. AutoFocus V2_instance_2
    API Key Account’s private token. N/A
    Source Reliability Reliability of the source providing the intelligence data. B - Usually reliable
    Additional Malicious Verdicts A comma-separated list of Palo Alto Networks verdicts to consider as malicious when calculating the DBot score. malware,phishing,c2
    Override default credentials Whether to override the default AutoFocus API key given by the Cortex XSOAR platform. False
    Trust any certificate (not secure) When selected, certificates are not checked. N/A
    Use System Proxy Settings Runs the integration instance using the proxy server (HTTP or HTTPS) that you defined in the server configuration. N/A
    handle_error Suppress errors for non found indicators. N/A
  4. Click Test to validate the URLs, token, and connection.

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.

Search for samples


Searches for samples. To view the results provide polling=true, or run the autofocus-samples-search-results command with the returned Af Cookie. The AF Cookie expires 120 seconds after the search completes. Use the query that was created in AutoFocus within playbooks “as-is”. To run the command with the query in Cortex XSOAR, wrap the query in backticks ``. For example:

!autofocus-search-samples query=`{"operator":"all","children":[{"field":"sample.malware","operator":"is","value":1}]}` scope=Global sort="First Seen (Create Date)" order=Ascending
Base Command

autofocus-search-samples

Input
Argument Name Description Required
query The query for which to retrieve samples. For additional information on how to build your query using the AF GUI, see the detailed description. Optional
max_results The number of results to return. Optional
sort The field by which to sort the results. Optional
order The order of the results. Can be “Ascending” or “Descending”. Optional
scope The scope of the search. Can be “Private”, “Public”, or “Global”. Required
file_hash The MD5, SHA1 or SHA256 hash of the file. Optional
domain The domain to search. Optional
ip The IP address to search. Optional
url The URL to search. Optional
artifact Whether to return artifacts of samples. Optional
wildfire_verdict The WildFire verdict. Can be “Malware”, “Grayware”, “Benign”, or “Phishing”. Optional
first_seen The date range of the creation date. Format: YYY Y-MM-DDTHH:MM:SS,YYYY-MM-DDTHH:MM:SS where the first date is the beginning and the second is the end. Example: 2019-09-09T00:00:00,2019-09-09T23:01:59 Optional
last_updated The date range of the last updated date. Format: YYY Y-MM-DDTHH:MM:SS,YYYY-MM-DDTHH:MM:SS where the first date is the beginning and the second is the end. Example: 2019-09-09T00:00:00,2019-09-09T23:01:59 Optional
af_cookie The AF Cookie for retrieving results of previous searches. The AF Cookie expires 120 seconds after the search completes. Optional
polling Use XSOAR built-in polling to retrieve the result when it’s ready. Optional
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Using polling

The polling argument was added in XSOAR 6.2.0. It enables to handle the search in a single command, foregoing the need to run autofocus-samples-search-results.

For more info see Scheduled Commands.

How to Build a Query

  1. Go to the AutoFocus platform search screen.
  2. Click the Advanced… button on the top right.
  3. Build a query by selecting the fields operators and relevant values. To add another condition, click the + button. For more information on how to use the search editor, see Work with the Search Editor.
  4. To get the query, open the API syntax, and click the >_API button.
    Copy the query value from the opening curly bracket { until the ,"scope" parameter, and paste it as the value for the query argument for both search commands. For example:
{"operator":"all","children":[{"field":"sample.malware","operator":"is","value":1},{"field":"sample.create_date","operator":"is after","value":["2019-06-13","2019-06-13"]}]}
Context Output
Path Type Description
AutoFocus.SamplesSearch.AFCookie String The ID of the search. Use this ID to get search results. The AF Cookie expires 120 seconds after the search completes.
AutoFocus.SamplesSearch.Status String The search status. Can be “in progress” or “complete”.
AutoFocus.SamplesResults.Size String The file size in bytes.
AutoFocus.SamplesResults.SHA1 String The SHA1 hash of the file.
AutoFocus.SamplesResults.SHA256 String The SHA256 hash of the file.
AutoFocus.SamplesResults.Created Date The date that the file was created.
AutoFocus.SamplesResults.Finished Date The date the file was finished.
AutoFocus.SamplesResults.Region String The region of the sample.
AutoFocus.SamplesResults.FileType String The file type.
AutoFocus.SamplesResults.Tags String The tags attached to the sample.
AutoFocus.SamplesResults.Verdict Number The verdict of the sample.
AutoFocus.SamplesResults.TagGroups String The groups of relevant tags.
AutoFocus.SamplesSearch.Status String The search status. Can be “in progress” or “complete”.
AutoFocus.SamplesSearch.Artifact.b Number How many set the artifact as benign.
AutoFocus.SamplesSearch.Artifact.g Number How many set the artifact as grayware.
AutoFocus.SamplesSearch.Artifact.m Number How many set the artifact as malicious.
AutoFocus.SamplesSearch.Artifact.confidence String How confident the decision.
AutoFocus.SamplesSearch.Artifact.indicator String The indicator that was tested.
AutoFocus.SamplesSearch.Artifact.indicator_type String The indicator type, for example: Mutex, User agent, IPv4, Domain.
File.Size Number The size of the file in bytes.
File.SHA1 String The SHA1 hash of the file.
File.SHA256 String The SHA256 hash of the file.
File.Type String The file type, as determined by libmagic (same as displayed in file entries).
File.Tags String The tags of the file.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-search-samples query=`{"operator":"all","children":[{"field":"sample.malware","operator":"is","value":1}]}` scope=Global sort="First Seen (Create Date)" order=Ascending
Context Example
{
    "AutoFocus.SamplesSearch": {
        "Status": "in progress", 
        "AFCookie": "2-78049b80-9c18-47e7-835e-d31ca8bd48aa+0"
    }
}
Human Readable Output
Search Samples Info
AFCookie Status
2-78049b80-9c18-47e7-835e-d31ca8bd48aa+0 in progress

Search for sessions


Searches for sessions. To view the results provide polling=true, or run the autofocus-sessions-search-results command with the returned AF Cookie. The AF Cookie expires 120 seconds after the search completes.

Base Command

autofocus-search-sessions

Input
Argument Name Description Required
query The query for which to retrieve samples. For additional information on how to build your query using the AF GUI, see the detailed description section. Optional
max_results The maximum number of results to return. The default is 30. Optional
sort The field by which to sort the results. Optional
order The order of the results. Can be “Ascending” or “Descending”. Optional
file_hash The MD5, SHA1 or SHA256 hash of the file. Optional
domain The domain to search. Optional
ip The IP address to search. Optional
url The URL to search. Optional
time_range The date range in which to search for sessions. Format: YYY Y-MM-DDTHH:MM:SS,YYYY-MM-DDTHH:MM:SS where the first date is the beginning and the second is the end. Example: 2019-09-09T00:00:00,2019-09-09T23:01:59 Optional
time_after The date after which to search for sessions. Format: YYYY-MM-DDTHH:MM:SS Example: 2019-09-09T23:01:59 Optional
time_before The date before which to search for sessions. Format: YYYY-MM-DDTHH:MM:SS Example: 2019-09-09T23:01:59 Optional
polling Use XSOAR built-in polling to retrieve the result when it’s ready. Optional
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Using polling

The polling argument was added in XSOAR 6.2.0. It enables to handle the search in a single command, foregoing the need for autofocus-sessions-search-results.

For more info see Scheduled Commands.

How to Build a Query

  1. Go to the AutoFocus platform search screen.
  2. Select the Advanced… button on the top right.
  3. Build a query by selecting fields operators and relevant values. To add another condition, click the + button. For more information on how to use the search editor, see Work with the Search Editor.
  4. To get the query you built, open the API syntax, and click the >_API button.
  5. Copy the query value from the opening curly bracket { until the ,"scope" parameter, and paste it as the value for the query argument for both search commands. For example:
{"operator":"all","children":[{"field":"sample.malware","operator":"is","value":1},{"field":"sample.create_date","operator":"is after","value":["2019-06-13","2019-06-13"]}]}
Context Output
Path Type Description
AutoFocus.SessionsSearch.AFCookie String The ID of the search. Use the ID to get search results. The AF Cookie expires 120 seconds after the search completes.
AutoFocus.SessionsSearch.Status String The status of the search. Can be “in progress” or “complete”.
AutoFocus.SessionsResults.FileName String The name of the file..
AutoFocus.SessionsResults.ID String The ID of the session. Used to get session details.
AutoFocus.SessionsResults.Industry String The related industry.
AutoFocus.SessionsResults.Region String The regions of the sessions.
AutoFocus.SessionsResults.SHA256 String The SHA256 hash of the file.
AutoFocus.SessionsResults.Seen Date The seen date.
AutoFocus.SessionsResults.UploadSource String The source of the uploaded sample.
AutoFocus.SessionsResults.FileURL String The URL of the file.
AutoFocus.SessionsResults.Tags String The relevant tags.
AutoFocus.SessionsSearch.Status String The search status. Can be “in progress” or “complete”.
File.Name String The full file name (including file extension).
File.SHA256 String The SHA256 hash of the file.
File.Tags String The tags of the file.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-search-sessions query={"operator":"all","children":[{"field":"sample.malware","operator":"is","value":1}]} max_results="30" sort="Application" order="Ascending"
Context Example
{
    "AutoFocus.SessionsSearch": {
        "Status": "in progress", 
        "AFCookie": "2-2d70539d-26af-40d2-b80b-16be60dabbaf+0"
    }
}
Human Readable Output
Search Sessions Info
AFCookie Status
2-2d70539d-26af-40d2-b80b-16be60dabbaf+0 in progress

Get results of a samples search


Returns the results of a previous samples search.

Base Command

autofocus-samples-search-results

Input
Argument Name Description Required
af_cookie The AF Cookie for retrieving results of previous searches. The AF Cookie expires 120 seconds after the search completes. Required
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.SamplesResults.Size String The file size in bytes.
AutoFocus.SamplesResults.SHA1 String The SHA1 hash of the file.
AutoFocus.SamplesResults.SHA256 String The SHA256 hash of the file.
AutoFocus.SamplesResults.Created Date The date that the file was created.
AutoFocus.SamplesResults.Finished Date The date the file was finished.
AutoFocus.SamplesResults.Region String The region of the sample.
AutoFocus.SamplesResults.FileType String The file type.
AutoFocus.SamplesResults.Tags String The tags attached to the sample.
AutoFocus.SamplesResults.Verdict Number The verdict of the sample.
AutoFocus.SamplesResults.TagGroups String The groups of relevant tags.
AutoFocus.SamplesSearch.Status String The search status. Can be “in progress” or “complete”.
AutoFocus.SamplesSearch.Artifact.b Number How many set the artifact as benign.
AutoFocus.SamplesSearch.Artifact.g Number How many set the artifact as grayware.
AutoFocus.SamplesSearch.Artifact.m Number How many set the artifact as malicious.
AutoFocus.SamplesSearch.Artifact.confidence String How confident the decision.
AutoFocus.SamplesSearch.Artifact.indicator String The indicator that was tested.
AutoFocus.SamplesSearch.Artifact.indicator_type String The indicator type, for example: Mutex, User agent, IPv4, Domain.
File.Size Number The size of the file in bytes.
File.SHA1 String The SHA1 hash of the file.
File.SHA256 String The SHA256 hash of the file.
File.Type String The file type, as determined by libmagic (same as displayed in file entries).
File.Tags String The tags of the file.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-samples-search-results af_cookie=2-c0a49ebb-2fee-4423-9bd3-76004d5878ba+1
Context Example
{
    "File": [
        {
            "SHA256": "55f66d613414b35d46e48b952541403a5b2a5d1a1e3c0bef2bd76607b41400b9", 
            "Type": "PE", 
            "Size": 28832
        },
    ], 
    "AutoFocus.SamplesResults": [
        {
            "Artifact": [
                {
                    "b": 914,
                    "confidence": "interesting",
                    "g": 25,
                    "indicator": "1048576",
                    "indicator_type": "Mutex",
                    "m": 292
                },
                {
                    "b": 120,
                    "confidence": "interesting",
                    "g": 0,
                    "indicator": "1048577",
                    "indicator_type": "Mutex",
                    "m": 179
                },
                {
                    "b": 64605,
                    "confidence": "suspect",
                    "g": 7095,
                    "indicator": "ZonesCacheCounterMutex",
                    "indicator_type": "Mutex",
                    "m": 512566
                }
            ],
            "Created": "2020-04-03T00:35:53",
            "FileType": "PE",
            "Finished": "2020-04-03T00:43:33",
            "ID": "2dfb6b0cb24d745fa412479ea3b0cabe9d2b57e008016656af55a6d3832c2091",
            "MD5": "ef05777192cccc6502609dbdf0dc6149",
            "Region": [
                "us"
            ],
            "SHA1": "c23fe9ce9c9f6260c5eb385cbb71fa1f6817cca5",
            "SHA256": "2dfb6b0cb24d745fa412479ea3b0cabe9d2b57e008016656af55a6d3832c2091",
            "Size": 234505,
            "Tags": [
                "Unit42.InitialSystemDataEnumeration",
                "Unit42.RunOnce",
                "Unit42.GandCrab"
            ],
            "Verdict": 1,
            "imphash": "af2a98692b8b30d8401f26d24a673b23",
            "ssdeep": "3072:kKogwq8P3Nm0ZSLPjerAg0FuD5HibZ6nEdMmgcUUcNS7FY+qTtwuz0f8TpIe8OuW:CvqqAOF+640UcSFNuzokpIx95K3",
            "tag_groups": [
                "Ransomware"
            ],
            "tasks": [
                {
                    "metadata_compilation_ts": "2018-05-14T22:05:59"
                }
            ]
        }
    ], 
    "AutoFocus.SamplesSearch": {
        "Status": "complete", 
        "AFCookie": "2-c0a49ebb-2fee-4423-9bd3-76004d5878ba+1"
    }
}
Human Readable Output

Search Samples Result is in progress

Created FileType Finished ID MD5 Region SHA1 SHA256 Size Tags Verdict imphash ssdeep tag_groups tasks
2020-04-05T00:03:49 PE 2020-04-05T00:11:59 d455abd39edc7a2f03fa43b4d0f9194a11e73fce9c794021b5ca050dd0bc156d 77c94c76214c7069b7fc5e7634b7e225 us 1460b6a9a0955f0d5c011edba569786c13b6d8a6 d455abd39edc7a2f03fa43b4d0f9194a11e73fce9c794021b5ca050dd0bc156d 362331 Unit42.IPAddressLookup,Unit42.InitialSystemDataEnumeration,Unit42.RunOnce,Unit42.GandCrab 1 f456e8b8fd5e0768c2e3120e086c8ebc 6144 Ransomware {‘metadata_compilation_ts’: ‘2018-06-11T11:15:25’}

Artifacts for Sample

b g m indicator_type confidence indicator
1 0 145006 Domain suspect carder.bit
1 0 208393 Domain suspect ransomware.bit
373 67 317773 IPv4 suspect 66.171.248.178

Get results of a sessions search


Returns the results of a previous session’s search.

Base Command

autofocus-sessions-search-results

Input
Argument Name Description Required
af_cookie The AF Cookie for retrieving the results of a previous search. The AF Cookie expires 120 seconds after the search completes. Required
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.SessionsResults.FileName String The name of the file..
AutoFocus.SessionsResults.ID String The ID of the session. Used to get session details.
AutoFocus.SessionsResults.Industry String The related industry.
AutoFocus.SessionsResults.Region String The regions of the sessions.
AutoFocus.SessionsResults.SHA256 String The SHA256 hash of the file.
AutoFocus.SessionsResults.Seen Date The seen date.
AutoFocus.SessionsResults.UploadSource String The source of the uploaded sample.
AutoFocus.SessionsResults.FileURL String The URL of the file.
AutoFocus.SessionsResults.Tags String The relevant tags.
AutoFocus.SessionsSearch.Status String The search status. Can be “in progress” or “complete”.
File.Name String The full file name (including file extension).
File.SHA256 String The SHA256 hash of the file.
File.Tags String The tags of the file.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-sessions-search-results af_cookie=2-f2c742b6-a363-4eb9-a313-63a99c376081+0
Context Example
{
    "AutoFocus.SessionsSearch": {
        "Status": "complete", 
        "AFCookie": "2-f2c742b6-a363-4eb9-a313-63a99c376081+0"
    }, 
    "File": [
        {
            "SHA256": "2eb355b54855c7531a811d435b2ff4dc74d377bfed98fd1ad03caa591f5555bd", 
            "Name": "wildfire-test-pe-file.exe", 
            "Tags": [
                "Commodity.WildFireTest"
            ]
        }, 
        {
            "SHA256": "f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38", 
            "Name": "wildfire-test-pe-file (4).exe", 
            "Tags": [
                "Commodity.WildFireTest"
            ]
        }
    ], 
    "AutoFocus.SessionsResults": [
        {
            "tag_groups": [], 
            "Tags": [
                "Commodity.WildFireTest"
            ], 
            "Industry": "High Tech", 
            "FileName": "wildfire-test-pe-file.exe", 
            "ID": "u_56095401643", 
            "UploadSource": "Manual API", 
            "Seen": "2019-12-11T08:52:16", 
            "SHA256": "2eb355b54855c7531a811d435b2ff4dc74d377bfed98fd1ad03caa591f5555bd", 
            "Region": "us"
        }
    ]
}
Human Readable Output
Search Sessions Results is complete
FileName ID Industry Region SHA256 Seen Tags UploadSource tag_groups
wildfire-test-pe-file.exe u_56095401643 High Tech us 2eb355b54855c7531a811d435b2ff4dc74d377bfed98fd1ad03caa591f5555bd 2019-12-11T08:52:16 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49158137853 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T11:04:05 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49159945553 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T11:19:21 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_48980717523 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-09-30T23:58:00 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_48980935123 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-01T00:02:36 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_48980770253 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-09-30T23:59:18 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_48980686453 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-09-30T23:57:10 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49128586383 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T08:44:04 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49129503223 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T08:49:24 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49122514613 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T07:39:45 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49145687573 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T09:52:36 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (4).exe u_49158441703 High Tech us f29192fba1064d582cddc85ef3bcf37fa8e9b7d5faddb3e67d241d472e66ab38 2019-10-02T11:06:29 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47517508773 High Tech us cafa7f3adaace43042e5f85328ddf1d6f0d8109e65f7e6c0b87676a9a7479733 2019-09-17T01:59:31 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47515984893 High Tech us 4851a140be5af4acf3d85621d99c177fd6e1403e8e93c9cba6037459c802382f 2019-09-17T01:32:11 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47517298263 High Tech us 5d3725fe649e3a1244fe50cd23b2e558594753d7579c30214da293566d6afa3b 2019-09-17T01:56:51 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47541182333 High Tech us 51a93620c2c1456081f91bad64e537724a0d93dcf55face4f1d33df9a91486f1 2019-09-17T06:05:21 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47518135653 High Tech us b39a6bf99de8dd7e55d22ee0732ea3582536a0615dab86e3d36010fe0d4ecf2a 2019-09-17T02:04:56 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47516600663 High Tech us 7078f4e2c5d8038bd875e3a6dfd09c9014573c5d3c155f27c3acd1073c05d16f 2019-09-17T01:46:01 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47561050553 High Tech us c14646114c390027d373cbd5af7d31d952ab6acd86d5157bb174b19792e557f2 2019-09-17T08:14:56 41453.TestElena,Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47517909453 High Tech us 2499501bebcc6ff59d3f0028f760e0433ee3a9415e916d1278a70c474690869d 2019-09-17T02:02:46 Commodity.WildFireTest Manual API  
wildfire-test-pe-file.exe u_47559447933 High Tech us 12f198c65cbdf49972b7432291dad4d2fae7cbb77a35cda1cc28ab2b83d1e2b5 2019-09-17T08:08:39 Commodity.WildFireTest Manual API  
https://wildfire.paloaltonetworks.com/publicapi/test/pe u_46060032683 High Tech us 2e40edcf77d95173463ca4bfaf833a6a1860ffa4e7b03c3fded8de08ee2be27f 2019-09-01T04:34:48 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (2).exe u_45811064553 High Tech us f27069e200ed14c56b1b91285ea3c061aa0e4ca53d9056fed9cc0c9c3e98e961 2019-08-28T21:17:33 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (2).exe u_45810946733 High Tech us f27069e200ed14c56b1b91285ea3c061aa0e4ca53d9056fed9cc0c9c3e98e961 2019-08-28T21:14:17 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (2).exe u_45810992703 High Tech us f27069e200ed14c56b1b91285ea3c061aa0e4ca53d9056fed9cc0c9c3e98e961 2019-08-28T21:15:31 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (2).exe u_45811012343 High Tech us f27069e200ed14c56b1b91285ea3c061aa0e4ca53d9056fed9cc0c9c3e98e961 2019-08-28T21:16:06 Commodity.WildFireTest Manual API  
https://wildfire.paloaltonetworks.com/publicapi/test/pe u_45835887733 High Tech us bfdc97ecc0d1e19d17cffe856b33c41883520d7b38daa77af03bb42ef83bc680 2019-08-29T05:19:21 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (3).exe u_45811604063 High Tech us 409eb2fa745b4bd804bb3ebdd48f0107bd9c6471a9447a61f68c1a32c480f0f9 2019-08-28T21:32:05 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (3).exe u_45811375593 High Tech us 409eb2fa745b4bd804bb3ebdd48f0107bd9c6471a9447a61f68c1a32c480f0f9 2019-08-28T21:25:36 Commodity.WildFireTest Manual API  
wildfire-test-pe-file (3).exe u_45811208463 High Tech us 409eb2fa745b4bd804bb3ebdd48f0107bd9c6471a9447a61f68c1a32c480f0f9 2019-08-28T21:20:56 Commodity.WildFireTest Manual API  

Get session details


Returns session details by session ID.

Base Command

autofocus-get-session-details

Input
Argument Name Description Required
session_id The ID of the session. Required
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.Sessions.FileName String The name of the file.
AutoFocus.Sessions.ID String The ID of the session.
AutoFocus.Sessions.Industry String The related industry.
AutoFocus.Sessions.Region String The session’s regions.
AutoFocus.Sessions.SHA256 String The SHA256 hash of the file.
AutoFocus.Sessions.Seen Date The seen date.
AutoFocus.Sessions.UploadSource String The source that uploaded the sample.
File.Name String The full file name (including file extension).
File.SHA256 String The SHA256 hash of the file.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-get-session-details session_id="u_39605858263"
Context Example
{
    "File": [
        {
            "SHA256": "8d4241654449c63f70dabd83483f8ca8bd8e8e6a8d0679639eb061b3b6dbcfec", 
            "Name": "wildfire-test-apk-file.apk"
        }
    ], 
    "AutoFocus.Sessions": [
        {
            "Industry": "High Tech", 
            "FileName": "wildfire-test-apk-file.apk", 
            "ID": "u_39605858263", 
            "UploadSource": "Manual API", 
            "Seen": "2019-05-29T15:25:26", 
            "SHA256": "8d4241654449c63f70dabd83483f8ca8bd8e8e6a8d0679639eb061b3b6dbcfec", 
            "Region": "us"
        }
    ]
}
Human Readable Output
Session u_39605858263
FileName ID Industry Region SHA256 Seen UploadSource
wildfire-test-apk-file.apk u_39605858263 High Tech us 8d4241654449c63f70dabd83483f8ca8bd8e8e6a8d0679639eb061b3b6dbcfec 2019-05-29T15:25:26 Manual API

Get analysis details


Returns properties, behaviors, and activities observed for a sample. Runs the command a single time to get the fields and operating systems under HTTP, Coverage, Behavior, Registry, Files, Processes, Connections, and DNS.

Base Command

autofocus-sample-analysis

Input
Argument Name Description Required
sample_id The SHA256 hash of the sample to analyze. Required
os The analysis environment. Can be “win7”, “winxp”, “android”, “static_analyzer”, “mac”, or “bare_metal”. Optional
filter_data Whether to smartly filter the data. If “False”, the data returned will not be smartly filtered, and will significantly reduce integration performance. The recommended setting is “True”. Optional
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.SampleAnalysis.Analysis.Http Unknown The HTTP requests made when the sample was executed.
AutoFocus.SampleAnalysis.Analysis.Coverage Unknown The WildFire signatures that matched the sample.
AutoFocus.SampleAnalysis.Analysis.Behavior Unknown The sample behavior: created or modified files, started a process, spawned new processes, modified the registry, or installed browser help objects.
AutoFocus.SampleAnalysis.Analysis.Registry Unknown The registry settings and options that showed activity when the sample was executed in the analysis environment.
AutoFocus.SampleAnalysis.Analysis.Files Unknown The files that showed activity as a result of the sample being executed.
AutoFocus.SampleAnalysis.Analysis.Processes Unknown The processes that showed activity when the sample was executed.
AutoFocus.SampleAnalysis.Analysis.Connections Unknown The connections to other hosts on the network when the sample was executed.
AutoFocus.SampleAnalysis.Analysis.Dns Unknown The DNS activity observed when the sample was executed.
AutoFocus.SampleAnalysis.Analysis.Mutex Unknown The mutex created when the program’s start is listed with the parent process if the sample generates other program threads when executed in the analysis environment.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-sample-analysis sample_id=dd0d26ceea034b3ae32a4f6a477466ac598ee17f811f88cf14b2c708240fb993
Context Example
{
    "AutoFocus.SampleAnalysis": {
        "ID": "dd0d26ceea034b3ae32a4f6a477466ac598ee17f811f88cf14b2c708240fb993", 
        "Analysis": {
            "Files": {
                "win7": [
                    {
                        "action": " Create ", 
                        "parent_process": "svchost.exe "
                    }, 
                    {
                        "action": " Create ", 
                        "parent_process": "na.exe "
                    }, 
                    {
                        "action": " Create ", 
                        "parent_process": "svchost.exe "
                    }, 
                    {
                        "action": " Create ", 
                        "parent_process": "users\\administrator\\sample.dll:DllInstall "
                    }, 
                    {
                        "action": " Create ", 
                        "parent_process": "users\\administrator\\sample.dll:DllInstall "
                    }
                ], 
                "winxp": []
            }, 
            "Processes": {
                "win7": [
                    {
                        "action": " created ", 
                        "parent_process": "svchost.exe "
                    }, 
                    {
                        "action": " created ", 
                        "parent_process": "services.exe "
                    }, 
                    {
                        "action": " created ", 
                        "parent_process": "TrustedInstaller.exe "
                    }, 
                    {
                        "action": " CreateProcessInternalW ", 
                        "parent_process": "<null> "
                    }
                ], 
                "winxp": [
                    {
                        "action": " created ", 
                        "parent_process": "explorer.exe "
                    }, 
                    {
                        "action": " created ", 
                        "parent_process": "svchost.exe "
                    }, 
                    {
                        "action": " created ", 
                        "parent_process": "winlogon.exe "
                    }
                ]
            }, 
            "Http": {
                "win7": [
                    {
                        "url": " / ", 
                        "host": "sp1.eventincoandhar.info ", 
                        "method": " POST "
                    }, 
                    {
                        "url": " / ", 
                        "host": "sc1.eventincoandhar.info ", 
                        "method": " POST "
                    }, 
                    {
                        "url": " / ", 
                        "host": "www.bbc.com ", 
                        "method": " HEAD "
                    }
                ]
            }, 
            "Coverage": {
                "url_categories": [
                    {
                        "url": "ns-154-b.gandi.net", 
                        "cat": "Computer and Internet Info"
                    }, 
                    {
                        "url": "ns3.fastly.net", 
                        "cat": "Computer and Internet Info"
                    }, 
                    {
                        "url": "aiden.ns.cloudflare.com", 
                        "cat": "Computer and Internet Info"
                    }, 
                    {
                        "url": "b.iana-servers.net", 
                        "cat": "Unknown"
                    }, 
                    {
                        "url": "aningtofrebri.info", 
                        "cat": "Unknown"
                    }
                ], 
                "fileurl_signatures": [], 
                "wildfire_signatures": [], 
                "dns_signatures": [
                    {
                        "create_date": "2016-03-30 07:32:49", 
                        "name": "generic:a.iana-servers.net"
                    }, 
                    {
                        "create_date": "2016-03-30 07:53:34", 
                        "name": "generic:b.iana-servers.net"
                    }, 
                    {
                        "create_date": "2017-12-13 22:55:29", 
                        "name": "Trojan-Downloader.adload:housandry.info"
                    }, 
                    {
                        "create_date": "2017-12-13 22:55:29", 
                        "name": "Trojan-Downloader.adload:whereason.info"
                    }, 
                    {
                        "create_date": "2018-04-07 10:05:16", 
                        "name": "Virus.ramnit:mrsewic.com"
                    }, 
                    {
                        "create_date": "2018-04-07 10:05:16", 
                        "name": "generic:ylsuest.com"
                    }, 
                    {
                        "create_date": "2018-04-07 10:15:23", 
                        "name": "generic:knsemis.com"
                    }, 
                    {
                        "create_date": "2019-02-07 09:00:08", 
                        "name": "Trojan.bsymem:inf2.aningtofrebri.info"
                    }
                ]
            }, 
            "Mutex": {
                "win7": [
                    {
                        "action": " CreateMutexW ", 
                        "process": "msiexec.exe ", 
                        "parameters": " Global\\_MSIExecute"
                    }
                ]
            }, 
            "Registry": {
                "win7": [
                    {
                        "action": " CreateKey ", 
                        "parameters": " HKLM\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
                    }, 
                    {
                        "action": " RegSetValueEx ", 
                        "parameters": " HKLM\\SYSTEM\\ControlSet001\\services\\Tcpip\\Parameters\\Interfaces\\{FF885F56-91B0-47CA-837A-F293CA541A1F} "
                    }, 
                    {
                        "action": " RegSetValueEx ", 
                        "parameters": " HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall "
                    }, 
                    {
                        "action": " RegSetValueEx ", 
                        "parameters": " HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5129CAA8-E24B-2AEE-652F-C652FBF1E9BB} "
                    }, 
                    {
                        "action": " RegSetValueEx ", 
                        "parameters": " HKLM\\SOFTWARE\\Wow6432Node\\$(brand_name) "
                    }
                ], 
                "winxp": [
                    {
                        "action": " SetValueKey ", 
                        "parameters": " HKCU\\SessionInformation\\ProgramCount "
                    }, 
                    {
                        "action": " SetValueKey ", 
                        "parameters": " HKLM\\SOFTWARE\\Microsoft\\WBEM\\CIMOM\\List of event-active namespaces "
                    }, 
                    {
                        "action": " SetValueKey ", 
                        "parameters": " HKLM\\SOFTWARE\\Microsoft\\WZCSVC\\Parameters\\Interfaces\\ControlFlags "
                    }, 
                    {
                        "action": " SetValueKey ", 
                        "parameters": " HKLM\\SOFTWARE\\Microsoft\\WZCSVC\\Parameters\\Interfaces\\ActiveSettings "
                    }
                ]
            }, 
            "Behavior": {
                "static_analyzer": [], 
                "win7": [
                    {
                        "risk": "high ", 
                        "behavior": " Connected to a non-standard HTTP port"
                    }, 
                    {
                        "risk": "medium ", 
                        "behavior": " Created or modified a file in the Windows system folder"
                    }, 
                    {
                        "risk": "high ", 
                        "behavior": " Connected to a malicious IP"
                    }, 
                    {
                        "risk": "high ", 
                        "behavior": " Connected to a malicious URL"
                    }
                ], 
                "winxp": [
                    {
                        "risk": "medium ", 
                        "behavior": " Created or modified a file in the Windows system folder"
                    }, 
                    {
                        "risk": "low ", 
                        "behavior": " Started a process from a user folder"
                    }
                ]
            }
        }
    }
}
Human Readable Output
Sample Analysis results for dd0d26ceea034b3ae32a4f6a477466ac598ee17f811f88cf14b2c708240fb993:### Behavior Static Analyzer

No entries

Behavior Win7
Behavior Risk
Connected to a non-standard HTTP port high
Created or modified a file in the Windows system folder medium
Generated unknown TCP or UDP traffic medium
Downloaded an executable high
Used a short HTTP header high
Used the HTTP POST method medium
Initiated a failed HTTP connection low
Sent an HTTP response before receiving a request high
Generated unknown HTTP traffic high
Connected to a malicious domain high
Created an executable file in a user folder low
Started a process from a user folder low
Deleted itself high
Registered an OLE control with regsvr32.exe medium
Started or stopped a Windows system service high
Attempted to determine public IP address via IP-checking website high
Connected to a malicious IP high
Connected to a malicious URL high
Behavior Winxp
Behavior Risk
Created or modified a file in the Windows system folder medium
Started a process from a user folder low
Processes Win7
Action Parent Process
created svchost.exe
created services.exe
created TrustedInstaller.exe
created csrss.exe
created TrustedInstaller.exe
created services.exe
created svchost.exe
created services.exe
Processes Winxp
Action Parent Process
created explorer.exe
created svchost.exe
created winlogon.exe
Files Win7
Action Parent Process
Create svchost.exe
Create na.exe
Create svchost.exe
Create na.exe
Create na.exe
Create na.exe
Create users\administrator\sample.dll:DllInstall
Create users\administrator\sample.dll:DllInstall
Files Winxp

No entries

###

33 Registry Win7:

Action Parameters
CreateKey HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
SetValueKey HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall{5129CAA8-E24B-2AEE-652F-C652FBF1E9BB}\cd77f991
CreateKey \Registry\Machine\System\CurrentControlSet\Services\RdyBoost\Parameters
CreateKey \Registry\Machine\System\CurrentControlSet\Services\RdyBoost\AttachState
SetValueKey HKLM\COMPONENTS\ServicingStackVersions\6.1.7601.17514 (win7sp1_rtm.101119-1850)
SetValueKey HKLM\SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\Paths\ProgramData\1560740575
SetValueKey HKLM\SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\Paths\Users\ADMINI~1\AppData\Local\Temp{F5743266-6DFF-3433-4CE4-56028389CD67}
RegSetValueEx HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
RegSetValueEx HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall{5129CAA8-E24B-2AEE-652F-C652FBF1E9BB}
RegSetValueEx HKLM\SOFTWARE\Wow6432Node$(brand_name)
Registry Winxp
Action Parameters
SetValueKey HKCU\SessionInformation\ProgramCount
SetValueKey HKLM\SOFTWARE\Microsoft\WBEM\CIMOM\List of event-active namespaces
SetValueKey HKCU\SessionInformation\ProgramCount
SetValueKey HKLM\SOFTWARE\Microsoft\WZCSVC\Parameters\Interfaces\ActiveSettings
Mutex Win7
Action Parameters Process
CreateMutexW Global_MSIExecute msiexec.exe
Http Win7
Host Method Url
sp1.eventincoandhar.info POST /
ip-api.com GET /json
knsemis.com POST /tickets
www.cnn.com HEAD /
www.bbc.com HEAD /

Get tag details


Returns details about the given tag.

Base Command

autofocus-tag-details

Input
Argument Name Description Required
tag_name The public tag name. Can be retrieved from the top-tags command. Required
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.Tag.TagName String The simple name of the tag.
AutoFocus.Tag.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.Tag.Count Number The number of samples that matched this tag.
AutoFocus.Tag.Lasthit Date The date that the tag was last encountered.
AutoFocus.Tag.TagDefinitionScope String The scope of the tag. Can be “public”, “private”, or “Unit42”.
AutoFocus.Tag.CustomerName String The organization that created the tag.
AutoFocus.Tag.Source String The organization or individual that discovered the threat that is defined in the tag.
AutoFocus.Tag.TagClass String The classification of the tag.
AutoFocus.Tag.TagDefinitionStatus String The status of the tag definition. Can be “enabled”, “disabled”, “removing”, or “rescoping”.
AutoFocus.Tag.TagGroup String The tag group of the tag.
AutoFocus.Tag.Description String The tag description.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-tag-details tag_name=490082.Pastebin_Raw
Context Example
{
    "AutoFocus.Tag": {
        "Count": 84674, 
        "Lasthit": "2020-01-02 05:22:18", 
        "CustomerName": "Squadra Solutions", 
        "PublicTagName": "490082.Pastebin_Raw", 
        "TagDefinitionScope": "public", 
        "Source": "Squadra Solutions", 
        "TagDefinitionStatus": "enabled", 
        "TagName": "Pastebin_Raw", 
        "TagClass": "malicious_behavior", 
        "Description": "Malicious actors may post raw code to Pastebin which can then be downloaded for further use or as a C2 channel. Some code are also encoded in base64 for further obfuscation"
    }
}
Human Readable Output
Tag 490082.Pastebin_Raw details
Count Customer Name Description Lasthit Public Tag Name Source Tag Class Tag Definition Scope Tag Definition Status Tag Name
84674 Squadra Solutions Malicious actors may post raw code to Pastebin which can then be downloaded for further use or as a C2 channel. Some code are also encoded in base64 for further obfuscation 2020-01-02 05:22:18 490082.Pastebin_Raw Squadra Solutions malicious_behavior public enabled Pastebin_Raw

Search for the most popular tags


Performs a search to identify the most popular tags.

Base Command

autofocus-top-tags-search

Input
Argument Name Description Required
scope The scope of the search. Can be “industry”, “organization”, “all”, or “global”. Required
class The tag class. Can be “Malware Family”, “Campaign”, “Actor”, “Exploit”, or Malicious Behavior”. See Tag Classes below for more information. Required
private Whether the tag scope is “private”. If “True”, the tag scope is private. The default is “False”. Optional
public Whether the tag scope is “public”. If “True”, the tag scope is public. The default is “False”. Optional
commodity Whether the tag scope is “commodity”. If “True”, the tag scope is commodity. The default is “False”. Optional
unit42 Whether the tag scope is “Unit42”. If “True”, the tag scope is unit42. The default is “False”. Optional
af_cookie The AF Cookie for retrieving results of previous searches. The AF Cookie expires 120 seconds after the search completes. Optional
polling Use XSOAR built-in polling to retrieve the result when it’s ready. Optional
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Using polling

The polling argument was added in XSOAR 6.2.0. It enables to handle the search in a single command, foregoing the need to run autofocus-samples-search-results.

For more info see Scheduled Commands.

Tag Classes
  • Malware Family: group of malware that have shared properties or common functions.
  • Campaign: targeted attack, which might include several incidents or sets of activities.
  • Actor: individual or group that initiates a campaign using malware families.
  • Exploit: an attack, which takes advantage of a software or network weakness, bug, or vulnerability to manipulate the behavior of the system.
  • Malicious Behavior: behavior that is not specific to a malware family or campaign, but indicates that your system has been compromised.
Context Output
Path Type Description
AutoFocus.TopTagsSearch.AFCookie String The ID of the search. Use this ID to get search results. The AF Cookie expires 120 seconds after the search completes.
AutoFocus.TopTagsSearch.Status String The status of the search. Can be “in progress” or “complete”.
AutoFocus.TopTagsResults.Count Number The number of samples that matched this tag.
AutoFocus.TopTagsResults.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.TopTagsResults.TagName String The simple name of the tag.
AutoFocus.TopTagsResults.Lasthit Date The last encounter date of the tag.
AutoFocus.TopTagsSearch.Status String The search status. Can be “in progress” or “complete”.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-top-tags-search scope="all" class="Malicious Behavior" private="True" public="True" commodity="False" unit42="False"
Context Example
{
    "AutoFocus.TopTagsSearch": {
        "Status": "in progress", 
        "AFCookie": "2-1caadf19-2e94-4742-b9cf-da8b2d90988c+0"
    }
}
Human Readable Output
Top tags search Info
AFCookie Status
2-1caadf19-2e94-4742-b9cf-da8b2d90988c+0 in progress

Get results of a top tags search


Returns the results of a previous top tags search.

Base Command

autofocus-top-tags-results

Input
Argument Name Description Required
af_cookie The AF Cookie for retrieving results of the previous search. The AF Cookie expires 120 seconds after the search completes. Required
retry_on_rate_limit Whether an auto retry of the command will be executed once the quota is refreshed if the API points have run out.
Possible values are: true, false. Default is false.
Optional
Context Output
Path Type Description
AutoFocus.TopTagsResults.Count Number The number of samples that matched this tag.
AutoFocus.TopTagsResults.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.TopTagsResults.TagName String The simple name of the tag.
AutoFocus.TopTagsResults.Lasthit Date The last encounter date of the tag.
AutoFocus.TopTagsSearch.Status String The search status. Can be “in progress” or “complete”.
AutoFocus.Quota.minute_points Number Total number of AutoFocus API points alloted per minute
AutoFocus.Quota.daily_points Number Total number of AutoFocus API points alloted per day
AutoFocus.Quota.minute_points_remaining Number Remaining number of AutoFocus API points per minute
AutoFocus.Quota.daily_points_remaining Number Remaining number of AutoFocus API points per day
AutoFocus.Quota.minute_bucket_start Date Timestamp for when the current minute allotment started
AutoFocus.Quota.daily_bucket_start Date Timestamp for when the current daily allotment started
Command Example
!autofocus-top-tags-results af_cookie=2-2190f844-7c0a-42e7-b4be-5f7d83c9b05c+0
Context Example
{
    "AutoFocus.TopTagsSearch": {
        "Status": "in progress", 
        "AFCookie": "2-2190f844-7c0a-42e7-b4be-5f7d83c9b05c+0"
    }, 
    "AutoFocus.TopTagsResults": [
        {
            "Count": 84674, 
            "Lasthit": "2020-01-02 05:22:18", 
            "TagName": "Pastebin_Raw", 
            "PublicTagName": "490082.Pastebin_Raw"
        }, 
        {
            "Count": 25288, 
            "Lasthit": "2020-01-01 18:36:12", 
            "TagName": "ServiceDllUnloadOnStop", 
            "PublicTagName": "46640.ServiceDllUnloadOnStop"
        }, 
        {
            "Count": 20912, 
            "Lasthit": "2020-01-01 16:09:10", 
            "TagName": "hupigon_mutex", 
            "PublicTagName": "104.hupigon_mutex"
        }, 
        {
            "Count": 68694, 
            "Lasthit": "2020-01-01 19:18:09", 
            "TagName": "Modify_ComputerName", 
            "PublicTagName": "490082.Modify_ComputerName"
        }, 
        {
            "Count": 18740, 
            "Lasthit": "2020-01-01 07:09:55", 
            "TagName": "Modify_TermServ_RDP", 
            "PublicTagName": "490082.Modify_TermServ_RDP"
        }, 
        {
            "Count": 53921, 
            "Lasthit": "2020-01-02 00:02:21", 
            "TagName": "Modify_Permission", 
            "PublicTagName": "46640.Modify_Permission"
        }, 
        {
            "Count": 11078, 
            "Lasthit": "2020-01-02 07:40:39", 
            "TagName": "MSOfficeResiliency", 
            "PublicTagName": "490082.MSOfficeResiliency"
        }, 
        {
            "Count": 18857, 
            "Lasthit": "2020-01-01 10:06:58", 
            "TagName": "SecurityProviders_Persistence_LoadDLL", 
            "PublicTagName": "490082.SecurityProviders_Persistence_LoadDLL"
        }, 
        {
            "Count": 100001, 
            "Lasthit": "2019-06-20 12:59:58", 
            "TagName": "Modify_AttachmentManager", 
            "PublicTagName": "490082.Modify_AttachmentManager"
        }, 
        {
            "Count": 15820, 
            "Lasthit": "2020-01-02 07:22:46", 
            "TagName": "Cygwin", 
            "PublicTagName": "490082.Cygwin"
        }, 
        {
            "Count": 7233, 
            "Lasthit": "2019-12-30 12:31:47", 
            "TagName": "SecureCRT", 
            "PublicTagName": "490082.SecureCRT"
        }, 
        {
            "Count": 13855, 
            "Lasthit": "2020-01-02 05:55:01", 
            "TagName": "Add_PKI_Cert_or_CA", 
            "PublicTagName": "490082.Add_PKI_Cert_or_CA"
        }, 
        {
            "Count": 40197, 
            "Lasthit": "2020-01-01 09:17:34", 
            "TagName": "Add_IE_EnhancedSecurityConfig", 
            "PublicTagName": "46640.Add_IE_EnhancedSecurityConfig"
        }, 
        {
            "Count": 35839, 
            "Lasthit": "2020-01-01 06:11:35", 
            "TagName": "WiresharkPCAP_DLL", 
            "PublicTagName": "490082.WiresharkPCAP_DLL"
        }, 
        {
            "Count": 6582, 
            "Lasthit": "2019-12-30 06:28:59", 
            "TagName": "ArdamaxKeyLogger", 
            "PublicTagName": "46640.ArdamaxKeyLogger"
        }, 
        {
            "Count": 26159, 
            "Lasthit": "2019-12-30 15:18:59", 
            "TagName": "Pastebin_Dropper", 
            "PublicTagName": "490082.Pastebin_Dropper"
        }, 
        {
            "Count": 24331, 
            "Lasthit": "2020-01-02 01:04:47", 
            "TagName": "Sandboxie", 
            "PublicTagName": "490082.Sandboxie"
        }, 
        {
            "Count": 6137, 
            "Lasthit": "2020-01-01 17:50:37", 
            "TagName": "FTP_Suspicious", 
            "PublicTagName": "490082.FTP_Suspicious"
        }, 
        {
            "Count": 9793, 
            "Lasthit": "2020-01-02 05:02:33", 
            "TagName": "AppCertDLL_Persistence_LoadDLL", 
            "PublicTagName": "490082.AppCertDLL_Persistence_LoadDLL"
        }, 
        {
            "Count": 2578, 
            "Lasthit": "2020-01-01 21:28:20", 
            "TagName": "MSIEXEC_Web_Install", 
            "PublicTagName": "46640.MSIEXEC_Web_Install"
        }
    ]
}
Human Readable Output
Search Top Tags Results is in progress
Count Lasthit Public Tag Name Tag Name
84674 2020-01-02 05:22:18 490082.Pastebin_Raw Pastebin_Raw
25288 2020-01-01 18:36:12 46640.ServiceDllUnloadOnStop ServiceDllUnloadOnStop
20912 2020-01-01 16:09:10 104.hupigon_mutex hupigon_mutex
68694 2020-01-01 19:18:09 490082.Modify_ComputerName Modify_ComputerName
18740 2020-01-01 07:09:55 490082.Modify_TermServ_RDP Modify_TermServ_RDP
53921 2020-01-02 00:02:21 46640.Modify_Permission Modify_Permission
11078 2020-01-02 07:40:39 490082.MSOfficeResiliency MSOfficeResiliency
18857 2020-01-01 10:06:58 490082.SecurityProviders_Persistence_LoadDLL SecurityProviders_Persistence_LoadDLL
100001 2019-06-20 12:59:58 490082.Modify_AttachmentManager Modify_AttachmentManager
15820 2020-01-02 07:22:46 490082.Cygwin Cygwin
7233 2019-12-30 12:31:47 490082.SecureCRT SecureCRT
13855 2020-01-02 05:55:01 490082.Add_PKI_Cert_or_CA Add_PKI_Cert_or_CA
40197 2020-01-01 09:17:34 46640.Add_IE_EnhancedSecurityConfig Add_IE_EnhancedSecurityConfig
35839 2020-01-01 06:11:35 490082.WiresharkPCAP_DLL WiresharkPCAP_DLL
6582 2019-12-30 06:28:59 46640.ArdamaxKeyLogger ArdamaxKeyLogger
26159 2019-12-30 15:18:59 490082.Pastebin_Dropper Pastebin_Dropper
24331 2020-01-02 01:04:47 490082.Sandboxie Sandboxie
6137 2020-01-01 17:50:37 490082.FTP_Suspicious FTP_Suspicious
9793 2020-01-02 05:02:33 490082.AppCertDLL_Persistence_LoadDLL AppCertDLL_Persistence_LoadDLL
2578 2020-01-01 21:28:20 46640.MSIEXEC_Web_Install MSIEXEC_Web_Install

Get the reputation for an IP address


Returns the reputation of an IP address.

Base Command

ip

Input
Argument Name Description Required
ip The IP address to check. Required
Context Output
Path Type Description
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Indicator String The indicator that was tested.
IP.Address String The IP address.
IP.Tags String Tags that are associated with the IP.
IP.MalwareFamily String The malware family associated with the IP.
IP.Relationships.EntityA String The source of the relationship.
IP.Relationships.EntityAType String The type of the source of the relationship.
IP.Relationships.EntityB String The destination of the relationship.
IP.Relationships.EntityBType String The type of the destination of the relationship.
IP.Relationships.Relationship String The name of the relationship.
AutoFocus.IP.IndicatorValue String The IP address value.
AutoFocus.IP.IndicatorType String The indicator type.
AutoFocus.IP.LatestPanVerdicts Unknown The latest verdicts from Palo Alto Networks products. Can be either “PAN_DB” or “WF_SAMPLE”(WildFire).
IP.Malicious.Vendor String The vendor that decided the file is malicious.
AutoFocus.IP.Tags.PublicTagName String The public name of the tag. This is used as the tag ID.
AutoFocus.IP.Tags.TagName String The simple name of the tag.
AutoFocus.IP.Tags.CustomerName String The organization that created the tag.
AutoFocus.IP.Tags.Source String The organization or individual that discovered the threat that is defined in the tag.
AutoFocus.IP.Tags.TagDefinitionScopeID Number The scope ID of the tag.
AutoFocus.IP.Tags.TagDefinitionStatusID Number The definition status ID of the tag.
AutoFocus.IP.Tags.TagClassID Number The classification ID of the tag.
AutoFocus.IP.Tags.Count Number The number of samples that matched this tag.
AutoFocus.IP.Tags.Lasthit Date The date that the tag was last encountered.
AutoFocus.IP.Tags.Description String The description of the tag.
Command Example
!ip ip=127.0.0.1 using-brand="AutoFocus V2"
Context Example
{
    "AutoFocus.IP": [
        {
            "SeenBy": [], 
            "LatestPanVerdicts": {
                "PAN_DB": "BENIGN"
            }, 
            "WildfireRelatedSampleVerdictCounts": {}, 
            "IndicatorValue": "127.0.0.1", 
            "IndicatorType": "IPV4_ADDRESS"
        }
    ], 
    "IP": [
        {
            "Address": "127.0.0.1"
        }
    ], 
    "DBotScore": [
        {
            "Vendor": "AutoFocus V2", 
            "Indicator": "127.0.0.1", 
            "Score": 1, 
            "Type": "ip"
        }
    ]
}
Human Readable Output
AutoFocus V2 IP reputation for: 127.0.0.1
Indicatortype Indicatorvalue Latestpanverdicts Seenby Wildfirerelatedsampleverdictcounts
IPV4_ADDRESS 127.0.0.1 PAN_DB: BENIGN    

Get the reputation of a URL


Returns the reputation of a URL.

Base Command

url

Input
Argument Name Description Required
url The URL to check. Required
Context Output
Path Type Description
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Indicator String The indicator that was tested.
URL.Data String The URL address.
URL.Tags String Tags that are associated with the URL.
URL.MalwareFamily String The malware family associated with the URL.
URL.Relationships.EntityA String The source of the relationship.
URL.Relationships.EntityAType String The type of the source of the relationship.
URL.Relationships.EntityB String The destination of the relationship.
URL.Relationships.EntityBType String The type of the destination of the relationship.
URL.Relationships.Relationship String The name of the relationship.
AutoFocus.URL.IndicatorValue String The URL value.
AutoFocus.URL.IndicatorType String The indicator type.
AutoFocus.URL.LatestPanVerdicts Unknown The latest verdicts from Palo Alto Networks products. Can be either “PAN_DB” or “WF_SAMPLE”(WildFire).
URL.Malicious.Vendor String The vendor that decided the file is malicious.
AutoFocus.URL.Tags.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.URL.Tags.TagName String The simple name of the tag.
AutoFocus.URL.Tags.CustomerName String The organization that created the tag.
AutoFocus.URL.Tags.Source String The organization or individual that discovered the threat that is defined in the tag.
AutoFocus.URL.Tags.TagDefinitionScopeID Number The scope ID of the tag.
AutoFocus.URL.Tags.TagDefinitionStatusID Number The definition status ID of the tag.
AutoFocus.URL.Tags.TagClassID Number The classification ID of the tag.
AutoFocus.URL.Tags.Count Number The number of samples that matched this tag.
AutoFocus.URL.Tags.Lasthit Date The date that the tag was last encountered.
AutoFocus.URL.Tags.Description String The description of the tag.
Command Example
!url url=www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/ using-brand="AutoFocus V2"
Context Example
{
    "URL": [
        {
            "Malicious": {
                "Vendor": "AutoFocus V2"
            }, 
            "Data": "www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/"
        }
    ], 
    "DBotScore": [
        {
            "Vendor": "AutoFocus V2", 
            "Indicator": "www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/", 
            "Score": 3, 
            "Type": "url"
        }
    ], 
    "AutoFocus.URL": [
        {
            "SeenBy": [], 
            "LatestPanVerdicts": {
                "PAN_DB": "MALWARE"
            }, 
            "WildfireRelatedSampleVerdictCounts": {}, 
            "IndicatorValue": "www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/", 
            "IndicatorType": "URL"
        }
    ]
}
Human Readable Output
AutoFocus V2 URL reputation for: www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/
Indicatortype Indicatorvalue Latestpanverdicts Seenby Wildfirerelatedsampleverdictcounts
URL www.andromedaa.ir/ir/andromedaa/likebegir/ap.smali/ PAN_DB: MALWARE    

Get the reputation of a file


Returns the reputation of a file.

Base Command

file

Input
Argument Name Description Required
file The SHA256 hash of the file. Required
Context Output
Path Type Description
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Indicator String The indicator that was tested.
File.SHA256 String The SHA256 hash of the file.
File.Tags String Tags that are associated with the file.
File.MalwareFamily String The malware family associated with the file.
File.Relationships.EntityA String The source of the relationship.
File.Relationships.EntityAType String The type of the source of the relationship.
File.Relationships.EntityB String The destination of the relationship.
File.Relationships.EntityBType String The type of the destination of the relationship.
File.Relationships.Relationship String The name of the relationship.
AutoFocus.File.IndicatorValue String The SHA256 hash value of the file.
AutoFocus.File.IndicatorType String The indicator type.
AutoFocus.File.LatestPanVerdicts Unknown The latest verdicts from Palo Alto Networks products. Can be either “PAN_DB” or “WF_SAMPLE”(WildFire).
File.Malicious.Vendor String The vendor that decided the file is malicious.
AutoFocus.File.Tags.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.File.Tags.TagName String The simple name of the tag.
AutoFocus.File.Tags.CustomerName String The organization that created the tag.
AutoFocus.File.Tags.Source String The organization or individual that discovered the threat that is defined in the tag.
AutoFocus.File.Tags.TagDefinitionScopeID Number The scope ID of the tag.
AutoFocus.File.Tags.TagDefinitionStatusID Number The definition status ID of the tag.
AutoFocus.File.Tags.TagClassID Number The classification ID of the tag.
AutoFocus.File.Tags.Count Number The number of samples that matched this tag.
AutoFocus.File.Tags.Lasthit Date The date that the tag was last encountered.
AutoFocus.File.Tags.Description String The description of the tag.
Command Example
!file file=9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac using-brand="AutoFocus V2"
Context Example
{
    "DBotScore": [
        {
            "Vendor": "AutoFocus V2", 
            "Indicator": "9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac", 
            "Score": 3, 
            "Type": "file"
        }
    ], 
    "File": [
        {
            "Malicious": {
                "Vendor": "AutoFocus V2"
            }, 
            "SHA256": "9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac"
        }
    ], 
    "AutoFocus.File": [
        {
            "SeenBy": [
                "WF_SAMPLE"
            ], 
            "LatestPanVerdicts": {
                "WF_SAMPLE": "MALWARE"
            }, 
            "WildfireRelatedSampleVerdictCounts": "", 
            "IndicatorType": "FILEHASH", 
            "IndicatorValue": "9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac", 
            "LastSeen": "2019-12-29T08:52:27.000Z", 
            "FirstSeen": "2019-09-24T06:46:21.000Z"
        }
    ]
}
Human Readable Output
AutoFocus V2 File reputation for: 9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac
Firstseen Indicatortype Indicatorvalue Lastseen Latestpanverdicts Seenby Wildfirerelatedsampleverdictcounts
2019-09-24T06:46:21.000Z FILEHASH 9040e9fda52931c9472c90ecad5b74295cdb9cf7b68e2b89219700f6a8bff5ac 2019-12-29T08:52:27.000Z WF_SAMPLE: MALWARE WF_SAMPLE  

Get the reputation of a domain name


Returns the reputation of a domain.

Base Command

domain

Input
Argument Name Description Required
domain The domain to check. Required
Context Output
Path Type Description
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Indicator String The indicator that was tested.
Domain.Name String The name of the domain.
Domain.Tags String Tags that are associated with the domain.
Domain.MalwareFamily String The malware family associated with the domain.
Domain.Relationships.EntityA String The source of the relationship.
Domain.Relationships.EntityAType String The type of the source of the relationship.
Domain.Relationships.EntityB String The destination of the relationship.
Domain.Relationships.EntityBType String The type of the destination of the relationship.
Domain.Relationships.Relationship String The name of the relationship.
AutoFocus.Domain.IndicatorValue String The value of the domain.
AutoFocus.Domain.IndicatorType String The indicator type.
AutoFocus.Domain.LatestPanVerdicts Unknown The latest verdicts from Palo Alto Networks products. Can be either “PAN_DB” or “WF_SAMPLE”(WildFire).
Domain.Malicious.Vendor String The vendor that decided the file is malicious.
AutoFocus.Domain.Tags.PublicTagName String The public name of the tag. This is used as an ID of the tag.
AutoFocus.Domain.Tags.TagName String The simple name of the tag.
AutoFocus.Domain.Tags.CustomerName String The organization that created the tag.
AutoFocus.Domain.Tags.Source String The organization or individual that discovered the threat that is defined in the tag.
AutoFocus.Domain.Tags.TagDefinitionScopeID Number The scope ID of the tag.
AutoFocus.Domain.Tags.TagDefinitionStatusID Number The definition status ID of the tag.
AutoFocus.Domain.Tags.TagClassID Number The classification ID of the tag.
AutoFocus.Domain.Tags.Count Number The number of samples that matched this tag.
AutoFocus.Domain.Tags.Lasthit Date The date that the tag was last encountered.
AutoFocus.Domain.Tags.Description String The description of the tag.
AutoFocus.Domain.WhoisAdminCountry String The country of the domain administrator.
AutoFocus.Domain.WhoisAdminEmail String The email address of the domain administrator.
AutoFocus.Domain.WhoisAdminName String The name of the domain administrator.
AutoFocus.Domain.WhoisDomainCreationDate Date The date that the domain was created.
AutoFocus.Domain.WhoisDomainExpireDate Date The date that the domain expires.
AutoFocus.Domain.WhoisDomainUpdateDate Date The date that the domain was last updated.
AutoFocus.Domain.WhoisRegistrar String The name of the registrar.
AutoFocus.Domain.WhoisRegistrarUrl String The email address of the registrar.
AutoFocus.Domain.WhoisRegistrant String The name of the registrant.
Command Example
!domain domain=google.com using-brand="AutoFocus V2"
Context Example
{
    "Domain": [
        {
            "Name": "google.com", 
            "WHOIS": {
                "Admin": {
                    "Email": null, 
                    "Name": null
                }, 
                "UpdatedDate": "2018-02-21", 
                "Registrar": {
                    "Name": "markdownguide Inc."
                }, 
                "ExpirationDate": "2020-09-14", 
                "CreationDate": "1997-09-15", 
                "Registrant": {
                    "Name": null
                }
            }
        }
    ], 
    "AutoFocus.Domain": [
        {
            "SeenBy": [], 
            "LatestPanVerdicts": {
                "PAN_DB": "BENIGN"
            }, 
            "WhoisAdminName": null, 
            "WhoisDomainExpireDate": "2020-09-14", 
            "WhoisRegistrarUrl": "www.markdownguide.org", 
            "WildfireRelatedSampleVerdictCounts": {}, 
            "IndicatorType": "DOMAIN", 
            "WhoisRegistrant": null, 
            "WhoisRegistrar": "markdownguide Inc.", 
            "IndicatorValue": "google.com", 
            "WhoisAdminEmail": null, 
            "WhoisDomainCreationDate": "1997-09-15", 
            "WhoisAdminCountry": null, 
            "WhoisDomainUpdateDate": "2018-02-21"
        }
    ], 
    "DBotScore": [
        {
            "Vendor": "AutoFocus V2", 
            "Indicator": "google.com", 
            "Score": 1, 
            "Type": "domain"
        }
    ]
}
Human Readable Output
AutoFocus V2 Domain reputation for: google.com
Indicatortype Indicatorvalue Latestpanverdicts Seenby Whoisadmincountry Whoisadminemail Whoisadminname Whoisdomaincreationdate Whoisdomainexpiredate Whoisdomainupdatedate Whoisregistrant Whoisregistrar Whoisregistrarurl Wildfirerelatedsampleverdictcounts
DOMAIN google.com PAN_DB: BENIGN         1997-09-15 2020-09-14 2018-02-21   markdownguide Inc. http://www.markdownguide.org  

autofocus-get-export-list-indicators


Gets export list indicators from AutoFocus.

Base Command

autofocus-get-export-list-indicators

Input

Argument Name Description Required
label The label of the exported list. Required

Context Output

Path Type Description
AutoFocus.ExportListIndicator.Type String The indicator type in the export list.
AutoFocus.ExportListIndicator.Value String The value of the indicator in the export list.
IP.Address String The IP address.
URL.Data String The URL address.
File.SHA256 String The SHA256 hash of the file.
Domain.Name String The domain name.

Configuration parameters

  • credentials
  • api_key — API Key
  • integrationReliability — Source Reliability
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • handle_error — Suppress errors for non found indicators
  • mark_as_malicious — Additional malicious verdicts
  • create_relationships — Create relationships

Commands (14)

  • autofocus-get-export-list-indicators

    Gets export list indicators from AutoFocus.

  • autofocus-get-session-details

    Get session details by session ID.

  • autofocus-sample-analysis

    Returns properties, behaviors, and activities observed for a sample. Run the command a single time to get the fields and operating systems under HTTP, Coverage, Behavior, Registry, Files, Processes, Connections, and DNS.

  • autofocus-samples-search-results

    Returns results of a previous samples search. `Autofocus Query Samples, Sessions and Tags` Playbook is recommended for querying and polling.

  • autofocus-search-samples

    Searches for samples in AutoFocus. To view results, run the autofocus-samples-search-results command with the returned AF Cookie. The AF Cookie expires 120 seconds after the search completes. `Autofocus Query Samples, Sessions and Tags` Playbook is recommended for querying and polling.

  • autofocus-search-sessions

    Searches for sessions in AutoFocus. To view results, run the autofocus-sessions-search-results command with the returned AF Cookie. The AF Cookie expires 120 seconds after the search completes. The `polling` argument was added in XSOAR 6.2.0. It enables handling the search in a single command, rather than using the `Autofocus Query Samples, Sessions and Tags` Playbook.

  • autofocus-sessions-search-results

    Returns results of a previous sessions search. `Autofocus Query Samples, Sessions and Tags` Playbook is recommended for querying and polling.

  • autofocus-tag-details

    Returns details about the given tag.

  • autofocus-top-tags-results

    Returns the results of a previous top tags search. `Autofocus Query Samples, Sessions and Tags` Playbook is recommended for querying and polling.

  • autofocus-top-tags-search

    Performs a search to identify the most popular tags. `Autofocus Query Samples, Sessions and Tags` Playbook is recommended for querying and polling.

  • domain

    Checks the reputation of a domain in AutoFocus.

  • file

    Checks the reputation of a file in AutoFocus.

  • ip

    Checks the reputation of an IP address in AutoFocus.

  • url

    Checks the reputation of a URL in AutoFocus.

from requests import Response

from CommonServerPython import *

""" IMPORTS """

import socket
import traceback
from collections.abc import Callable

""" GLOBALS/PARAMS """
PARAMS = demisto.params()

API_KEY = AutoFocusKeyRetriever(PARAMS.get("credentials", {}).get("password") or PARAMS.get("api_key")).key

# Remove trailing slash to prevent wrong URL path to service
SERVER = "https://autofocus.paloaltonetworks.com"

# Service base URL
BASE_URL = SERVER + "/api/v1.0"
VENDOR_NAME = "AutoFocus V2"

# Headers to be sent in requests
HEADERS = {"Content-Type": "application/json"}
RELATIONSHIP_TYPE_BY_TAG_CLASS_ID = {
    1: {"entity_b_type": "STIX Threat Actor", "name": "indicator-of"},
    2: {"entity_b_type": "Campaign", "name": "indicator-of"},
    3: {"entity_b_type": "STIX Malware", "name": "indicator-of"},
    5: {"entity_b_type": "STIX Attack Pattern", "name": "indicator-of"},
}
API_PARAM_DICT = {
    "scope": {"Private": "private", "Public": "public", "Global": "global"},
    "order": {"Ascending": "asc", "Descending": "desc"},
    "artifact": "artifactSource",
    "sort": {
        "App Name": "app_name",
        "App Packagename": "app_packagename",
        "File type": "filetype",
        "Size": "size",
        "Finish Date": "finish_date",
        "First Seen (Create Date)": "create_date",
        "Last Updated (Update Date)": "update_date",
        "MD5": "md5",
        "SHA1": "sha1",
        "SHA256": "sha256",
        "Ssdeep Fuzzy Hash": "ssdeep",
        "Application": "app",
        "Device Country": "device_country",
        "Device Country Code": "device_countrycode",
        "Device Hostname": "device_hostname",
        "Device Serial": "device_serial",
        "Device vsys": "vsys",
        "Destination Country": "dst_country",
        "Destination Country Code": "dst_countrycode",
        "Destination IP": "dst_ip",
        "Destination Port": "dst_port",
        "Email Charset": "emailsbjcharset",
        "Industry": "device_industry",
        "Source Country": "src_country",
        "Source Country Code": "src_countrycode",
        "Source IP": "src_ip",
        "Source Port": "src_port",
        "Time": "tstamp",
        "Upload source": "upload_srcPossible",
    },
    "tag_class": {
        "Actor": "actor",
        "Campaign": "campaign",
        "Exploit": "exploit",
        "Malicious Behavior": "malicious_behavior",
        "Malware Family": "malware_family",
    },
    "search_arguments": {
        "file_hash": {"api_name": "alias.hash_lookup", "operator": "is"},
        "domain": {"api_name": "alias.domain", "operator": "contains"},
        "ip": {"api_name": "alias.ip_address", "operator": "contains"},
        "url": {"api_name": "alias.url", "operator": "contains"},
        "wildfire_verdict": {
            "api_name": "sample.malware",
            "operator": "is",
            "translate": {
                "Malware": 1,
                "Grayware": 2,
                "Benign": 3,
                "Phishing": 4,
            },
        },
        "first_seen": {"api_name": "sample.create_date", "operator": "is in the range"},
        "last_updated": {"api_name": "sample.update_date", "operator": "is in the range"},
        "time_range": {"api_name": "session.tstamp", "operator": "is in the range"},
        "time_after": {"api_name": "session.tstamp", "operator": "is after"},
        "time_before": {"api_name": "session.tstamp", "operator": "is before"},
    },
    "file_indicators": {
        "Size": "Size",
        "SHA1": "SHA1",
        "SHA256": "SHA256",
        "FileType": "Type",
        "Tags": "Tags",
        "FileName": "Name",
    },
    "search_results": {
        "sha1": "SHA1",
        "sha256": "SHA256",
        "filetype": "FileType",
        "malware": "Verdict",
        "size": "Size",
        "create_date": "Created",
        "finish_date": "Finished",
        "md5": "MD5",
        "region": "Region",
        "tag": "Tags",
        "_id": "ID",
        "tstamp": "Seen",
        "filename": "FileName",
        "device_industry": "Industry",
        "upload_src": "UploadSource",
        "fileurl": "FileURL",
        "artifact": "Artifact",
    },
}
SAMPLE_ANALYSIS_LINE_KEYS = {
    "behavior": {"display_name": "behavior", "indexes": {"risk": 0, "behavior": -1}},
    "process": {"display_name": "processes", "indexes": {"parent_process": 0, "action": 1}},
    "file": {"display_name": "files", "indexes": {"parent_process": 0, "action": 1}},
    "registry": {"display_name": "registry", "indexes": {"action": 1, "parameters": 2}},
    "dns": {"display_name": "DNS", "indexes": {"query": 0, "response": 1}},
    "http": {"display_name": "HTTP", "indexes": {"host": 0, "method": 1, "url": 2}},
    "connection": {"display_name": "connections", "indexes": {"destination": 2}},
    "mutex": {"display_name": "mutex", "indexes": {"process": 0, "action": 1, "parameters": 2}},
}
SAMPLE_ANALYSIS_COVERAGE_KEYS = {
    "wf_av_sig": {"display_name": "wildfire_signatures", "fields": ["name", "create_date"]},
    "fileurl_sig": {"display_name": "fileurl_signatures", "fields": ["name", "create_date"]},
    "dns_sig": {"display_name": "dns_signatures", "fields": ["name", "create_date"]},
    "url_cat": {"display_name": "url_categories", "fields": ["url", "cat"]},
}

VERDICTS_TO_DBOTSCORE = {"benign": 1, "malware": 3, "grayware": 2, "phishing": 3, "c2": 3}

ERROR_DICT = {
    404: "Invalid URL.",
    408: "Invalid URL.",
    409: "Invalid message or missing parameters.",
    500: "Internal error.",
    503: "Rate limit exceeded.",
}

if PARAMS.get("mark_as_malicious"):
    verdicts = argToList(PARAMS.get("mark_as_malicious"))
    VERDICTS_TO_DBOTSCORE.update(dict.fromkeys(verdicts, 3))

DEFAULT_BUCKET_INFO = dict.fromkeys(
    (
        "minute_points",
        "daily_points",
        "minute_points_remaining",
        "daily_points_remaining",
        "minute_bucket_start",
        "daily_bucket_start",
    ),
    "Unavailable",
)

EXECUTION_METRICS = ExecutionMetrics()
API_POINTS_TABLE = CommandResults(outputs_prefix="AutoFocus.Quota", replace_existing=True)


""" CLIENT CLASS """


class Client(BaseClient):
    def __init__(self, url: str, verify: bool = True, proxy: bool = False):
        super().__init__(base_url=url, verify=verify, proxy=proxy)

    def parse_response(self, resp: requests.Response, err_operation: str | None) -> dict:
        try:
            res_json = resp.json()
            save_api_metrics(res_json)  # type: ignore
            if resp.status_code == 503:
                EXECUTION_METRICS.quota_error += 1
                raise RateLimitExceededError(res_json)

            # Handle error responses gracefully
            if demisto.params().get("handle_error", True) and resp.status_code == 409:
                EXECUTION_METRICS.service_error += 1
                raise Exception("Response status code: 409 \nRequested sample not found")

            resp.raise_for_status()

            if "x-trace-id" in resp.headers:
                # this debug log was request by autofocus team for debugging on their end purposes
                demisto.debug(f'x-trace-id: {resp.headers["x-trace-id"]}')

            EXECUTION_METRICS.success += 1
            return res_json
        # Errors returned from AutoFocus
        except requests.exceptions.HTTPError:
            EXECUTION_METRICS.general_error += 1
            raise DemistoException(f'{err_operation}: {res_json.get("message")}')
        # Unexpected errors (where no json object was received)
        except Exception as err:
            EXECUTION_METRICS.general_error += 1
            raise DemistoException(f"{err_operation}: {err}")

    def http_request(
        self, url_suffix, method="POST", data={}, err_operation=None, ok_codes=(200, 409, 503), headers=HEADERS, params={}
    ):
        """A general http request.
        Args:
            method: str - the method to perform in the http request (GET, POST, etc.)
            url_suffix: str - the url_suffix for the http request.
            data: Any - the data for the request.
            err_operation: str - The string that will be in the exception in case one occurred.
            ok_codes: tuple - a list of status codes that we want to handle in the code and not raise automatic exception about.
            headers: dict - the headers of the request
            params: dict - the parameters of the request
        Returns:
            A response object in case of a GET method (url, ip, domain, file), otherwise a dict.
        """
        # The GET method is used only in search_indicator commands (url, ip, domain, file), and they have the API key in
        # the headers instead of data.
        if method == "POST":
            data.update({"apiKey": API_KEY})
        try:
            demisto.debug("http_request: before the request")
            res = self._http_request(
                method=method,
                url_suffix=url_suffix,
                data=json.dumps(data),
                headers=headers,
                resp_type="response",
                ok_codes=ok_codes,
                retries=3,
                params=params,
            )
            demisto.debug(f"http_request: {res=}")
        # Handle with connection error
        except requests.exceptions.ConnectionError as err:
            demisto.debug("http_request in requests.exceptions.ConnectionError")
            EXECUTION_METRICS.connection_error += 1
            raise DemistoException(f"Error connecting to server. Check your URL/Proxy/Certificate settings: {err}")

        # for the different search_indicator commands (url, ip, domain, file) the calling function handles the different
        # status codes.
        if method == "GET":
            return res

        return self.parse_response(res, err_operation)


""" HELPER FUNCTIONS """


class RateLimitExceededError(BaseException):
    def __init__(self, api_res: dict) -> None:
        super().__init__()
        self.api_res = api_res


def return_metrics():
    if EXECUTION_METRICS.metrics is not None and ExecutionMetrics.is_supported():
        return_results(EXECUTION_METRICS.metrics)
    if API_POINTS_TABLE.readable_output:
        return_results(API_POINTS_TABLE)


""" COMMAND FUNCTIONS """


def rerun_command_if_required(api_res: dict, retry_on_rate_limit: bool):
    daily_points_remaining = dict_safe_get(api_res, ("bucket_info", "daily_points_remaining"), 0)
    next_run = int(dict_safe_get(api_res, ("bucket_info", "wait_in_seconds"), 70, (int, float)))  # type: ignore
    if retry_on_rate_limit and daily_points_remaining and next_run < 300:
        results = CommandResults(
            readable_output="API Rate limit exceeded, rerunning command.",
            scheduled_command=ScheduledCommand(
                command=demisto.command(),
                args=(demisto.args() | {"retry_on_rate_limit": "false"}),
                next_run_in_seconds=(next_run + 20),
            ),
        )
    else:
        results = CommandResults(
            readable_output=f'Error in API call to AutoFocus.\nMessage: {api_res.get("message")}',
            entry_type=EntryType.ERROR,
            raw_response=f'Error in API call to AutoFocus.\nMessage: {api_res.get("message")}',
        )
    return_results(results)


def save_api_metrics(res_obj: dict):
    if bucket_info := res_obj.get("bucket_info"):
        demisto.debug(f"save_api_metrics: {bucket_info=}")
        API_POINTS_TABLE.readable_output = tableToMarkdown(
            "Autofocus API Points",
            {
                "Daily points used": "{daily_points_remaining}/{daily_points}",
                "Daily allotment started": "{daily_bucket_start}",
                "Minute points used": "{minute_points_remaining}/{minute_points}",
                "Minute allotment started": "{minute_bucket_start}",
            },
        ).format(**(DEFAULT_BUCKET_INFO | bucket_info))
        API_POINTS_TABLE.outputs = bucket_info
    else:
        demisto.debug("save_api_metrics: no bucket_info")


def run_polling_command(client: Client, args: dict, cmd: str, search_function: Callable, results_function: Callable):
    interval_in_secs = arg_to_number(args.get("interval_in_seconds", 60))
    if "af_cookie" not in args:
        # create new search
        command_results = search_function(client, args)
        outputs = command_results.outputs
        af_cookie = outputs.get("AFCookie")
        if outputs.get("Status") != "complete":
            polling_args = {"af_cookie": af_cookie, "interval_in_seconds": interval_in_secs, "polling": True, **args}
            command_results.scheduled_command = ScheduledCommand(
                command=cmd,
                next_run_in_seconds=interval_in_secs,  # type: ignore
                args=polling_args,
                timeout_in_seconds=600,
            )
            return command_results
        else:
            # continue to look for search results
            args["af_cookie"] = af_cookie
    # get search status
    command_results, status = results_function(client, args)
    if status != "complete":
        # schedule next poll
        polling_args = {"af_cookie": args.get("af_cookie"), "interval_in_seconds": interval_in_secs, "polling": True, **args}
        scheduled_command = ScheduledCommand(
            command=cmd,
            next_run_in_seconds=interval_in_secs,  # type: ignore
            args=polling_args,
            timeout_in_seconds=600,
        )

        # result with scheduled_command only - no update to the war room
        command_results = CommandResults(scheduled_command=scheduled_command)
    return command_results


def validate_sort_and_order_and_artifact(
    sort: Optional[str] = None, order: Optional[str] = None, artifact_source: Optional[str] = None
) -> bool:
    """
    Function that validates the arguments combination.
    sort and order arguments must be defined together.
    Sort and order can't appear with artifact.
    Args:
        sort: variable to sort by.
        order: the order which the results is ordered by.
        artifact_source: true if artifacts are needed and false otherwise.
    Returns:
        true if arguments are valid for the request, false otherwise.
    """
    if artifact_source == "true" and sort:
        raise Exception("Please remove or disable one of sort or artifact, As they are not supported in the api together.")
    elif sort and not order:
        raise Exception("Please specify the order of sorting (Ascending or Descending).")
    elif order and not sort:
        raise Exception("Please specify a field to sort by.")
    return bool(sort and order)


def do_search(
    client: Client,
    search_object: str,
    query: dict,
    scope: Optional[str],
    size: Optional[str] = None,
    sort: Optional[str] = None,
    order: Optional[str] = None,
    err_operation: Optional[str] = None,
    artifact_source: Optional[str] = None,
) -> dict:
    """
    This function created the data to be sent in http request and sends it.
    Args:
        client: The client to make the requests with.
        search_object: Type of search sessions or samples.
        query: Query based on conditions specified within this object.
        scope:  Scope of the search. Only available and required for: samples. e.g. Public, Global, Private.
        size: Number of results to provide.
        sort: Sort based on the provided artifact.
        order: How to display sort results in ascending or descending order.
        err_operation: String error which specificed which command failed.
        artifact_source: Whether artifacts are wanted or not.
    Returns:
        raw response of the http request.
    """
    path = "/samples/search" if search_object == "samples" else "/sessions/search"
    data = {"query": query, "size": size}
    if scope:
        data.update({"scope": API_PARAM_DICT["scope"][scope]})  # type: ignore
    if validate_sort_and_order_and_artifact(sort, order, artifact_source):
        data.update({"sort": {API_PARAM_DICT["sort"][sort]: {"order": API_PARAM_DICT["order"][order]}}})  # type: ignore
    if artifact_source == "true":
        data.update({"artifactSource": "af"})
        data.update({"type": "scan"})
    # Remove nulls
    data = createContext(data, removeNull=True)
    demisto.debug(f"do_search: {path=} {data=} {err_operation=}")
    result = client.http_request(url_suffix=path, data=data, err_operation=err_operation)
    return result


def run_search(
    client: Client,
    search_object: str,
    query: str,
    scope: Optional[str] = None,
    size: str = None,
    sort: str = None,
    order: str = None,
    artifact_source: str = None,
) -> dict:
    """
    This function searches the relevent search and returns search info for result command.
    Args:
        client: The client to make the requests with.
        search_object: Type of search sessions or samples.
        query: Query based on conditions specified within this object.
        scope:  Scope of the search. Only available and required for: samples. e.g. Public, Global, Private.
        size: Number of results to provide.
        sort: Sort based on the provided artifact.
        order: How to display sort results in ascending or descending order.
        artifact_source: Whether artifacts are wanted or not.
    Returns:
        dict of response for result commands.
    """
    result = do_search(
        client,
        search_object,
        query=json.loads(query),
        scope=scope,
        size=size,
        sort=sort,
        order=order,
        artifact_source=artifact_source,
        err_operation="Search operation failed",
    )
    in_progress = result.get("af_in_progress")
    status = "in progress" if in_progress else "complete"
    search_info = {
        "AFCookie": result.get("af_cookie"),
        "Status": status,
        "SessionStart": datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
    }
    return search_info


def run_get_search_results(client: Client, search_object, af_cookie):
    path = f"/samples/results/{af_cookie}" if search_object == "samples" else f"/sessions/results/{af_cookie}"
    results = client.http_request(url_suffix=path, err_operation="Fetching search results failed")
    return results


def get_fields_from_hit_object(result_object, response_dict_name):
    new_object = {}
    af_params_dict = API_PARAM_DICT.get(response_dict_name)
    for key, value in result_object.items():
        if key in af_params_dict:  # type: ignore
            new_key = af_params_dict.get(key)  # type: ignore
            new_object[new_key] = value
        else:
            new_object[key] = value
    return new_object


def parse_hits_response(hits, response_dict_name):
    parsed_objects = []  # type: ignore
    if not hits:
        return parsed_objects
    else:
        for hit in hits:
            flattened_obj = {}  # type: ignore
            flattened_obj.update(hit.get("_source"))
            flattened_obj["_id"] = hit.get("_id")
            parsed_obj = get_fields_from_hit_object(flattened_obj, response_dict_name)
            parsed_objects.append(parsed_obj)
        return parsed_objects


def get_search_results(client: Client, search_object, af_cookie):
    results = run_get_search_results(client, search_object, af_cookie)
    retry_count = 0
    # Checking if the query has no results because the server has not fetched them yet.
    # In this case, the complete percentage would be 0 (or lower than 100).
    # In a case where there really aren't results (hits), the af_complete_percentage would be 100.
    while (not results.get("hits") and (results.get("af_complete_percentage", 0) != 100)) and retry_count < 10:
        time.sleep(5)
        results = run_get_search_results(client, search_object, af_cookie)
        retry_count += 1
    parsed_results = parse_hits_response(results.get("hits"), "search_results")
    in_progress = results.get("af_in_progress")
    status = "in progress" if in_progress else "complete"
    return parsed_results, status


def get_session_details(client: Client, session_id):
    path = f"/session/{session_id}"
    result = client.http_request(url_suffix=path, err_operation="Get session failed")
    parsed_result = parse_hits_response(result.get("hits"), "search_results")
    return parsed_result


def validate_if_line_needed(category, info_line):
    line = info_line.get("line")
    line_values = line.split(",")
    category_indexes = SAMPLE_ANALYSIS_LINE_KEYS.get(category).get("indexes")  # type: ignore
    if category == "behavior":
        risk_index = category_indexes.get("risk")  # type: ignore
        risk = line_values[risk_index].strip()
        # only lines with risk higher the informational are considered
        return risk != "informational"
    elif category == "registry":
        action_index = category_indexes.get("action")  # type: ignore
        action = line_values[action_index].strip()
        # Only lines with actions SetValueKey, CreateKey or RegSetValueEx are considered
        return action in ("SetValueKey", "CreateKey", "RegSetValueEx")
    elif category == "file":
        action_index = category_indexes.get("action")  # type: ignore
        action = line_values[action_index].strip()
        benign_count = info_line.get("b") if info_line.get("b") else 0
        malicious_count = info_line.get("m") if info_line.get("m") else 0
        # Only lines with actions Create or CreateFileW where malicious count is grater than benign count are considered
        return action in ("Create", "CreateFileW") and malicious_count > benign_count
    elif category == "process":
        action_index = category_indexes.get("action")  # type: ignore
        action = line_values[action_index].strip()
        # Only lines with actions created, CreateKey or CreateProcessInternalW are considered
        return action in ("created", "CreateProcessInternalW")
    else:
        return True


def get_data_from_line(line, category_name):
    category_indexes = SAMPLE_ANALYSIS_LINE_KEYS.get(category_name).get("indexes")  # type: ignore
    values = line.split(",")
    sub_categories = {}  # type: ignore
    if not category_indexes:
        return sub_categories
    else:
        for sub_category in category_indexes:  # type: ignore
            sub_category_index = category_indexes.get(sub_category)  # type: ignore
            sub_categories.update({sub_category: values[sub_category_index]})
        return sub_categories


def get_data_from_coverage_sub_category(sub_category_name, sub_category_data):
    sub_categories_list = []
    for item in sub_category_data:
        new_sub_category = {}
        fields_to_extract = SAMPLE_ANALYSIS_COVERAGE_KEYS.get(sub_category_name).get("fields")  # type: ignore
        for field in fields_to_extract:  # type: ignore
            new_sub_category[field] = item.get(field)  # type: ignore
        sub_categories_list.append(new_sub_category)
    return sub_categories_list


def parse_coverage_sub_categories(coverage_data):
    new_coverage = {}
    for sub_category_name, sub_category_data in coverage_data.items():
        if sub_category_name in SAMPLE_ANALYSIS_COVERAGE_KEYS and isinstance(sub_category_data, dict):
            new_sub_category_data = get_data_from_coverage_sub_category(sub_category_name, sub_category_data)
            new_sub_category_name = SAMPLE_ANALYSIS_COVERAGE_KEYS.get(sub_category_name).get(  # type: ignore
                "display_name"
            )  # type: ignore
            new_coverage[new_sub_category_name] = new_sub_category_data
    return {"coverage": new_coverage}


def parse_lines_from_os(category_name, data, filter_data_flag):
    new_lines = []
    for info_line in data:
        if not filter_data_flag or validate_if_line_needed(category_name, info_line):
            new_sub_categories = get_data_from_line(info_line.get("line"), category_name)
            new_lines.append(new_sub_categories)
    return new_lines


def parse_sample_analysis_response(resp, filter_data_flag):
    analysis = {}
    for category_name, category_data in resp.items():
        if category_name in SAMPLE_ANALYSIS_LINE_KEYS:
            new_category = {}
            for os_name, os_data in category_data.items():
                os_sanitized_data = parse_lines_from_os(category_name, os_data, filter_data_flag)
                new_category[os_name] = os_sanitized_data

            category_dict = SAMPLE_ANALYSIS_LINE_KEYS.get(category_name)
            analysis.update({category_dict["display_name"]: new_category})  # type: ignore

        elif category_name == "coverage":
            new_category = parse_coverage_sub_categories(category_data)
            analysis.update(new_category)

    return analysis


def sample_analysis(client: Client, sample_id, os, filter_data_flag):
    path = f"/sample/{sample_id}/analysis"
    data = {"coverage": "true"}
    if os:
        data["platforms"] = [os]  # type: ignore

    result = client.http_request(url_suffix=path, data=data, err_operation="Sample analysis failed")
    if "error" in result:
        return demisto.results(result["error"])
    analysis_obj = parse_sample_analysis_response(result, filter_data_flag)

    return analysis_obj


def parse_tag_details_response(resp):
    tag_details = resp.get("tag")
    fields_to_extract_from_tag_details = [
        "public_tag_name",
        "tag_name",
        "customer_name",
        "source",
        "tag_definition_scope",
        "tag_definition_status",
        "tag_class",
        "count",
        "lasthit",
        "description",
    ]
    new_tag_info = {}
    for field in fields_to_extract_from_tag_details:
        new_tag_info[field] = tag_details.get(field)

    tag_group_details = resp.get("tag_groups")
    if tag_group_details:
        new_tag_info["tag_group"] = tag_group_details

    return new_tag_info


def autofocus_tag_details(client: Client, tag_name):
    path = f"/tag/{tag_name}"
    resp = client.http_request(url_suffix=path, err_operation="Tag details operation failed")
    tag_info = parse_tag_details_response(resp)
    return tag_info


def validate_tag_scopes(private, public, commodity, unit42):
    if not any((private, public, commodity, unit42)):
        raise DemistoException("Add at least one Tag scope by setting `commodity`, `private`, `public` or `unit42` to True")


def autofocus_top_tags_search(client: Client, scope, tag_class_display, private, public, commodity, unit42):
    validate_tag_scopes(private, public, commodity, unit42)
    tag_class = API_PARAM_DICT["tag_class"][tag_class_display]  # type: ignore
    query = {"operator": "all", "children": [{"field": "sample.tag_class", "operator": "is", "value": tag_class}]}
    tag_scopes = []
    if private:
        tag_scopes.append("private")
    if public:
        tag_scopes.append("public")
    if commodity:
        tag_scopes.append("commodity")
    if unit42:
        tag_scopes.append("unit42")
    data = {"query": query, "scope": scope, "tagScopes": tag_scopes}
    path = "/top-tags/search/"
    resp = client.http_request(url_suffix=path, data=data, err_operation="Top tags operation failed")
    in_progress = resp.get("af_in_progress")
    status = "in progress" if in_progress else "complete"
    search_info = {"AFCookie": resp.get("af_cookie"), "Status": status}
    return search_info


def parse_top_tags_response(response):
    top_tags_list = []  # type: ignore
    top_tags = response.get("top_tags")
    if not top_tags:
        return top_tags_list
    else:
        for tag in top_tags:
            fields_to_extract_from_top_tags = ["tag_name", "public_tag_name", "count", "lasthit"]
            new_tag = {}
            for field in fields_to_extract_from_top_tags:
                new_tag[field] = tag[field]
            top_tags_list.append(new_tag)
        return top_tags_list


def get_top_tags_results(client: Client, af_cookie):
    path = f"/top-tags/results/{af_cookie}"
    results = client.http_request(url_suffix=path, err_operation="Fetching top tags results failed")
    top_tags = parse_top_tags_response(results)
    in_progress = results.get("af_in_progress")
    status = "in progress" if in_progress else "complete"
    return top_tags, status


def print_hr_by_category(category_name, category_data):
    hr = content = f"### {string_to_table_header(category_name)}:\nNo entries"
    if category_name == "coverage":
        content = category_data
        if category_data:
            hr = tableToMarkdown(
                f"{string_to_table_header(category_name)}:", category_data, headerTransform=string_to_table_header
            )
        else:
            hr = f"### {string_to_table_header(category_name)}:\nNo entries"
        demisto.results({"Type": entryTypes["note"], "ContentsFormat": formats["text"], "Contents": content, "HumanReadable": hr})
    else:
        for os_name, os_data in category_data.items():
            content = os_data
            table_header = f"{category_name}_{os_name}"
            if os_data:
                hr = tableToMarkdown(f"{string_to_table_header(table_header)}:", os_data, headerTransform=string_to_table_header)
            else:
                hr = f"### {string_to_table_header(table_header)}:\nNo entries"
            demisto.results(
                {"Type": entryTypes["note"], "ContentsFormat": formats["text"], "Contents": content, "HumanReadable": hr}
            )


def get_files_data_from_results(results):
    """
    Gets a list of results and for each result returns a file object includes all relevant file indicators exists
    in that result
    :param results: a list of dictionaries
    :return: a list of file objects
    """
    files = []
    if results:
        for result in results:
            raw_file = get_fields_from_hit_object(result, "file_indicators")
            file_data = filter_object_entries_by_dict_values(raw_file, "file_indicators")
            files.append(file_data)
    return files


def filter_object_entries_by_dict_values(result_object, response_dict_name):
    """
    Gets a dictionary (result_object) and filters it's keys by the values of another
    dictionary (response_dict_name)
    input: response_dict_name = 'file_indicators' - see API_PARAM_DICT above
           result_object = {
                              "app": "web-browsing",
                              "vsys": 1,
                              "SHA256": "18c9acd34a3aea09121f027857e0004a3ea33a372b213a8361e8a978330f0dc8",
                              "UploadSource": "Firewall",
                              "src_port": 80,
                              "device_serial": "007051000050926",
                              "Seen": "2019-07-24T09:37:04",
                              "Name": "wildfire-test-pe-file.exe",
                              "user_id": "unknown",
                              "src_country": "United States",
                              "src_countrycode": "US",
                              "dst_port": 65168,
                              "device_countrycode": "US",
                              "Industry": "High Tech",
                              "Region": "us",
                              "device_country": "United States",
                              "ID": "179972200903"
                            }
    output: {
                "SHA256": "18c9acd34a3aea09121f027857e0004a3ea33a372b213a8361e8a978330f0dc8",
                "Name": "wildfire-test-pe-file.exe"
            }
    :param result_object: a dictionary representing an object
    :param response_dict_name: a dictionary which it's values are the relevant fields (filters)
    :return: the result_object filtered by the relevant fields
    """
    af_params_dict = API_PARAM_DICT.get(response_dict_name)
    result_object_filtered = {}
    if af_params_dict and isinstance(result_object, dict) and isinstance(af_params_dict, dict):
        for key in result_object:
            if key in af_params_dict.values():  # type: ignore
                result_object_filtered[key] = result_object.get(key)
    return result_object_filtered


def search_samples(
    client: Client,
    query=None,
    scope=None,
    size=None,
    sort=None,
    order=None,
    file_hash=None,
    domain=None,
    ip=None,
    url=None,
    wildfire_verdict=None,
    first_seen=None,
    last_updated=None,
    artifact_source=None,
    use_batches=False,
):
    validate_no_query_and_indicators(query, [file_hash, domain, ip, url, wildfire_verdict, first_seen, last_updated])
    if not query:
        indicator_args_for_query = {"file_hash": file_hash, "domain": domain, "ip": ip, "url": url}
        used_indicator = validate_no_multiple_indicators_for_search(indicator_args_for_query)
        if use_batches:
            search_result = []
            for _batch in batch(indicator_args_for_query[used_indicator], batch_size=100):
                query = build_sample_search_query(used_indicator, _batch, wildfire_verdict, first_seen, last_updated)
                search_result.append(
                    run_search(
                        client,
                        "samples",
                        query=query,
                        scope=scope,
                        size=size,
                        sort=sort,
                        order=order,
                        artifact_source=artifact_source,
                    )
                )
            return search_result
        indicators = indicator_args_for_query[used_indicator]
        query = build_sample_search_query(used_indicator, indicators, wildfire_verdict, first_seen, last_updated)

    return run_search(
        client, "samples", query=query, scope=scope, size=size, sort=sort, order=order, artifact_source=artifact_source
    )


def build_sample_search_query(used_indicator, indicators_values, wildfire_verdict, first_seen, last_updated):
    indicator_list = build_indicator_children_query(used_indicator, indicators_values)
    indicator_query = build_logic_query("OR", indicator_list)
    filtering_args_for_search = {}  # type: ignore
    if wildfire_verdict:
        filtering_args_for_search["wildfire_verdict"] = demisto.get(
            API_PARAM_DICT, f"search_arguments.wildfire_verdict.translate.{wildfire_verdict}"
        )
    if first_seen:
        filtering_args_for_search["first_seen"] = first_seen
    if last_updated:
        filtering_args_for_search["last_updated"] = last_updated
    filters_list = build_children_query(filtering_args_for_search)
    filters_list.append(indicator_query)
    logic_query = build_logic_query("AND", filters_list)
    return json.dumps(logic_query)


def search_sessions(
    client: Client,
    query=None,
    size=None,
    sort=None,
    order=None,
    file_hash=None,
    domain=None,
    ip=None,
    url=None,
    from_time=None,
    to_time=None,
    use_batches=False,
):
    validate_no_query_and_indicators(query, [file_hash, domain, ip, url, from_time, to_time])
    if not query:
        indicator_args_for_query = {"file_hash": file_hash, "domain": domain, "ip": ip, "url": url}
        used_indicator = validate_no_multiple_indicators_for_search(indicator_args_for_query)
        if use_batches:
            search_result = []
            for _batch in batch(indicator_args_for_query[used_indicator], batch_size=100):
                query = build_session_search_query(used_indicator, _batch, from_time, to_time)
                search_result.append(run_search(client, "sessions", query=query, size=size, sort=sort, order=order))
            return search_result

        indicators = indicator_args_for_query[used_indicator]
        query = build_session_search_query(used_indicator, indicators, from_time, to_time)

    return run_search(client, "sessions", query=query, size=size, sort=sort, order=order)


def build_session_search_query(used_indicator, indicators_batch, from_time, to_time):
    indicator_list = build_indicator_children_query(used_indicator, indicators_batch)
    indicator_query = build_logic_query("OR", indicator_list)
    time_filters_for_search = {}  # type: ignore
    if from_time and to_time:
        time_filters_for_search = {"time_range": [from_time, to_time]}
    elif from_time:
        time_filters_for_search = {"time_after": [from_time]}
    elif to_time:
        time_filters_for_search = {"time_before": [to_time]}

    filters_list = build_children_query(time_filters_for_search)
    filters_list.append(indicator_query)
    logic_query = build_logic_query("AND", filters_list)
    return json.dumps(logic_query)


def build_logic_query(logic_operator, condition_list):
    return {"operator": {"AND": "all", "OR": "any"}.get(logic_operator), "children": condition_list}


def build_children_query(args_for_query):
    children_list = []  # type: ignore
    for key, val in args_for_query.items():
        field_api_name = API_PARAM_DICT["search_arguments"][key]["api_name"]  # type: ignore
        operator = API_PARAM_DICT["search_arguments"][key]["operator"]  # type: ignore
        children_list += children_list_generator(field_api_name, operator, [val])
    return children_list


def build_indicator_children_query(used_indicator, indicators_values):
    if indicators_values:
        field_api_name = API_PARAM_DICT["search_arguments"][used_indicator]["api_name"]  # type: ignore
        operator = API_PARAM_DICT["search_arguments"][used_indicator]["operator"]  # type: ignore
        children_list = children_list_generator(field_api_name, operator, indicators_values)
    else:
        children_list = []
        demisto.debug(f"{indicators_values=} -> {children_list=}")
    return children_list


def children_list_generator(field_name, operator, val_list):
    query_list = []
    for value in val_list:
        query_list.append({"field": field_name, "operator": operator, "value": value})
    return query_list


def validate_no_query_and_indicators(query, arg_list):
    if query and any(arg_list):
        raise DemistoException(
            "The search command can either run a search using a custom query or use the builtin arguments, but not both"
        )


def validate_no_multiple_indicators_for_search(arg_dict):
    used_arg = None
    for arg, val in arg_dict.items():
        if val and used_arg:
            raise DemistoException(
                f"The search command can receive one indicator type at a time, two were given: {used_arg}, {arg}."
                " For multiple indicator types use the custom query"
            )
        elif val:
            used_arg = arg
    if not used_arg:
        raise DemistoException("In order to perform a samples/sessions search, a query or an indicator must be given.")
    return used_arg


def search_indicator(client, indicator_type, indicator_value):
    headers = HEADERS | {"apiKey": API_KEY}

    params = {
        "indicatorType": indicator_type,
        "indicatorValue": indicator_value,
        "includeTags": "true",
    }

    demisto.debug(f"search_indicator: {indicator_value=}")
    result = Response()
    try:
        # 404, 409, 503 a list of status codes that we want to handle in the code and not raise automatic exception about.
        ok_codes = (200, 404, 409, 503)
        demisto.debug(f"search_indicator: using the client with {ok_codes=}")
        result = client.http_request(method="GET", url_suffix="/tic", headers=headers, params=params, ok_codes=ok_codes)
        demisto.debug(f"search_indicator: {result.status_code=} {result=}")

        try:
            result_json = result.json()
        except ValueError:
            result_json = {}
        demisto.debug(f"search_indicator {result_json=}")

        save_api_metrics(result_json)
        if result.status_code == 503:
            demisto.debug("search_indicator: result.status_code == 503")
            EXECUTION_METRICS.quota_error += 1
            raise RateLimitExceededError(result_json)

        # Handle error responses gracefully
        result.raise_for_status()

    # Handle with connection error
    except requests.exceptions.ConnectionError as err:
        demisto.debug("search_indicator: in requests.exceptions.ConnectionError")
        EXECUTION_METRICS.connection_error += 1
        raise DemistoException(f"Error connecting to server. Check your URL/Proxy/Certificate settings: {err}")

    # Unexpected errors (where no json object was received)
    except Exception as err:
        demisto.debug(f"search_indicator: Unexpected errors {err}")
        EXECUTION_METRICS.general_error += 1
        try:
            if demisto.params().get("handle_error", True) and (result.status_code == 404 or result.status_code == 409):
                return {
                    "indicator": {
                        "indicatorType": indicator_type,
                        "indicatorValue": indicator_value,
                        "latestPanVerdicts": {"PAN_DB": "UNKNOWN"},
                    }
                }
            text_error = result.json()
        except ValueError:
            text_error = {}
        error_message = text_error.get("message")
        if error_message:
            raise DemistoException(f"Request Failed with status: {result.status_code}.\nReason is: {error_message}.")
        elif result.status_code in ERROR_DICT:
            raise DemistoException(
                f"Request Failed with status: {result.status_code}.\nReason is: {ERROR_DICT[result.status_code]}."
            )
        else:
            err_msg = f"Request Failed with message: {err}."
        raise DemistoException(err_msg)

    EXECUTION_METRICS.success += 1
    return result_json


def parse_indicator_response(res, raw_tags, indicator_type):
    indicator = {}
    indicator["IndicatorValue"] = res.get("indicatorValue", "")
    indicator["IndicatorType"] = res.get("indicatorType", "")
    indicator["LatestPanVerdicts"] = res.get("latestPanVerdicts", "")
    indicator["WildfireRelatedSampleVerdictCounts"] = res.get("wildfireRelatedSampleVerdictCounts", "")
    indicator["SeenBy"] = res.get("seenByDataSourceIds", "")

    first_seen = res.get("firstSeenTsGlobal", "")
    last_seen = res.get("lastSeenTsGlobal", "")

    if first_seen:
        indicator["FirstSeen"] = timestamp_to_datestring(first_seen)
    if last_seen:
        indicator["LastSeen"] = timestamp_to_datestring(last_seen)

    if raw_tags:
        tags = []
        for tag in raw_tags:
            tags.append(
                {
                    "PublicTagName": tag.get("public_tag_name", ""),
                    "TagName": tag.get("tag_name", ""),
                    "CustomerName": tag.get("customer_name", ""),
                    "Source": tag.get("source", ""),
                    "TagDefinitionScopeID": tag.get("tag_definition_scope_id", ""),
                    "TagDefinitionStatusID": tag.get("tag_definition_status_id", ""),
                    "TagClassID": tag.get("tag_class_id", ""),
                    "Count": tag.get("count", ""),
                    "Lasthit": tag.get("lasthit", ""),
                    "Description": tag.get("description", ""),
                }
            )
        indicator["Tags"] = tags

    if indicator_type == "Domain":
        indicator["WhoisAdminCountry"] = res.get("whoisAdminCountry", "")
        indicator["WhoisAdminEmail"] = res.get("whoisAdminEmail", "")
        indicator["WhoisAdminName"] = res.get("whoisAdminName", "")
        indicator["WhoisDomainCreationDate"] = res.get("whoisDomainCreationDate", "")
        indicator["WhoisDomainExpireDate"] = res.get("whoisDomainExpireDate", "")
        indicator["WhoisDomainUpdateDate"] = res.get("whoisDomainUpdateDate", "")
        indicator["WhoisRegistrar"] = res.get("whoisRegistrar", "")
        indicator["WhoisRegistrarUrl"] = res.get("whoisRegistrarUrl", "")
        indicator["WhoisRegistrant"] = res.get("whoisRegistrant", "")

    return indicator


def calculate_dbot_score(indicator_response, indicator_type):
    latest_pan_verdicts = indicator_response["latestPanVerdicts"]
    if not latest_pan_verdicts:
        raise Exception("latestPanVerdicts value is empty in indicator response.")

    pan_db = latest_pan_verdicts.get("PAN_DB")
    wf_sample = latest_pan_verdicts.get("WF_SAMPLE")

    # use WF_SAMPLE value for file indicator and PAN_DB for domain,url and ip indicators
    if indicator_type == "File" and wf_sample:
        return VERDICTS_TO_DBOTSCORE.get(wf_sample.lower(), 0)
    elif pan_db:
        return VERDICTS_TO_DBOTSCORE.get(pan_db.lower(), 0)
    else:
        score = next(iter(latest_pan_verdicts.values()))
        if score:
            return VERDICTS_TO_DBOTSCORE.get(score.lower(), 0)
        return 0


def check_for_ip(indicator):
    if "-" in indicator:
        # check for address range
        ip1, ip2 = indicator.split("-", 1)

        if re.match(ipv4Regex, ip1) and re.match(ipv4Regex, ip2):
            return FeedIndicatorType.IP

        elif re.match(ipv6Regex, ip1) and re.match(ipv6Regex, ip2):
            return FeedIndicatorType.IPv6

        elif re.match(ipv4cidrRegex, ip1) and re.match(ipv4cidrRegex, ip2):
            return FeedIndicatorType.CIDR

        elif re.match(ipv6cidrRegex, ip1) and re.match(ipv6cidrRegex, ip2):
            return FeedIndicatorType.IPv6CIDR

        return None

    if "/" in indicator:
        if re.match(ipv4cidrRegex, indicator):
            return FeedIndicatorType.CIDR

        elif re.match(ipv6cidrRegex, indicator):
            return FeedIndicatorType.IPv6CIDR

        return None

    else:
        if re.match(ipv4Regex, indicator):
            return FeedIndicatorType.IP

        elif re.match(ipv6Regex, indicator):
            return FeedIndicatorType.IPv6

    return None


def find_indicator_type(indicator):
    """Infer the type of the indicator.

    Args:
        indicator(str): The indicator whose type we want to check.

    Returns:
        str. The type of the indicator.
    """
    # trying to catch X.X.X.X:portNum
    if ":" in indicator and "/" not in indicator:
        sub_indicator = indicator.split(":", 1)[0]
        ip_type = check_for_ip(sub_indicator)
        if ip_type:
            return ip_type

    ip_type = check_for_ip(indicator)

    if ip_type:
        # catch URLs of type X.X.X.X/path/url or X.X.X.X:portNum/path/url
        if "/" in indicator and (ip_type not in [FeedIndicatorType.IPv6CIDR, FeedIndicatorType.CIDR]):
            return FeedIndicatorType.URL

        else:
            return ip_type

    elif re.match(sha256Regex, indicator):
        return FeedIndicatorType.File

    # in AutoFocus, URLs include a path while domains do not - so '/' is a good sign for us to catch URLs.
    elif "/" in indicator:
        return FeedIndicatorType.URL

    else:
        return FeedIndicatorType.Domain


def resolve_ip_address(ip):
    if check_for_ip(ip):
        return socket.gethostbyaddr(ip)[0]

    return None


def convert_url_to_ascii_character(url_name):
    def convert_non_ascii_chars(non_ascii):
        # converts non-ASCII chars to IDNA notation
        return str(non_ascii.group(0)).encode("idna").decode("utf-8")

    # Regex to catch all non ascii chars (from 0 to 127 in hexadecimal).
    return re.sub(r"[^\x00-\x7F]+", convert_non_ascii_chars, url_name)


""" COMMANDS"""


def test_module(client: Client):
    """
    Performs basic get request to get item samples
    """
    query = {"operator": "all", "children": [{"field": "sample.malware", "operator": "is", "value": 1}]}
    demisto.debug("test-module")
    do_search(client, "samples", query=query, scope="Public", err_operation="Test module failed")


def search_samples_command(client: Client, args):
    file_hash = argToList(args.get("file_hash"))
    domain = argToList(args.get("domain"))
    ip = argToList(args.get("ip"))
    url = argToList(args.get("url"))
    wildfire_verdict = args.get("wildfire_verdict")
    first_seen = argToList(args.get("first_seen"))
    last_updated = argToList(args.get("last_updated"))
    query = args.get("query")
    scope = args.get("scope").capitalize()
    max_results = args.get("max_results")
    sort = args.get("sort")
    order = args.get("order")
    artifact_source = args.get("artifact")
    use_batches = args.get("use_batches")
    info = search_samples(
        client,
        query=query,
        scope=scope,
        size=max_results,
        sort=sort,
        order=order,
        file_hash=file_hash,
        domain=domain,
        ip=ip,
        url=url,
        wildfire_verdict=wildfire_verdict,
        first_seen=first_seen,
        last_updated=last_updated,
        artifact_source=artifact_source,
        use_batches=use_batches,
    )
    md = tableToMarkdown("Search Samples Info:", info)
    return CommandResults(
        outputs=info, readable_output=md, outputs_key_field="AFCookie", outputs_prefix="AutoFocus.SamplesSearch"
    )


def search_samples_with_polling_command(client: Client, args):
    return run_polling_command(client, args, "autofocus-search-samples", search_samples_command, samples_search_results_command)


def search_sessions_with_polling_command(client: Client, args):
    return run_polling_command(
        client, args, "autofocus-search-sessions", search_sessions_command, sessions_search_results_command
    )


def search_sessions_command(client: Client, args):
    file_hash = argToList(args.get("file_hash"))
    domain = argToList(args.get("domain"))
    ip = argToList(args.get("ip"))
    url = argToList(args.get("url"))
    from_time = args.get("time_after")
    to_time = args.get("time_before")
    time_range = args.get("time_range")
    query = args.get("query")
    max_results = args.get("max_results")
    sort = args.get("sort")
    order = args.get("order")
    use_batches = args.get("use_batches")

    if time_range:
        if from_time or to_time:
            raise DemistoException(
                "The 'time_range' argument cannot be specified with neither 'time_after' nor 'time_before' arguments."
            )
        else:
            from_time, to_time = time_range.split(",")

    info = search_sessions(
        client,
        query=query,
        size=max_results,
        sort=sort,
        order=order,
        file_hash=file_hash,
        domain=domain,
        ip=ip,
        url=url,
        from_time=from_time,
        to_time=to_time,
        use_batches=use_batches,
    )
    md = tableToMarkdown("Search Sessions Info:", info)
    cmd_results = CommandResults(
        outputs_prefix="AutoFocus.SessionsSearch", outputs_key_field="AFCookie", outputs=info, readable_output=md
    )
    return cmd_results


def samples_search_results_command(client: Client, args):
    af_cookie = args.get("af_cookie")
    results, status = get_search_results(client, "samples", af_cookie)
    files = get_files_data_from_results(results)
    hr = ""
    if not results or len(results) == 0:
        hr = "No entries found that match the query" if status == "complete" else f"Search Sessions Results is {status}"
    context = {
        "AutoFocus.SamplesResults(val.ID === obj.ID)": results,
        "AutoFocus.SamplesSearch(val.AFCookie === obj.AFCookie)": {"Status": status, "AFCookie": af_cookie},
        outputPaths["file"]: files,
    }
    if not results:
        return_outputs(readable_output=hr, outputs=context, raw_response={})
    else:
        # for each result a new entry will be set with two tables, one of the result and one of its artifacts
        for result in results:
            if "Artifact" in result:
                hr = samples_search_result_hr(result, status)
                return_outputs(readable_output=hr, outputs=context, raw_response=results)
            else:
                hr = tableToMarkdown(f"Search Samples Result is {status}", result)
                hr += tableToMarkdown("Artifacts for Sample: ", [])
                return_outputs(readable_output=hr, outputs=context, raw_response=results)
    return None, status


def samples_search_result_hr(result: dict, status: str) -> str:
    """
    Creates human readable output for a specific entry which contains two tables, one for the result's
    and another for the artifacts that are related to it.
    Args:
        result: one result of the search sample command.
        status: status of result command.
    Returns:
        human readable of two tables for this result.
    """
    artifact = result.pop("Artifact")
    updated_artifact = []
    for indicator in artifact:
        # Filter on returned indicator types, as we do not support Mutex and User Agent.
        if "Mutex" not in indicator.get("indicator_type") and "User Agent" not in indicator.get("indicator_type"):
            updated_artifact.append(indicator)
    hr = "\n\n".join(
        (
            tableToMarkdown(f"Search Samples Result is {status}", result),
            tableToMarkdown(
                "Artifacts for Sample: ", updated_artifact, headers=["b", "g", "m", "indicator_type", "confidence", "indicator"]
            ),
        )
    )
    return hr


def sessions_search_results_command(client: Client, args):
    af_cookie = args.get("af_cookie")
    results, status = get_search_results(client, "sessions", af_cookie)
    files = get_files_data_from_results(results)
    if not results or len(results) == 0:
        md = results = "No entries found that match the query"
    else:
        md = tableToMarkdown(f"Search Samples Results is {status}", results)
    context = {
        "AutoFocus.SessionsResults(val.ID === obj.ID)": results,
        "AutoFocus.SessionsSearch(val.AFCookie === obj.AFCookie)": {"Status": status, "AFCookie": af_cookie},
        outputPaths["file"]: files,
    }
    return CommandResults(outputs=context, raw_response=results, readable_output=md), status


def get_session_details_command(client: Client):
    args = demisto.args()
    session_id = args.get("session_id")
    result = get_session_details(client, session_id)
    files = get_files_data_from_results(result)
    md = tableToMarkdown(f"Session {session_id}:", result)
    context = {"AutoFocus.Sessions(val.ID === obj.ID)": result, outputPaths["file"]: files}
    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": result,
            "EntryContext": context,
            "HumanReadable": md,
        }
    )


def sample_analysis_command(client: Client):
    args = demisto.args()
    sample_id = args.get("sample_id")
    os = args.get("os")
    filter_data = args.get("filter_data") != "False"
    analysis = sample_analysis(client, sample_id, os, filter_data)
    context = createContext(analysis, keyTransform=string_to_context_key)
    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": {"ID": sample_id, "Analysis": analysis},
            "HumanReadable": f"### Sample Analysis results for {sample_id}:",
            "EntryContext": {"AutoFocus.SampleAnalysis(val.ID == obj.ID)": {"ID": sample_id, "Analysis": context}},
        }
    )
    for category_name, category_data in analysis.items():
        print_hr_by_category(category_name, category_data)


def tag_details_command(client: Client):
    args = demisto.args()
    tag_name = args.get("tag_name")
    result = autofocus_tag_details(client, tag_name)
    md = tableToMarkdown(f"Tag {tag_name} details:", result, headerTransform=string_to_table_header)
    context = createContext(result, keyTransform=string_to_context_key)
    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": result,
            "EntryContext": {"AutoFocus.Tag(val.ID == obj.ID)": context},
            "HumanReadable": md,
        }
    )


def top_tags_search_command(client: Client, args):
    scope = args.get("scope")
    tag_class = args.get("class")
    private = args.get("private") == "True"
    public = args.get("public") == "True"
    commodity = args.get("commodity") == "True"
    unit42 = args.get("unit42") == "True"
    info = autofocus_top_tags_search(client, scope, tag_class, private, public, commodity, unit42)
    md = tableToMarkdown("Top tags search Info:", info)
    return CommandResults(
        outputs_prefix="AutoFocus.TopTagsSearch", outputs_key_field="AFCookie", outputs=info, readable_output=md
    )


def top_tags_results_command(client: Client, args) -> tuple[CommandResults, str]:
    af_cookie = args.get("af_cookie")
    results, status = get_top_tags_results(client, af_cookie)
    md = tableToMarkdown(f"Search Top Tags Results is {status}:", results, headerTransform=string_to_table_header)
    context = createContext(results, keyTransform=string_to_context_key)
    outputs = {
        "AutoFocus.TopTagsResults(val.PublicTagName === obj.PublicTagName)": context,
        "AutoFocus.TopTagsSearch(val.AFCookie === obj.AFCookie)": {"Status": status, "AFCookie": af_cookie},
    }
    return CommandResults(outputs=outputs, raw_response=results, readable_output=md), status


def top_tags_with_polling_command(client: Client, args):
    return run_polling_command(client, args, "autofocus-top-tags-search", top_tags_search_command, top_tags_results_command)


def search_ip_command(client, ip, reliability, create_relationships):
    indicator_type = "IP"
    ip_list = argToList(ip)

    command_results = []
    relationships = []

    for ip_address in ip_list:
        ip_type = "ipv6_address" if is_ipv6_valid(ip_address) else "ipv4_address"
        raw_res = search_indicator(client, ip_type, ip_address)

        indicator = raw_res.get("indicator")
        if indicator:
            raw_tags = raw_res.get("tags")

            score = calculate_dbot_score(indicator, indicator_type)
            dbot_score = Common.DBotScore(
                indicator=ip_address,
                indicator_type=DBotScoreType.IP,
                integration_name=VENDOR_NAME,
                score=score,
                reliability=reliability,
            )
            if create_relationships:
                relationships = create_relationships_list(
                    entity_a=ip_address, entity_a_type=indicator_type, tags=raw_tags, reliability=reliability
                )
            ip = Common.IP(
                ip=ip_address,
                dbot_score=dbot_score,
                malware_family=get_tags_for_tags_and_malware_family_fields(raw_tags, True),
                tags=get_tags_for_tags_and_malware_family_fields(raw_tags),
                relationships=relationships,
            )

            autofocus_ip_output = parse_indicator_response(indicator, raw_tags, indicator_type)

            # create human readable markdown for ip
            tags = autofocus_ip_output.get("Tags")
            table_name = f"{VENDOR_NAME} {indicator_type} reputation for: {ip_address}"
            if tags:
                indicators_data = autofocus_ip_output.copy()
                del indicators_data["Tags"]
                md = tableToMarkdown(table_name, indicators_data)
                md += tableToMarkdown("Indicator Tags:", tags)
            else:
                md = tableToMarkdown(table_name, autofocus_ip_output)
        else:
            dbot_score = Common.DBotScore(
                indicator=ip_address,
                indicator_type=DBotScoreType.IP,
                integration_name=VENDOR_NAME,
                score=0,
                reliability=reliability,
            )
            ip = Common.IP(
                ip=ip_address,
                dbot_score=dbot_score,
            )
            md = f"### The IP indicator: {ip_address} was not found in AutoFocus"
            autofocus_ip_output = {"IndicatorValue": ip_address}

        command_results.append(
            CommandResults(
                outputs_prefix="AutoFocus.IP",
                outputs_key_field="IndicatorValue",
                outputs=autofocus_ip_output,
                readable_output=md,
                raw_response=raw_res,
                indicator=ip,
                relationships=relationships,
            )
        )

    return command_results


def search_domain_command(client, domain, reliability, create_relationships):
    indicator_type = "Domain"
    domain_name_list = argToList(domain)

    command_results = []
    relationships = []

    for domain_name in domain_name_list:
        raw_res = search_indicator(client, "domain", domain_name)
        indicator = raw_res.get("indicator")

        if indicator:
            raw_tags = raw_res.get("tags")
            score = calculate_dbot_score(indicator, indicator_type)
            dbot_score = Common.DBotScore(
                indicator=domain_name,
                indicator_type=DBotScoreType.DOMAIN,
                integration_name=VENDOR_NAME,
                score=score,
                reliability=reliability,
            )
            if create_relationships:
                relationships = create_relationships_list(
                    entity_a=domain_name, entity_a_type=indicator_type, tags=raw_tags, reliability=reliability
                )
            domain = Common.Domain(
                domain=domain_name,
                dbot_score=dbot_score,
                # Converting date format from YYYY-MM-DD to DD-MM-YYYY due to a parsing problem on the server later
                creation_date="-".join((indicator.get("whoisDomainCreationDate") or "").split("-")[::-1]),
                expiration_date="-".join((indicator.get("whoisDomainExpireDate") or "").split("-")[::-1]),
                updated_date="-".join((indicator.get("whoisDomainUpdateDate") or "").split("-")[::-1]),
                admin_email=indicator.get("whoisAdminEmail"),
                admin_name=indicator.get("whoisAdminName"),
                admin_country=indicator.get("whoisAdminCountry"),
                registrar_name=indicator.get("whoisRegistrar"),
                registrant_name=indicator.get("whoisRegistrant"),
                malware_family=get_tags_for_tags_and_malware_family_fields(raw_tags, True),
                tags=get_tags_for_tags_and_malware_family_fields(raw_tags),
                relationships=relationships,
            )
            autofocus_domain_output = parse_indicator_response(indicator, raw_tags, indicator_type)
            # create human readable markdown for ip
            tags = autofocus_domain_output.get("Tags")
            table_name = f"{VENDOR_NAME} {indicator_type} reputation for: {domain_name}"
            if tags:
                indicators_data = autofocus_domain_output.copy()
                del indicators_data["Tags"]
                md = tableToMarkdown(table_name, indicators_data)
                md += tableToMarkdown("Indicator Tags:", tags)
            else:
                md = tableToMarkdown(table_name, autofocus_domain_output)
        else:
            dbot_score = Common.DBotScore(
                indicator=domain_name,
                indicator_type=DBotScoreType.DOMAIN,
                integration_name=VENDOR_NAME,
                score=0,
                reliability=reliability,
            )
            domain = Common.Domain(domain=domain_name, dbot_score=dbot_score)
            md = f"### The Domain indicator: {domain_name} was not found in AutoFocus"
            autofocus_domain_output = {"IndicatorValue": domain_name}

        command_results.append(
            CommandResults(
                outputs_prefix="AutoFocus.Domain",
                outputs_key_field="IndicatorValue",
                outputs=autofocus_domain_output,
                readable_output=md,
                raw_response=raw_res,
                indicator=domain,
                relationships=relationships,
            )
        )
    return command_results


def search_url_command(client, url, reliability, create_relationships, separator=","):
    indicator_type = "URL"
    url_list = argToList(url, separator)

    command_results = []
    relationships = []

    for url_name in url_list:
        raw_res = search_indicator(client, "url", convert_url_to_ascii_character(url_name))

        indicator = raw_res.get("indicator")
        if indicator:
            indicator["indicatorValue"] = url_name
            raw_tags = raw_res.get("tags")

            score = calculate_dbot_score(indicator, indicator_type)

            dbot_score = Common.DBotScore(
                indicator=url_name,
                indicator_type=DBotScoreType.URL,
                integration_name=VENDOR_NAME,
                score=score,
                reliability=reliability,
            )
            if create_relationships:
                relationships = create_relationships_list(
                    entity_a=url_name, entity_a_type=indicator_type, tags=raw_tags, reliability=reliability
                )
            url = Common.URL(
                url=url_name,
                dbot_score=dbot_score,
                malware_family=get_tags_for_tags_and_malware_family_fields(raw_tags, True),
                tags=get_tags_for_tags_and_malware_family_fields(raw_tags),
                relationships=relationships,
            )

            autofocus_url_output = parse_indicator_response(indicator, raw_tags, indicator_type)
            autofocus_url_output = {k: v for k, v in autofocus_url_output.items() if v}

            tags = autofocus_url_output.get("Tags")
            table_name = f"{VENDOR_NAME} {indicator_type} reputation for: {url_name}"
            if tags:
                indicators_data = autofocus_url_output.copy()
                del indicators_data["Tags"]
                md = tableToMarkdown(table_name, indicators_data)
                md += tableToMarkdown("Indicator Tags:", tags)
            else:
                md = tableToMarkdown(table_name, autofocus_url_output)
        else:
            dbot_score = Common.DBotScore(
                indicator=url_name,
                indicator_type=DBotScoreType.URL,
                integration_name=VENDOR_NAME,
                score=0,
                reliability=reliability,
            )
            url = Common.URL(url=url_name, dbot_score=dbot_score)
            md = f"### The URL indicator: {url_name} was not found in AutoFocus"
            autofocus_url_output = {"IndicatorValue": url_name}

        command_results.append(
            CommandResults(
                outputs_prefix="AutoFocus.URL",
                outputs_key_field="IndicatorValue",
                outputs=autofocus_url_output,
                readable_output=md,
                raw_response=raw_res,
                indicator=url,
                relationships=relationships,
            )
        )

    return command_results


def search_file_command(client, file, reliability, create_relationships):
    indicator_type = "File"
    file_list = argToList(file)

    command_results = []
    relationships = []

    for file_hash in file_list:
        raw_res = search_indicator(client, "filehash", file_hash.lower())

        indicator = raw_res.get("indicator")
        if indicator:
            raw_tags = raw_res.get("tags")

            score = calculate_dbot_score(indicator, indicator_type)
            dbot_score = Common.DBotScore(
                indicator=file_hash,
                indicator_type=DBotScoreType.FILE,
                integration_name=VENDOR_NAME,
                score=score,
                reliability=reliability,
            )
            if create_relationships:
                relationships = create_relationships_list(
                    entity_a=file_hash, entity_a_type=indicator_type, tags=raw_tags, reliability=reliability
                )
            autofocus_file_output = parse_indicator_response(indicator, raw_tags, indicator_type)

            tags = autofocus_file_output.get("Tags")
            table_name = f"{VENDOR_NAME} {indicator_type} reputation for: {file_hash}"
            if tags:
                indicators_data = autofocus_file_output.copy()
                del indicators_data["Tags"]
                md = tableToMarkdown(table_name, indicators_data)
                md += tableToMarkdown("Indicator Tags:", tags)
            else:
                md = tableToMarkdown(table_name, autofocus_file_output)

            hash_type = get_hash_type(file_hash)

            file = Common.File(
                md5=file_hash if hash_type == "md5" else None,
                sha1=file_hash if hash_type == "sha1" else None,
                sha256=file_hash if hash_type == "sha256" else None,
                dbot_score=dbot_score,
                malware_family=get_tags_for_tags_and_malware_family_fields(raw_tags, True),
                tags=get_tags_for_tags_and_malware_family_fields(raw_tags),
                relationships=relationships,
            )
        else:
            dbot_score = Common.DBotScore(
                indicator=file_hash,
                indicator_type=DBotScoreType.FILE,
                integration_name=VENDOR_NAME,
                score=0,
                reliability=reliability,
            )
            hash_type = get_hash_type(file_hash)
            hash_val_arg = {hash_type: file_hash}
            file = Common.File(dbot_score=dbot_score, **hash_val_arg)
            md = f"### The File indicator: {file_hash} was not found in AutoFocus"
            autofocus_file_output = {"IndicatorValue": file_hash}

        command_results.append(
            CommandResults(
                outputs_prefix="AutoFocus.File",
                outputs_key_field="IndicatorValue",
                outputs=autofocus_file_output,
                readable_output=md,
                raw_response=raw_res,
                indicator=file,
                relationships=relationships,
            )
        )

    return command_results


def get_tags_for_generic_context(tags: Optional[list]):
    if not tags:
        return None
    results = []
    keys = ["TagGroups", "Aliases", "PublicTagName", "TagName"]
    sub_keys = ["TagGroupName"]
    for item in tags:
        generic_context_tags = {key: item.get(key) for key in keys}
        generic_context_tags["tagGroups"] = {key: item.get(key) for key in sub_keys}
        results.append(remove_empty_elements(generic_context_tags))
    return results


def get_tags_for_tags_and_malware_family_fields(tags: Optional[list], is_malware_family=False):
    """get specific tags for the tags and malware_family fields
    Args
        tags (Optional[list]): tags from the response
        is_malware_family (bool): indicating whether it is for the malware_family field
    return:
        List[str]: list of tags without duplicates and empty elements
    """
    if not tags:
        return None
    results = []
    for item in tags:
        results.append(item.get("tag_name"))
        results.append(item.get("public_tag_name"))
        for alias in item.get("aliases", []):
            results.append(alias)
        if not is_malware_family:
            for group in item.get("tagGroups", [{}]):
                results.append(group.get("tag_group_name"))
    # Returns a list without duplicates and empty elements
    return list(set(filter(None, results)))


def create_relationships_list(entity_a, entity_a_type, tags, reliability):
    """
    Create a list of relationships objects from the tags.

    entity_a (str): the entity a of the relation which is the current indicator.
    entity_a_type (str): the entity a type which is the type of the current indicator (IP/Domain/URL/File)
    tags (list): list of tags returned from the api.
    reliability (str): reliability of the source.

    return:
    list of EntityRelationship objects containing all the relationships from the enricher.
    """
    if not tags:
        return []
    relationships = []
    for tag in tags:
        tag_class = tag.get("tag_class_id")
        entity_b = tag.get("tag_name")
        relation_by_type = RELATIONSHIP_TYPE_BY_TAG_CLASS_ID.get(tag_class)
        if entity_b and relation_by_type:
            relationships.append(
                EntityRelationship(
                    relation_by_type.get("name"),
                    entity_a=entity_a,
                    entity_a_type=entity_a_type,
                    entity_b=entity_b,
                    entity_b_type=FeedIndicatorType.indicator_type_by_server_version(relation_by_type.get("entity_b_type")),
                    source_reliability=reliability,
                    brand=VENDOR_NAME,
                )
            )

    return relationships


def get_export_list_command(client: Client, args):
    # the label is the name of the export list we want to fetch.
    # panosFormatted is a flag stating that only indicators should be returned in the list.
    data = {"label": args.get("label"), "panosFormatted": True, "apiKey": ""}

    results = client.http_request(
        url_suffix="/export", method="POST", data=data, err_operation=f"Failed to fetch export list: {args.get('label')}"
    )

    indicators = []
    context_ip = []
    context_url = []
    context_domain = []
    context_file = []
    for indicator_value in results.get("export_list"):
        indicator_type = find_indicator_type(indicator_value)
        if indicator_type in [FeedIndicatorType.IP, FeedIndicatorType.IPv6, FeedIndicatorType.IPv6CIDR, FeedIndicatorType.CIDR]:
            if "-" in indicator_value:
                context_ip.append({"Address": indicator_value.split("-")[0]})
                context_ip.append({"Address": indicator_value.split("-")[1]})

            elif ":" in indicator_value:
                context_ip.append({"Address": indicator_value.split(":", 1)[0]})

            else:
                context_ip.append({"Address": indicator_value})

        elif indicator_type == FeedIndicatorType.Domain:
            context_domain.append({"Name": indicator_value})

        elif indicator_type == FeedIndicatorType.File:
            context_file.append({"SHA256": indicator_value})

        elif indicator_type == FeedIndicatorType.URL:
            if ":" in indicator_value:
                resolved_address = resolve_ip_address(indicator_value.split(":", 1)[0])
                semicolon_suffix = indicator_value.split(":", 1)[1]
                slash_suffix = None

            else:
                resolved_address = resolve_ip_address(indicator_value.split("/", 1)[0])
                slash_suffix = indicator_value.split("/", 1)[1]
                semicolon_suffix = None

            if resolved_address:
                if semicolon_suffix:
                    indicator_value = resolved_address + ":" + semicolon_suffix

                else:
                    indicator_value = resolved_address + "/" + slash_suffix

            context_url.append(
                {
                    "Data": indicator_value,
                }
            )

        indicators.append(
            {
                "Type": indicator_type,
                "Value": indicator_value,
            }
        )

    hr = tableToMarkdown(f"Export list {args.get('label')}", indicators, headers=["Type", "Value"])

    return_outputs(
        hr,
        {
            "AutoFocus.Indicator(val.Value == obj.Value && val.Type == obj.Type)": indicators,
            "IP(obj.Address == val.Address)": context_ip,
            "URL(obj.Data == val.Data)": context_url,
            "File(obj.SHA256 == val.SHA256)": context_file,
            "Domain(obj.Name == val.Name)": context_domain,
        },
        results,
    )


def main():
    if is_demisto_version_ge("8.12.0") and datetime.now() > datetime(2025, 12, 1):
        return_error("Palo Alto Networks AutoFocus v2 integration is deprecated. Please use Unit 42 Intelligence integration instead.")
    else:
        return_warning("AutoFocus v2 is deprecated and will stop working after December 1, 2025. Please migrate to Unit 42 Intelligence integration.")
    command = demisto.command()
    demisto.debug(f"Command being called is {command}")
    reliability = PARAMS.get("integrationReliability", "B - Usually reliable")
    create_relationships = PARAMS.get("create_relationships", True)
    proxy = PARAMS.get("proxy", False)
    USE_SSL = not PARAMS.get("insecure", False)  # Should we use SSL
    if DBotScoreReliability.is_valid_type(reliability):
        reliability = DBotScoreReliability.get_dbot_score_reliability_from_str(reliability)
    else:
        raise Exception("AutoFocus error: Please provide a valid value for the Source Reliability parameter")

    client = Client(url=BASE_URL, verify=USE_SSL, proxy=proxy)
    args = demisto.args() | {
        "reliability": reliability,
        "create_relationships": create_relationships,
    }

    try:
        if command == "test-module":
            # This is the call made when pressing the integration test button.
            test_module(client)
            demisto.results("ok")
        elif command == "autofocus-search-samples":
            if args.get("polling") == "true":
                cmd_res = search_samples_with_polling_command(client, args)
                if cmd_res is not None:
                    return_results(cmd_res)
            else:
                args["use_batches"] = True
                return_results(search_samples_command(client, args))
        elif command == "autofocus-search-sessions":
            if args.get("polling") == "true":
                return_results(search_sessions_with_polling_command(client, args))
            else:
                args["use_batches"] = True
                return_results(search_sessions_command(client, args))
        elif command == "autofocus-samples-search-results":
            samples_search_results_command(client, args)
        elif command == "autofocus-sessions-search-results":
            return_results(sessions_search_results_command(client, args)[0])  # first result is CommandResults
        elif command == "autofocus-get-session-details":
            get_session_details_command(client)
        elif command == "autofocus-sample-analysis":
            sample_analysis_command(client)
        elif command == "autofocus-tag-details":
            tag_details_command(client)
        elif command == "autofocus-top-tags-search":
            if args.get("polling") == "true":
                return_results(top_tags_with_polling_command(client, args))
            else:
                return_results(top_tags_search_command(client, args))
        elif command == "autofocus-top-tags-results":
            return_results(top_tags_results_command(client, args)[0])
        elif command == "autofocus-get-export-list-indicators":
            get_export_list_command(client, args)
        elif command == "ip":
            return_results(search_ip_command(client, **args))
        elif command == "domain":
            return_results(search_domain_command(client, **args))
        elif command == "url":
            return_results(search_url_command(client, **args))
        elif command == "file":
            return_results(search_file_command(client, **args))
        else:
            raise NotImplementedError(f"Command {command!r} is not implemented.")

    except RateLimitExceededError as e:
        rerun_command_if_required(e.api_res, argToBoolean(args.get("retry_on_rate_limit", False)))

    except Exception as e:
        return_error(f"Unexpected error: {e}.\ntraceback: {traceback.format_exc()}")

    finally:
        return_metrics()


if __name__ in ["__main__", "builtin", "builtins"]:
    main()