RSA NetWitness Endpoint

RSA NetWitness Endpoint provides deep visibility beyond basic endpoint security solutions by monitoring and collecting activity across all of your endpoints on and off your network. The RSA Demisto integration provides access to information about endpoints, modules and indicators.

Endpoint · RSA NetWitness Endpoint

Details

IDRSA NetWitness Endpoint
ProviderPartnerOne
CategoryEndpoint
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Overview


RSA NetWitness Endpoint provides deep visibility beyond basic endpoint security solutions by monitoring and collecting activity across all of your endpoints—on and off your network.
Use this integration to access to information about endpoints, modules, and indicators.

This integration was integrated and tested with RSA NetWitness Endpoint v4.0.

 

Configure RSA NetWitness Endpoint on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for RSA NetWitness Endpoint.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • Server URL (e.g. https://192.168.0.1:30022)
    • credentials
    • Trust any certificate (not secure)
    • Use system proxy settings
  4. Click Test to validate the URL and credentials.

Commands


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

  1. Get GUIDs for multiple machines: netwitness-get-machines
  2. Get the GUID for a single machine: netwitness-get-machine
  3. List IOCs for a specific machine: netwitness-get-machine-iocs
  4. Get information for machine modules: netwitness-get-machine-modules
  5. Get information for a single machine module: netwitness-get-machine-module
  6. Blacklist IP addresses: netwitness-blacklist-ips
  7. Blacklist domains: netwitness-blacklist-domains

1. Get GUIDs for multiple machines


Get machine GUID. Search by machine name and more.

Base Command
netwitness-get-machines
Input
Argument Name Description Required
machineName Hostname to filter results by. Not case sensitive. Optional
iocScoreGreaterThan Filter all machines whose IOC score is greater than or equal to this value. Default = 0. Optional
iocScoreLessThan Filter all machines whose IOC score is less than or equal to this value. Default = 1024. Cannot be zero. Optional
ipAdress Filter all machines based on IP address. Optional
macAddress Filter all machines based on MAC address. Optional
limit Limit the number of results. Default = 100. Optional
includeMachineData Include full machine data Optional
includeMachineIOCs Include machine IOCs Optional
includeMachineModules Include machine modules Optional
 
Context Output
Path Description
NetWitness.Machines.MachineGUID Machine GUID
NetWitness.Machines.AgentID Agent ID
NetWitness.Machines.MachineName Machine name
NetWitness.Machines.LocalIP Local IP
NetWitness.Machines.RemoteIP Remote IP
NetWitness.Machines.MAC MAC
NetWitness.Machines.MachineStatus Machine status
NetWitness.Machines.IIOCScore IIOC score
NetWitness.Machines.IIOCLevel0 IIOC Level 0
NetWitness.Machines.IIOCLevel1 IIOC Level 1
NetWitness.Machines.IIOCLevel2 IIOC Level 2
NetWitness.Machine.IIOCLevel3 IIOC Level 3
NetWitness.Machines.AntiVirusDisabled Anti-virus disabled
NetWitness.Machines.Comment Comment
NetWitness.Machines.ContainmentStatus Containment status
NetWitness.Machines.ContainmentSupported Containment supported
NetWitness.Machines.Country Country
NetWitness.Machines.DNS DNS
NetWitness.Machines.DomainName Domain name
NetWitness.Machines.FirewallDisabled Firewall disabled
NetWitness.Machines.Gateway Gateway
NetWitness.Machines.Group Group
NetWitness.Machines.Idle Idle
NetWitness.Machines.InstallTime Install time
NetWitness.Machines.InstallationFailed Installation failed
NetWitness.Machines.LastScan Last scan
NetWitness.Machines.LastSeen Last seen
NetWitness.Machines.NetworkSegment Network segment
NetWitness.Machines.OperatingSystem Operating system
NetWitness.Machines.OrganizationUnit Organization unit
NetWitness.Machines.Platform Platform
NetWitness.Machines.Scanning Scanning
NetWitness.Machines.UserName User name
NetWitness.Machine.VersionInfo Version information
NetWitness.IOCs.Description Description
NetWitness.IOCs.Type Type
NetWitness.IOCs.MachineCount Machine count
NetWitness.IOCs.ModuleCount Module count
NetWitness.IOCs.IOCLevel IOC level
NetWitness.IOCs.Priority Priority
NetWitness.IOCs.Active Active
NetWitness.IOCs.LastExecuted Last executed
NetWitness.IOCs.Alertable Alertable
NetWitness.IOCs.IOCTriggeredOnMachine IOC Triggered On Machine
NetWitness.Machines.MachineGUID Machine GUID
NetWitness.Modules.ModuleName Module name
NetWitness.Modules.ModuleID Module ID
NetWitness.Modules.Description Description
NetWitness.Modules.IOCScore IOC score
NetWitness.Modules.AnalyticsScore Analytics score
NetWitness.Modules.GlobalMachineCount Global machine count
NetWitness.Modules.MD5 MD5
NetWitness.Modules.SHA256 SHA-256
 
Command Example
!netwitness-get-machines limit="100" includeMachineData="no" includeMachineIOCs="no" includeMachineModules="no"
Context Example
{
    "NetWitness": {
        "Machines": {
            "IOCScore": {
                "FilterValue": 71,
                "FullScore": 8016,
                "Level": 3,
                "Level0": 0,
                "Level1": 0,
                "Level2": 8,
                "Level3": 16,
                "Score": 71,
                "__type": "Tools.IOCScore, Tools"
            },
            "LastScan": "2018-09-12T15:59:48Z",
            "LocalIp": "xxx.xxx.xxx.xxx",
            "MacAddress": "xx:xx:xx:xx:xx:xxx",
            "MachineGUID": "xxxxxx",
            "MachineName": "NWE",
            "Online": true,
            "OperatingSystem": "Microsoft Windows Server 2012 R2 Datacenter"
        }
    }
}
Human Readable Output

NetWitness Endpoint - Get Machines

MachineName MachineGUID Online OperatingSystem LastScan IOCScore MacAddress LocalIp
NWE xxxxxxxx true Microsoft Windows Server 2012 R2 Datacenter 2018-09-12T15:59:48Z FilterValue: 71
Level: 3
Score: 71
Level0: 0
Level1: 0
Level2: 8
Level3: 16
__type: Tools.IOCScore, Tools
FullScore: 8016
xx:xx:xx:xx:xx:xx xxx.xxx.xxx.xxx

 

2. Get the GUID for a single machine


Get information on a specific machine.

Base Command
netwitness-get-machine
Input
Argument Name Description Required
machineGUID GUID of the machine Required
 
Context Output
Path Description
NetWitness.Machines.AgentID Agent ID
NetWitness.Machines.MachineName Machine name
NetWitness.Machines.LocalIP Local IP
NetWitness.Machines.RemoteIP Remote IP
NetWitness.Machines.MAC MAC
NetWitness.Machines.MachineStatus Machine status
NetWitness.Machines.IIOCScore IIOC score
NetWitness.Machines.IIOCLevel0 IIOC Level 0
NetWitness.Machines.IIOCLevel1 IIOC Level 1
NetWitness.Machines.IIOCLevel2 IIOC Level 2
NetWitness.Machine.IIOCLevel3 IIOC Level 3
NetWitness.Machines.AntiVirusDisabled Anti-virus disabled
NetWitness.Machines.Comment Comment
NetWitness.Machines.ContainmentStatus Containment status
NetWitness.Machines.ContainmentSupported Containment supported
NetWitness.Machines.Country Country
NetWitness.Machines.DNS DNS
NetWitness.Machines.DomainName Domain name
NetWitness.Machines.FirewallDisabled Firewall disabled
NetWitness.Machines.Gateway Gateway
NetWitness.Machines.Group Group
NetWitness.Machines.Idle Idle
NetWitness.Machines.InstallTime Installation time
NetWitness.Machines.InstallationFailed Installation failed
NetWitness.Machines.LastScan Last scan
NetWitness.Machines.LastSeen Last seen
NetWitness.Machines.NetworkSegment Network segment
NetWitness.Machines.OperatingSystem Operating system
NetWitness.Machines.OrganizationUnit Organization unit
NetWitness.Machines.Platform Platform
NetWitness.Machines.Scanning Scanning
NetWitness.Machines.UserName User name
NetWitness.Machine.VersionInfo Version information
 
Command Example
!netwitness-get-machine machineGUID=abc123def456
Context Example
{
    "NetWitness": {
        "Machine": {
            "AgentID": "xxxxxx",
            "AntiVirusDisabled": "False",
            "Comment": "",
            "ContainmentStatus": "Not Contained",
            "ContainmentSupported": "True",
            "Country": "USA",
            "DNS": "8.8.8.8",
            "DomainName": "WORKGROUP",
            "FirewallDisabled": "False",
            "Gateway": "xxx.xxx.xxx.xxx",
            "Group": "Default",
            "IIOCLevel0": "0",
            "IIOCLevel1": "0",
            "IIOCLevel2": "8",
            "IIOCLevel3": "16",
            "IIOCScore": "71",
            "Idle": "True",
            "InstallTime": "9/3/2018 4:01:03 PM",
            "InstallationFailed": "False",
            "LastScan": "9/12/2018 3:59:48 PM",
            "LastSeen": "9/25/2018 1:27:01 PM",
            "LocalIP": "xxx.xxx.xxx.xxx",
            "MAC": "xx:xx:xx:xx:xx:xx",
            "MachineName": "NWE",
            "MachineStatus": "Online",
            "NetworkSegment": "xxx.xxx.xxx.xxx",
            "OperatingSystem": "Microsoft Windows Server 2012 R2 Datacenter",
            "OrganizationUnit": "",
            "Platform": "64-bit (x64)",
            "RemoteIP": "xxx.xxx.xxx.xxx",
            "Scanning": "False",
            "UserName": "",
            "VersionInfo": "4.4.0.6"
        }
    }
}
Human Readable Output

NetWitness Endpoint - Machine NWE Full Data

AgentID MachineName LocalIP RemoteIP MAC MachineStatus IIOCScore IIOCLevel0 IIOCLevel1 IIOCLevel2 IIOCLevel3 AntiVirusDisabled Comment ContainmentStatus ContainmentSupported Country DNS DomainName FirewallDisabled Gateway Group Idle InstallTime InstallationFailed LastScan LastSeen NetworkSegment OperatingSystem OrganizationUnit Platform Scanning UserName VersionInfo
xxxxxx NWE xxx.xxx.xxx.xxx xxx.xxx.xxx.xx xx:xx:xx:xx:xx:xx Online 71 0 0 8 16 False   Not Contained True USA 8.8.8.8 WORKGROUP False xxx.xxx.xxx.xxx Default True 9/3/2018 4:01:03 PM False 9/12/2018 3:59:48 PM 9/25/2018 1:27:01 PM xxx.xxx.xxx.xxx Microsoft Windows Server 2012 R2 Datacenter   64-bit (x64) False   4.4.0.6

 

3. List IOCs for a specific machine


List IOCs for a specific machine.

Base Command
netwitness-get-machine-iocs
Input
Argument Name Description Required
machineGUID The machine GUID Required
limit Limit the number of results. Default = 100. Optional
 
Context Output
Path Description
NetWitness.Machines.MachineGUID Machine GUID
NetWitness.IOCs.Description Description
NetWitness.IOCs.Type Type
NetWitness.IOCs.MachineCount Machine count
NetWitness.IOCs.ModuleCount Module count
NetWitness.IOCs.IOCLevel IOC level
NetWitness.IOCs.Priority Priority
NetWitness.IOCs.Active Active
NetWitness.IOCs.LastExecuted Last executed
NetWitness.IOCs.Alertable Alertable
NetWitness.IOCs.IOCTriggeredOnMachine IOC Triggered On Machine
 
Command Example
Context Example
Human Readable Output

4. Get information for machine modules


Get Names and ID's of modules of the machine. Filter by name or IOC score.

Base Command
netwitness-get-machine-modules
Input
Argument Name Description Required
machineGUID The machine GUID Required
moduleName Module name to filter results by (not case sensitive). Example: ModuleName=".exe "will match all machines which have the word ".exe" in their module name. Optional
iocScoreGreaterThan Filter all modules whose IOC score is greater than or equal to this value. Default = 0. Optional
iocScoreLessThan Filter all modules whose IOC score is less than or equal to this value. Default = 1024. Cannot be zero. Optional
limit Limit the number of results. Default 50. Optional
 
Context Output
Path Description
NetWitness.Machines.MachineGUID Machine GUID
NetWitness.Modules.ModuleName Module name
NetWitness.Modules.ModuleID Module ID
NetWitness.Modules.Description Description
NetWitness.Modules.IOCScore IOC score
NetWitness.Modules.AnalyticsScore Analytics score
NetWitness.Modules.GlobalMachineCount Global machine count
NetWitness.Modules.MD5 MD5
NetWitness.Modules.SHA256 SHA-256
 
Command Example
!netwitness-get-machine-modules machineGUID= iocScoreGreaterThan="20" limit="50"
Context Example
{
    "File": {
        "MD5": XX,
        "Name": AdobeARMHelper.exe
    },
    "NetWitness": {
        "Modules": {
            "AnalyticsScore": "1",
            "Description": "Adobe Reader and Acrobat Manager Helper",
            "GlobalMachineCount": 1,
            "IOCScore": {
                "FilterValue": 25,
                "FullScore": 3001,
                "Level": 3,
                "Level0": 0,
                "Level1": 0,
                "Level2": 3,
                "Level3": 1,
                "Score": 25,
                "__type": "Tools.IOCScore, Tools"
            },
            "MD5": "XX",
            "MachineGUID": "XX",
            "ModuleID": 685,
            "ModuleName": "AdobeARMHelper.exe",
            "SHA256": "XX"
        }
    }
}
Human Readable Output

NetWitness Endpoint - Get Modules

ModuleName ModuleID Description IOCScore AnalyticsScore GlobalMachineCount MD5 SHA256
AdobeARMHelper.exe 685 Adobe Reader and Acrobat Manager Helper FilterValue: 25
Level: 3
Score: 25
Level0: 0
Level1: 0
Level2: 3
Level3: 1
__type: Tools.IOCScore, Tools
FullScore: 3001
1 1 XX XX

 

5. Get information for a single machine module


Get information for a specific machine module.

Base Command
netwitness-get-machine-module
Input
Argument Name Description Required
machineGUID The machine GUID Required
moduleID The module ID Required
 
Context Output
Path Description
NetWitness.Modules.MachineGUID Machine GUID
NetWitness.Modules.ModuleID Module ID
NetWitness.Modules.FileName File name
NetWitness.Modules.FullPath Full path
NetWitness.Modules.MD5 MD5
NetWitness.Modules.RiskScore Risk score
NetWitness.Modules.SHA1 SHA-1
NetWitness.Modules.SHA256 SHA-256
NetWitness.Modules.IIOCScore IIOC score
NetWitness.Modules.Blacklisted Blacklisted
NetWitness.Modules.Graylisted Graylisted
NetWitness.Modules.Whitelisted Whitelisted
NetWitness.Modules.MachineCount Machine count
NetWitness.Modules.IIOCLevel0 IIOC Level 0
NetWitness.Modules.IIOCLevel1 IIOC Level 1
NetWitness.Modules.IIOCLevel2 IIOC Level 2
NetWitness.Modules.IIOCLevel3 IIOC Level 3
NetWitness.Modules.FirstSeenName First seen name
NetWitness.Modules.FirstSeenDate First seen date
File.Name The file name
File.MD5 File MD5
File.SHA1 File SHA-1
File.Path File full path
 
Command Example
!netwitness-get-machine-module machineGUID= moduleID=
Context Example
{
    "File": {
        "MD5": null,
        "Name": null,
        "Path": "C:\\Program Files (x86)\\Common Files\\Adobe\\ARM\\1.0\\Temp\\242902160\\AdobeARMHelper.exe",
        "SHA1": "7AFB5FDF4FAC3C682877B22B90F3D9C3737271D2"
    },
    "NetWitness": {
        "Module": {
            "Blacklisted": "None",
            "FileName": "AdobeARMHelper.exe",
            "FirstSeenDate": "9/18/2018 8:13:02 PM",
            "FirstSeenName": "AdobeARMHelper.exe",
            "FullPath": "C:\\Program Files (x86)\\Common Files\\Adobe\\ARM\\1.0\\Temp\\242902160\\AdobeARMHelper.exe",
            "Graylisted": "None",
            "IIOCLevel0": "0",
            "IIOCLevel1": "0",
            "IIOCLevel2": "3",
            "IIOCLevel3": "1",
            "IIOCScore": "25",
            "MD5": "7182705213142EE4DCF722AA247DD55C",
            "MachineCount": "1",
            "MachineGUID": "ea946082-0563-c15e-8128-c5b6e8b2fea9",
            "RiskScore": "1",
            "SHA1": "7AFB5FDF4FAC3C682877B22B90F3D9C3737271D2",
            "SHA256": "F9B595F657589A25F6F247B4CDD0DE7F2BA0319B015D33F000728BFC11D0A1C2",
            "Whitelisted": "None"
        }
    }
}
Human Readable Output

NetWitness Endpoint - Get Module

ModuleID ModuleName FullPath FirstSeenName FirstSeenDate MD5 SHA1 SHA256 IIOCLevel0 IIOCLevel1 IIOCLevel2 IIOCLevel3 IIOCScore Blacklisted Graylisted Whitelisted MachineCount RiskScore AVDefinitionHash AVDescription AVFirstThreat AVScanResult AccessNetwork AnalysisTime AppDataLocal AppDataRoaming AutoStartCategory Autorun BlacklistCategory BlockingStatus Desktop Downloaded DownloadedTime FakeStartAddress FileAccessDenied FileAccessTime FileCreationTime FileEncrypted FileHiddenAttributes FileModificationTime FileName FileOccurrences Floating HashLookup Hooking ImportedDLLCount ImportedDLLs LiveConnectRiskEnum LiveConnectRiskReason Loaded OriginalFileName Packed Platform RelativeFileName RelativePath RemoteFileName RemotePath Signature SignatureTimeStamp SizeInBytes Status YaraDefinitionHash YaraScanDescription YaraScanFirstThreat YaraScanresult Windows WritetoExecutable SysWOW64 System32 Temporary TooManyConnections User SignatureValid SignedbyMicrosoft SignatureExpired SignaturePresent RenametoExecutable ReservedName ProcessAccessDenied ProgramData ProgramFiles ReadDocument MD5Collision InstallerDirectory LikelyPacked Listen ImageHidden ImageMismatch FirewallAuthorized AutorunScheduledTask Beacon
  AdobeARMHelper.exe C:\Program Files (x86)\Common Files\Adobe\ARM\1.0\Temp\242902160\AdobeARMHelper.exe AdobeARMHelper.exe 9/18/2018 8:13:02 PM XX XX XX 0 0 3 1 25 None None None 1 1 0     Unknown False 1/1/0001 12:00:00 AM False False None False Generic Malware Unknown False False 1/1/0001 12:00:00 AM False False 9/18/2018 8:11:45 PM 9/18/2018 8:11:45 PM False False 3/21/2018 7:21:48 AM AdobeARMHelper.exe 10343 False Good False 16 PSAPI.DLL; msi.dll; USERENV.dll; KERNEL32.dll; USER32.dll; ADVAPI32.dll; SHELL32.dll; ole32.dll; SHLWAPI.dll; CRYPT32.dll; WINTRUST.dll; OLEACC.dll; GDI32.dll; WINSPOOL.DRV; COMDLG32.dll; OLEAUT32.dll Unknown None True   False I386         Valid: Adobe Systems, Incorporated 3/21/2018 9:19:15 AM 413.5 kB Neutral 0     Unknown False True False False True False False True False False True False False False False True False False True False False False False False False False

 

6. Block list IP addresses


Add a list of IP addresses to block list.

Base Command
netwitness-blacklist-ips
Input
Argument Name Description Required
ips Comma separated list of IP addresses Required
 
Context Output

There is no context output for this command.

Command Example

!netwitness-blacklist-ips ips="1.1.1.1,2.2.2.2"

Context Example
{
    "NetWitness": {
        "Blacklist": {
            "IPs": [
                "1.2.3.4"
            ]
        }
    }
}
Human Readable Output

IPs Successfully Block listed

IP
1.2.3.4

 

7. Block list domains


Add a list of domain block list.

Base Command
netwitness-blacklist-domains
Input
Argument Name Description Required
domains Comma separated list of domains Required
 
Context Output

There is no context output for this command.

Command Example
!netwitness-blacklist-domains domains="https://www.example2.com,https://www.example2.com"
Context Example
{
    "NetWitness": {
        "Blacklist": {
            "Domains": [
                "www.example.com"
            ]
        }
    }
}
Human Readable Output

Domains Successfully Block listed

Domain
www.example.com

Configuration parameters

  • server — Server URL (e.g. https://192.168.0.1:30022) (required)
  • credentials — Username
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (7)

  • netwitness-blacklist-domains

    Add a list of domains to block list

  • netwitness-blacklist-ips

    Add a list of IP addresses to block list

  • netwitness-get-machine

    Get information on a specific machine.

  • netwitness-get-machine-iocs

    List IOC's for a specific machine.

  • netwitness-get-machine-module

    Get information on a specific machine module.

  • netwitness-get-machine-modules

    Get Names and ID's of modules of the machine. Filter by name or IOC score.

  • netwitness-get-machines

    Get machine GUID. Search by machine name and more.

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

"""

IMPORTS

"""
import math
import os

import requests
import urllib3

# disable insecure warnings
urllib3.disable_warnings()

"""

HANDLE PROXY

"""


def set_proxies():
    if demisto.params()["proxy"]:
        http = os.environ["http_proxy"] or os.environ["HTTP_PROXY"]
        https = os.environ["https_proxy"] or os.environ["HTTPS_PROXY"]
        proxies = {"http": http, "https": https}
        return proxies
    return None


"""

GLOBAL VARS

"""

SERVER_URL = demisto.params()["server"]
BASE_PATH = f"{SERVER_URL}/api/v2" if SERVER_URL.endswith("/") else f"{SERVER_URL}/api/v2"
USERNAME = demisto.params()["credentials"]["identifier"]
PASSWORD = demisto.params()["credentials"]["password"]
USE_SSL = not demisto.params()["insecure"]
PROXIES = set_proxies()

MACHINE_DATA_EXTENDED = [
    "AgentID",
    "MachineName",
    "LocalIP",
    "RemoteIP",
    "MAC",
    "MachineStatus",
    "IIOCScore",
    "IIOCLevel0",
    "IIOCLevel1",
    "IIOCLevel2",
    "IIOCLevel3",
    "AntiVirusDisabled",
    "Comment",
    "ContainmentStatus",
    "ContainmentSupported",
    "Country",
    "DNS",
    "DomainName",
    "FirewallDisabled",
    "Gateway",
    "Group",
    "Idle",
    "InstallTime",
    "InstallationFailed",
    "LastScan",
    "LastSeen",
    "NetworkSegment",
    "OperatingSystem",
    "OrganizationUnit",
    "Platform",
    "Scanning",
    "UserName",
    "VersionInfo",
]

MACHINE_DATA = ["MachineName", "MachineGUID", "Online", "OperatingSystem", "LastScan", "IOCScore", "MacAddress", "LocalIp"]

IOC_DATA = [
    "Description",
    "Type",
    "MachineCount",
    "ModuleCount",
    "IOCLevel",
    "Priority",
    "Active",
    "LastExecuted",
    "Alertable",
    "IOCTriggeredOnMachine",
]

MODULE_DATA = ["ModuleName", "ModuleID", "Description", "IOCScore", "AnalyticsScore", "GlobalMachineCount", "MD5", "SHA256"]

MODULE_DATA_EXTENDED = [
    "ModuleID",
    "ModuleName",
    "FullPath",
    "FirstSeenName",
    "FirstSeenDate",
    "MD5",
    "SHA1",
    "SHA256",
    "IIOCLevel0",
    "IIOCLevel1",
    "IIOCLevel2",
    "IIOCLevel3",
    "IIOCScore",
    "Blacklisted",
    "Graylisted",
    "Whitelisted",
    "MachineCount",
    "RiskScore",
    "AVDefinitionHash",
    "AVDescription",
    "AVFirstThreat",
    "AVScanResult",
    "AccessNetwork",
    "AnalysisTime",
    "AppDataLocal",
    "AppDataRoaming",
    "AutoStartCategory",
    "Autorun",
    "BlacklistCategory",
    "BlockingStatus",
    "Desktop",
    "Downloaded",
    "DownloadedTime",
    "FakeStartAddress",
    "FileAccessDenied",
    "FileAccessTime",
    "FileCreationTime",
    "FileEncrypted",
    "FileHiddenAttributes",
    "FileModificationTime",
    "FileName",
    "FileOccurrences",
    "Floating",
    "HashLookup",
    "Hooking",
    "ImportedDLLCount",
    "ImportedDLLs",
    "LiveConnectRiskEnum",
    "LiveConnectRiskReason",
    "Loaded",
    "OriginalFileName",
    "Packed",
    "Platform",
    "RelativeFileName",
    "RelativePath",
    "RemoteFileName",
    "RemotePath",
    "Signature",
    "SignatureTimeStamp",
    "SizeInBytes",
    "Status",
    "YaraDefinitionHash",
    "YaraScanDescription",
    "YaraScanFirstThreat",
    "YaraScanresult",
    "Windows",
    "WritetoExecutable",
    "SysWOW64",
    "System32",
    "Temporary",
    "TooManyConnections",
    "User",
    "SignatureValid",
    "SignedbyMicrosoft",
    "SignatureExpired",
    "SignaturePresent",
    "RenametoExecutable",
    "ReservedName",
    "ProcessAccessDenied",
    "ProgramData",
    "ProgramFiles",
    "ReadDocument",
    "MD5Collision",
    "InstallerDirectory",
    "LikelyPacked",
    "Listen",
    "ImageHidden",
    "ImageMismatch",
    "FirewallAuthorized",
    "AutorunScheduledTask",
    "Beacon",
]

MODULE_DATA_EXTENDED_CONTEXT = [
    "ModuleID",
    "FileName",
    "FullPath",
    "MD5",
    "RiskScore",
    "SHA1",
    "SHA256",
    "IIOCScore",
    "Blacklisted",
    "Graylisted",
    "Whitelisted",
    "MachineCount",
    "IIOCLevel0",
    "IIOCLevel1",
    "IIOCLevel2",
    "IIOCLevel3",
    "FirstSeenName",
    "FirstSeenDate",
]


def is_html_response(response: requests.Response):
    return "text/html" in response.headers.get("Content-Type", "").lower()


def get_html_from_response(response):
    text = response.text
    open_tag = text.lower().find("<html")
    close_tag = text.lower().find("</html>")
    return text[open_tag : close_tag + len("</html>")]


def html_error_entry(html):
    return {"Type": entryTypes["error"], "Contents": html, "ContentsFormat": formats["html"]}


def parse_error_response(error_response):
    # NetWitness has fixed structure for
    try:
        error = error_response.json()
        return (
            f"Request failed with status code: "
            f"{error_response.status_code}\nReason: {error.ResponseStatus.ErrorCode}\n{error.ResponseStatus.Message}"
        )
    except Exception as e:
        demisto.debug(f"{e}")
        return f"Request failed with status code: {error_response.status_code}\n{error_response.content}"


def http_request(method, url, data=None, headers={"Accept": "application/json"}, url_params=None):
    # send http request using user settings for unsecure and proxy parameters
    # uses basic auth
    # returns the http response

    LOG(f"Attempting {method} request to {url}")
    try:
        response = requests.request(
            method, url, headers=headers, data=data, auth=(USERNAME, PASSWORD), params=url_params, verify=USE_SSL, proxies=PROXIES
        )
    except requests.exceptions.SSLError as e:
        LOG(e)
        raise ValueError("An SSL error occurred. Consider to set unsecure")

    if is_html_response(response):
        html_body = get_html_from_response(response)
        demisto.results(html_error_entry(html_body))
        raise ValueError("Caught HTML response, please verify server url.")

    if response.status_code < 200 or response.status_code >= 300:
        msg = parse_error_response(response)
        raise ValueError(msg)

    try:
        return response.json()
    except Exception as e:
        LOG(e)
        return {}


def login():
    url = f"{BASE_PATH}/auth"
    # this call will raise an exception on wrong credential
    http_request("GET", url)


def get_machines(query, limit):
    # GET /machines

    # specify additional data to be returned
    query["Properties"] = "Online,OperatingSystem,LastScanUTCTime,IOCScore,MacAddress,LocalIp"
    # add paging to query
    query["page"] = 1
    # set per_page parameter only if 'limit' is under 50
    if limit < 50:
        query["per_page"] = limit  # int

    machines = []
    # loop on page number
    while True:
        res = http_request("GET", f"{BASE_PATH}/machines", url_params=query)
        items = res.get("Items")
        if not items:
            # no results
            break
        machines.extend(items)
        if len(machines) >= limit:
            # reached/exceeded limit
            break
        # get next page
        query["page"] = query["page"] + 1

    if len(machines) > limit:
        # results exceeded limit
        machines[limit - 1 : -1] = []

    return machines


def get_machines_command():
    args = demisto.args()

    # prepare query
    query = {
        "MachineName": args.get("machineName"),  # string
        "iocscore_gte": int(args.get("iocScoreGreaterThan")) if args.get("iocScoreGreaterThan") else None,  # int
        "iocscore_lte": int(args.get("iocScoreLessThan")) if args.get("iocScoreLessThan") else None,  # int
        "IpAddress": args.get("ipAddress"),  # string
        "macAddress": args.get("macAddress"),  # string
    }
    limit = int(args.get("limit")) if args.get("limit") else math.inf
    if limit < 1:
        raise ValueError("Please input valid limit number")

    machines = get_machines(query, limit)

    context = []
    for machine in machines:
        properties = machine["Properties"]
        context.append(
            {
                "MachineGUID": machine.get("Id"),
                "MachineName": machine.get("Name"),
                "Online": properties.get("Online"),
                "OperatingSystem": properties.get("OperatingSystem"),
                "LastScan": properties.get("LastScanUTCTime"),
                "IOCScore": properties.get("IOCScore"),
                "MacAddress": properties.get("MacAddress"),
                "LocalIp": properties.get("LocalIp"),
            }
        )

    entry = {
        "Type": entryTypes["note"],
        "Contents": {"Machines": machines, "Machine": [], "IOCs": [], "Modules": []},
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": tableToMarkdown("NetWitness Endpoint - Get Machines", context, MACHINE_DATA),
        "EntryContext": {"NetWitness.Machines(obj.MachineGUID==val.MachineGUID)": context},
    }

    # get additional machine data
    for id in [machine["Id"] for machine in machines]:
        if args.get("includeMachineData") == "yes":
            machine_entry = create_machine_entry(id)

            entry["Contents"]["Machine"].append(machine_entry["Contents"])
            entry["HumanReadable"] += "\n{}".format(machine_entry["HumanReadable"])
            entry["EntryContext"].update(machine_entry["EntryContext"])

        if args.get("includeMachineIOCs") == "yes":
            iocs_entry = create_iocs_entry(id, 50)

            entry["Contents"]["IOCs"].extend(iocs_entry["Contents"])
            entry["HumanReadable"] += "\n{}".format(iocs_entry["HumanReadable"])
            entry["EntryContext"].update(iocs_entry["EntryContext"])

        if args.get("includeMachineModules") == "yes":
            modules_entry = create_modules_entry(id, {}, 30)

            entry["Contents"]["Modules"].extend(modules_entry["Contents"])
            entry["HumanReadable"] += "\n{}".format(modules_entry["HumanReadable"])
            entry["EntryContext"].update(modules_entry["EntryContext"])

    demisto.results(entry)


def get_machine(machine_id):
    # GET /machines/{Guid}
    response = http_request("GET", f"{BASE_PATH}/machines/{machine_id}")
    return response.get("Machine")


def create_machine_entry(machine_id):
    machine = get_machine(machine_id)
    machine_name = machine.get("MachineName")

    machine_data = {k: v for k, v in machine.items() if k in MACHINE_DATA_EXTENDED}
    machine_data["MachineGUID"] = machine_id

    entry = {
        "Type": entryTypes["note"],
        "Contents": machine,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": tableToMarkdown(
            f"NetWitness Endpoint - Machine {machine_name} Full Data", machine_data, MACHINE_DATA_EXTENDED
        ),
        "EntryContext": {"NetWitness.Machines(obj.MachineGUID==val.MachineGUID)": machine_data},
    }
    return entry


def get_machine_command():
    entry = create_machine_entry(demisto.args().get("machineGUID"))
    demisto.results(entry)


def list_iocs(machine_id, limit):
    # GET /machines/{Guid}/instantiocs

    paging_params = {"page": 1}
    # set per_page parameter only if 'limit' is under 50
    if limit < 50:
        paging_params["per_page"] = limit

    iocs = []
    # loop on page number
    while True:
        res = http_request("GET", f"{BASE_PATH}/machines/{machine_id}/instantiocs", url_params=paging_params)
        items = res.get("Iocs")
        if not items:
            # no results
            break
        iocs.extend(items)
        if len(iocs) >= limit:
            # reached/exceeded limit
            break
        # get next page
        paging_params["page"] = paging_params["page"] + 1

    if len(iocs) > limit:
        # results exceeded limit
        iocs[limit - 1 : -1] = []

    return iocs


def create_iocs_entry(machine_id, limit):
    iocs = list_iocs(machine_id, limit)

    context = []
    for ioc in iocs:
        data = {k: v for k, v in ioc.items() if k in IOC_DATA}
        data["MachineGUID"] = machine_id
        context.append(data)

    entry = {
        "Type": entryTypes["note"],
        "Contents": iocs,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": tableToMarkdown("NetWitness Endpoint - Machine IOC's", context, IOC_DATA),
        "EntryContext": {
            "NetWitness.IOCS(obj.Description==val.Description)": context,
        },
    }
    return entry


def list_iocs_command():
    args = demisto.args()
    machine_id = args.get("machineGUID")
    limit = int(args.get("limit")) if args.get("limit") else math.inf

    if limit < 1:
        raise ValueError("Please input valid limit number")

    entry = create_iocs_entry(machine_id, limit)
    demisto.results(entry)


def get_machine_modules(machine_id, query, limit):
    # GET /machines/{Guid}/modules

    # specify additional data to be returned
    query["Properties"] = "Description,IOCScore,AnalyticsScore,GlobalMachineCount,HashMD5,HashSHA256"
    # add paging to query
    query["page"] = 1
    # set per_page parameter only if 'limit' is under 50
    if limit < 50:
        query["per_page"] = limit

    modules = []
    # loop on page number
    while True:
        res = http_request("GET", f"{BASE_PATH}/machines/{machine_id}/modules", url_params=query)
        items = res.get("Items")
        if not items:
            # no results
            break
        modules.extend(items)
        if len(modules) >= limit:
            # reached/exceeded limit
            break
        # get next page
        query["page"] = query["page"] + 1

    if len(modules) > limit:
        # results exceeded limit
        modules[limit - 1 : -1] = []

    return modules


def create_modules_entry(machine_id, query, limit):
    modules = get_machine_modules(machine_id, query, limit)

    context = []
    files = []
    for module in modules:
        properties = module["Properties"]
        context.append(
            {
                "ModuleID": module.get("Id"),
                "ModuleName": module.get("Name"),
                "Description": properties.get("Description"),
                "IOCScore": properties.get("IOCScore"),
                "AnalyticsScore": properties.get("AnalyticsScore"),
                "GlobalMachineCount": properties.get("GlobalMachineCount"),
                "MD5": properties.get("HashMD5"),
                "SHA256": properties.get("HashSHA256"),
                "MachineGUID": machine_id,
            }
        )
        files.append(
            {
                "Name": module.get("Name"),
                "MD5": properties.get("HashMD5"),
            }
        )

    entry = {
        "Type": entryTypes["note"],
        "Contents": modules,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": tableToMarkdown("NetWitness Endpoint - Get Modules", context, MODULE_DATA),
        "EntryContext": {"NetWitness.Modules(obj.ModuleID==val.ModuleID)": context, "File(obj.MD5==val.MD5)": files},
    }
    return entry


def get_machine_modules_command():
    args = demisto.args()

    machine_id = args.get("machineGUID")
    limit = int(args.get("limit")) if args.get("limit") else math.inf
    if limit < 1:
        raise ValueError("Please input valid limit number")
    # prepare query
    query = {
        "ModuleName": args.get("moduleName"),  # string
        "iocscore_gte": int(args.get("iocScoreGreaterThan")) if args.get("iocScoreGreaterThan") else None,  # int
        "iocscore_lte": int(args.get("iocScoreLessThan")) if args.get("iocScoreLessThan") else None,  # int
    }

    entry = create_modules_entry(machine_id, query, limit)
    demisto.results(entry)


def get_machine_module(machine_guid, moudule_id):
    # GET machines/{Guid}/modules/{Id}
    response = http_request(
        "GET",
        f"{BASE_PATH}/machines/{machine_guid}/modules/{moudule_id}",
    )
    return response.get("MachineModulePath")


def get_machine_module_command():
    args = demisto.args()
    machine_id = args.get("machineGUID")

    module = get_machine_module(machine_id, args.get("moduleID"))

    file = {"Name": module.get("Name"), "MD5": module.get("HashMD5"), "SHA1": module.get("SHA1"), "Path": module.get("FullPath")}
    readable = {k: v for k, v in module.items() if k in MODULE_DATA_EXTENDED}
    context = {k: v for k, v in module.items() if k in MODULE_DATA_EXTENDED_CONTEXT}
    context["MachineGUID"] = machine_id
    entry = {
        "Type": entryTypes["note"],
        "Contents": module,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": tableToMarkdown("NetWitness Endpoint - Get Module", readable, MODULE_DATA_EXTENDED),
        "EntryContext": {"NetWitness.Modules(obj.ModuleID==val.ModuleID)": context, "File(obj.MD5==val.MD5)": file},
    }
    demisto.results(entry)


def blacklist_ips(ips):
    # POST /blacklist/ip
    body = {"Ips": ips}
    response = http_request("POST", f"{BASE_PATH}/blacklist/ip", data=body)
    return response.get("Ips")


def blacklist_domains(domains):
    # POST /blacklist/domain
    body = {"Domains": domains}
    response = http_request("POST", f"{BASE_PATH}/blacklist/domain", data=body)
    return response.get("Domains")


def blacklist_ips_command():
    ips = demisto.args().get("ips").split(",")

    ips_successfully_blacklisted = blacklist_ips(ips)

    ips_failed = [ip for ip in ips if ip not in ips_successfully_blacklisted]
    readable = tableToMarkdown("IPs Successfully Blacklisted", ips_successfully_blacklisted, headers=["IP"])
    if len(ips_failed) > 0:
        readable += tableToMarkdown("The following IPs could not be processed", ips_failed, headers=["IP"])

    entry = {
        "Type": entryTypes["note"],
        "Contents": ips_successfully_blacklisted,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": readable,
        "EntryContext": {
            "NetWitness.Blacklist.IPs": ips_successfully_blacklisted,
        },
    }
    demisto.results(entry)


def blacklist_domains_command():
    args = demisto.args()
    domains = args.get("domains").split(",")

    domains_successfully_blacklisted = blacklist_domains(domains)

    domains_failed = [domain for domain in domains if domain not in domains_successfully_blacklisted]
    readable = tableToMarkdown("Domains Successfully Blacklisted", domains_successfully_blacklisted, headers=["Domain"])
    if len(domains_failed) > 0:
        readable += tableToMarkdown("The following domains could not be processed", domains_failed, headers=["Domain"])

    entry = {
        "Type": entryTypes["note"],
        "Contents": domains_successfully_blacklisted,
        "ContentsFormat": formats["json"],
        "ReadableContentsFormat": formats["markdown"],
        "HumanReadable": readable,
        "EntryContext": {
            "NetWitness.Blacklist.Domains": domains_successfully_blacklisted,
        },
    }
    demisto.results(entry)


"""

EXECUTION

"""


def main():
    try:
        login()
        command = demisto.command()

        if command == "test-module":
            # validated credentials with login call
            # test permission - call get_machines
            get_machines({}, 1)
            demisto.results("ok")
        elif command == "netwitness-get-machines":
            get_machines_command()
        elif command == "netwitness-get-machine":
            get_machine_command()
        elif command == "netwitness-get-machine-iocs":
            list_iocs_command()
        elif command == "netwitness-get-machine-modules":
            get_machine_modules_command()
        elif command == "netwitness-get-machine-module":
            get_machine_module_command()
        elif command == "netwitness-blacklist-ips":
            blacklist_ips_command()
        elif command == "netwitness-blacklist-domains":
            blacklist_domains_command()

    except ValueError as e:
        LOG(e)
        LOG.print_log()
        return_error(e)


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