Accessdata Deprecated
Deprecated. Use Exterro FTK instead.
Forensics & Malware Analysis · Accessdata (Deprecated)
Details
| ID | Accessdata |
|---|---|
| Provider | Exterro |
| Category | Forensics & Malware Analysis |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.10.5.31928 |
| Supported Modules | Agentix |
README
Use the Quin-C AccessData integration to protect against and provide additional visibility into phishing and other malicious email attacks. This integration was integrated and tested with version 20190926 of Quin-C Accessdata.
Documentation for the integration was provided by Quin-C.
AccessData Playbook
For example, you can look at “Accessdata: Dump memory for malicious process” playbook to understand how to use this integration.
Configure AccessData in Cortex
| Parameter | Description | Example |
|---|---|---|
| Name | A meaningful name for the integration instance. | Quin-C Instance Alpha |
| Server URL | The URL to the AccessData server, including the scheme. | FQDN or IP address in X.X.X.X format with scheme specified. |
| Token | A piece of data that servers use to verify for authenticity | eea810f5-a6f6 |
| 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. | https://proxyserver.com |
Commands
You can execute these commands from the 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.
Get a process list
Returns a list of processes from the legacy agent.
Base Command
accessdata-legacyagent-get-processlist
Input
| Argument Name | Description | Required |
|---|---|---|
| caseid | The ID of the case. | Optional |
| target_ip | The IP address of the agent. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.Job.ID | string | The ID of the job. |
| Accessdata.Job.CaseID | string | The ID of the case. |
| Accessdata.Job.CaseJobID | string | The concatenated CaseID and JobID, for example, like “1_800”. |
| Accessdata.Job.Type | string | The job type. |
| Accessdata.Job.State | string | The execution state of the job. |
Command Example
accessdata-legacyagent-get-processlist caseid=2 target_ip=X.X.X.X
Context Example
{
"Accessdata.Job": {
"ID": 157,
"Type": "Volatile",
"CaseID": "2",
"State": "Unknown",
"CaseJobID": "2_157"
}
}
Human Readable Output
JobID: 157
Create a legacy agent memory dump
Creates a legacy agent memory dump.
Base Command
accessdata-legacyagent-get-memorydump
Input
| Argument Name | Description | Required |
|---|---|---|
| caseid | The ID of the case. | Optional |
| target_ip | The IP address of the agent. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.Job.ID | string | The ID of the job. |
| Accessdata.Job.CaseID | string | The ID of the case. |
| Accessdata.Job.CaseJobID | string | The concatenated CaseID and JobID, for example, like “1_800”. |
| Accessdata.Job.Type | string | The job type. |
| Accessdata.Job.State | string | The execution state of the job. |
Command Example
accessdata-legacyagent-get-memorydump caseid=2 target_ip=X.X.X.X
Context Example
{
"Accessdata.Job": {
"ID": 158,
"Type": "LegacyMemoryDump",
"CaseID": "2",
"State": "Unknown",
"CaseJobID": "2_158"
}
}
Human Readable Output
JobID: 158
Read a file from a case folder
Reads a file from a case folder and puts the contents into the context output.
Base Command
accessdata-read-casefile
Input
| Argument Name | Description | Required |
|---|---|---|
| filepath | The path to the case file. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.File.Contents | string | The contents of the file. |
Command Example
accessdata-read-casefile filepath="\\X.X.X.X\D$\paths\cases\ProcessingHelperCase\b389a8e9-4ce4-473d-8d2e-9026f53f925c\Jobs\job_153\fa9787a3-49a1-4d73-a194-7c944eb9a3bf\1\snapshot.xml"
Context Example
{
"Accessdata.File.Contents": "<?xml version=\"1.0\"?>\r\n<root>\r\n<Process resultitemtype=\"15\"><Name>addm.exe</Name><Path/><StartTi ... ress>0</baseAddress><ImageSize>0</ImageSize><ProcessName/><FromAgent/></DLL>\r\n</root>\r\n"
}
Human Readable Output
<?xml version="1.0"?>
<root>
<Process resultitemtype="15">\<Name>addm.exe</Name>\<Path/>\<StartTi ... ress>0</baseAddress>\<ImageSize>0</ImageSize>\<ProcessName/>\<FromAgent/>\</DLL>
</root>
Check the status of a job
Checks the status of a job.
Base Command
accessdata-jobstatus-scan
Input
| Argument Name | Description | Required |
|---|---|---|
| caseJobID | The concatenated CaseID and JobID, for example, “1_800”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.Job.CaseID | string | The ID of the case. |
| Accessdata.Job.ID | string | The ID of the job. |
| Accessdata.Job.CaseJobID | string | The concatenated CaseID and JobID, for example, like “1_800”. |
| Accessdata.Job.State | string | The execution state of the job. |
Command Example
accessdata-jobstatus-scan caseJobID=2_153
Context Example
{
"Accessdata.Job": {
"ID": "153",
"CaseID": "2",
"State": "Success",
"CaseJobID": "2_153"
}
}
Human Readable Output
Current job state: Success
Get a snapshot of a path
Gets a snapshot of the path from the results of the process list job.
Base Command
accessdata-get-jobstatus-processlist
Input
| Argument Name | Description | Required |
|---|---|---|
| caseID | The ID of the case. | Required |
| jobID | The ID of the job. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.Job.State | string | The state of the job. |
| Accessdata.Job.Result | string | The snapshot of the path with the processes list. |
| Accessdata.Job.ID | number | The ID of the job. |
| Accessdata.Job.CaseID | number | The case ID of the job. |
| Accessdata.Job.CaseJobID | string | The concatenated CaseID and JobID, for example, like “1_800”. |
Command Example
accessdata-get-jobstatus-processlist caseID=2 jobID=153
Context Example
{
"Accessdata.Job": {
"ID": "153",
"Result": "\\\\X.X.X.X\\D$\\paths\\cases\\ProcessingHelperCase\\b389a8e9-4ce4-473d-8d2e-9026f53f925c\\Jobs\\job_153\\fa9787a3-49a1-4d73-a194-7c944eb9a3bf\\1\\snapshot.xml",
"CaseID": "2",
"State": "Success",
"CaseJobID": "2_153"
}
}
Human Readable Output
\X.X.X.X\D$\paths\cases\ProcessingHelperCase\b389a8e9-4ce4-473d-8d2e-9026f53f925c\Jobs\job_153\fa9787a3-49a1-4d73-a194-7c944eb9a3bf\1\snapshot.xml
Get a memory dump
Gets a memory dump path from the results of a memory dump job.
Base Command
accessdata-get-jobstatus-memorydump
Input
| Argument Name | Description | Required |
|---|---|---|
| caseID | The ID of the case. | Required |
| jobID | The ID of the job. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.Job.State | string | The state of the job. |
| Accessdata.Job.Result | string | The path of the memory dump. |
| Accessdata.Job.ID | number | The ID of the job. |
| Accessdata.Job.CaseID | number | The case ID of the job. |
| Accessdata.Job.CaseJobID | string | The concatenated CaseID and JobID, for example, like “1_800”. |
Command Example
accessdata-get-jobstatus-memorydump caseID=2 jobID=154
Context Example
{
"Accessdata.Job": {
"ID": "154",
"Result": "\\\\X.X.X.X\\data\\SiteServer\\storage\\60564598-ca55-475c-9f27-ab4992e8ff46\\1\\memdump.mem",
"CaseID": "2",
"State": "Success",
"CaseJobID": "2_154"
}
}
Human Readable Output
\X.X.X.X\data\SiteServer\storage\60564598-ca55-475c-9f27-ab4992e8ff46\1\memdump.mem
Get an ID
Returns the ID of the processing case.
Base Command
accessdata-get-processing-case-id
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| Accessdata.ProcessingCaseId | string | The ID of the processing case. |
Command Example
accessdata-get-processing-case-id
Context Example
{
"Accessdata.ProcessingCaseId": 2
}
Human Readable Output
2
Configuration parameters
server_name— Server URL with scheme (FQDN or IP address in X.X.X.X format with scheme specified) (required)Token— The token is required to connect to Quinc. (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (7)
-
accessdata-get-jobstatus-memorydumpReturns the memory dump path from the result of the memory dump job.
-
accessdata-get-jobstatus-processlistReturns a snapshot path from the results of the process list job.
-
accessdata-get-processing-case-idReturns the ID of the Quin-C processing case.
-
accessdata-jobstatus-scanChecks status of the job.
-
accessdata-legacyagent-get-memorydumpCreates a legacy agent memory dump.
-
accessdata-legacyagent-get-processlistReturns a list of processes from the legacy agent.
-
accessdata-read-casefileReads the file from a case folder and returns the contents to the current context.
import demistomock as demisto from CommonServerPython import * from CommonServerUserPython import * ''' IMPORTS ''' import os import json import requests from urllib3 import disable_warnings from requests.exceptions import HTTPError # Disable insecure warnings disable_warnings() ''' CONSTANTS ''' DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" ACCESS_DATA = 'Accessdata' JOBID_KEY = 'Accessdata.Job.ID' JOBRESULT_KEY = 'Accessdata.Job.Result' JOBSTATE_KEY = 'Accessdata.Job.State' JOB_KEY = 'Accessdata.Job' ''' HELPERS ''' def create_jobstate_context(contents): if 'CaseJobID' not in contents: return { JOB_KEY + '(val.ID == obj.ID)': contents } return { JOB_KEY + '(val.CaseJobID == obj.CaseJobID)': contents } def create_contents(caseID, jobID, state=None, result=None): ec = { 'CaseID': caseID, 'ID': jobID, 'CaseJobID': str(caseID) + "_" + str(jobID) } if state is not None: ec['State'] = state if result is not None: ec['Result'] = result return ec def wrap_jobstate_context(contents, humanReadableMessage=""): return { 'Type': entryTypes['note'], 'ContentsFormat': formats['json'], 'Contents': contents, 'HumanReadable': humanReadableMessage, 'EntryContext': create_jobstate_context(contents) } class Client: """ Client will implement the service API, should not contain Demisto logic. Should do requests and return data # """ def __init__(self, base_url=None, verify=None, proxy=None, token=None): self.base_url = base_url self.verify = verify self.headers = { 'EnterpriseApiKey': token, 'Accept': 'application/json', 'Content-Type': 'application/json' } self.proxy = proxy def http_request(self, method, url_suffix, body=None, params=None): try: full_url = self.base_url + url_suffix res = requests.request( method, full_url, data=body, headers=self.headers, params=params, proxies=self.proxy, verify=self.verify) res.raise_for_status() return res.json() except ValueError: return res.text except HTTPError: err_json = res.json() err_msg = '' if 'message' in err_json: err_msg = err_msg + \ 'Error: {0}.\n'.format(err_json['message']) elif 'http_response' in err_json: err_msg = err_msg + \ 'Error: {0}.\n'.format(err_json['http_response']) if 'code' in err_json: err_msg = err_msg + \ 'QRadar Error Code: {0}'.format(err_json['code']) return_error(err_msg) return "" def test_quinc(self): res = self.http_request('GET', 'api/v2/enterpriseapi/statuscheck') return res.lower() def get_jobstatus(self, args): caseID = args['caseID'] jobID = args['jobID'] url = 'api/v2/enterpriseapi/core/' + str(caseID) + \ '/getjobstatus/' + str(jobID) res = self.http_request('GET', url) if 'resultData' not in res: # if no data take state from first level of nesting contents = create_contents(caseID, jobID, res['state'], res) return wrap_jobstate_context(contents, "Current job state: " + res['state']) resultData = json.loads(res['resultData']) if 'RealData' not in resultData: # if no data take state from first level of nesting contents = create_contents(caseID, jobID, res['state'], resultData) return wrap_jobstate_context(contents, "Current job state: " + res['state']) RealData = json.loads(resultData['RealData']) if 'TaskStatusList' not in RealData: # if no data take state from first level of nesting contents = create_contents(caseID, jobID, res['state'], RealData) return wrap_jobstate_context(contents, "Current job state: " + res['state']) task = RealData['TaskStatusList'][0] if task is not None: if task['State'] is None: contents = create_contents(caseID, jobID, 'Unknown', task) return wrap_jobstate_context(contents, "Cannot get job state") if task['State'] != 'Success': contents = create_contents(caseID, jobID, task['State'], task) return wrap_jobstate_context(contents, "Current job state: " + task['State']) else: result = json.loads(task['Results'][0]['Data']) res = json.loads(task['Results'][1]['Data']) if result['OperationType'] == 24: # software inventory contents = create_contents( caseID, jobID, 'Success', res['Applications']) return wrap_jobstate_context( contents, tableToMarkdown( 'Applications', res['Applications'], [ 'Name', 'Version', 'Publisher', 'InstallDate', 'InstallLocation', 'InstallSource', 'EstimatedSizeInBytes' ])) elif result['OperationType'] == 12: # volatile data contents = create_contents(caseID, jobID, 'Success', res) return wrap_jobstate_context(contents, "Job completed successfully") elif result['OperationType'] == 11: # memory dump memdumpres = json.loads(task['Results'][2]['Data']) contents = create_contents(caseID, jobID, 'Success', memdumpres) return wrap_jobstate_context(contents, "Job completed successfully") else: contents = create_contents(caseID, jobID, 'Success', task) return wrap_jobstate_context(contents, "Job completed successfully") contents = create_contents(caseID, jobID, 'Failed', None) return wrap_jobstate_context(contents, "Job exited unexpectedly") def get_jobstatus_processlist(self, args): jobStatus = self.get_jobstatus(args) contents = jobStatus['Contents'] newContents = create_contents(contents['CaseID'], contents['ID'], contents['State'], "") message = "(to get path to snapshot job should be finished) " if 'Result' not in contents: message += "No Result in response scheme" return wrap_jobstate_context(newContents, message) if 'SnapshotDetails' not in contents['Result']: message += "No Result.SnapshotDetails in response scheme" return wrap_jobstate_context(newContents, message) if 'File' not in contents['Result']['SnapshotDetails']: message += "No Result.SnapshotDetails.File in response scheme" return wrap_jobstate_context(newContents, message) newContents['Result'] = contents['Result']['SnapshotDetails']['File'] return wrap_jobstate_context(newContents, newContents['Result']) def get_jobstatus_memorydump(self, args): jobStatus = self.get_jobstatus(args) contents = jobStatus['Contents'] newContents = create_contents( contents['CaseID'], contents['ID'], contents['State'], "") contents = contents['Result'] message = "(to get path to memory dump job should be finished) " if 'ResultFiles' not in contents: message += "No ResultFiles in response scheme" return wrap_jobstate_context(newContents, message) if not contents['ResultFiles']: message += "ResultFiles is empty" return wrap_jobstate_context(newContents, message) contents = contents['ResultFiles'][0] if 'Path' not in contents: message += "No Path in response scheme" return wrap_jobstate_context(newContents, message) newContents['Result'] = contents['Path'] return wrap_jobstate_context(newContents, newContents['Result']) def jobstatus_scan(self, args): caseJobID = args['caseJobID'] preparedParameters = caseJobID.split("_") preparedParameters = { 'caseID': preparedParameters[0], 'jobID': preparedParameters[1] } jobStatus = self.get_jobstatus(preparedParameters) contents = jobStatus['Contents'] newContents = create_contents(preparedParameters['caseID'], preparedParameters['jobID'], 'Unknown') if 'State' not in contents: return wrap_jobstate_context(newContents, "No state in job result") newContents['State'] = contents['State'] return wrap_jobstate_context(newContents, "Current job state: " + newContents['State']) def legacyagent_runvolatilejob(self, args): if ('caseid' not in args or args['caseid'] is None): args['caseid'] = self.get_processing_case_id()['Contents'] url = 'api/v2/enterpriseapi/agent/' + str(args['caseid']) + '/volatile' data = { 'ips': {'targets': [args['target_ip']]}, 'Volatile': { 'Operation': 12, 'IncludeProcessTree': True, 'ProcessTreeOptions': { 'DetectHiddenProcesses': True, 'IncludeDlls': True, 'IncludeSockets': True } } } jobID = self.http_request('POST', url, json.dumps(data)) contents = create_contents(args['caseid'], jobID, 'Unknown') contents['Type'] = 'Volatile' return { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': contents, 'HumanReadable': "JobID: " + str(jobID), 'EntryContext': create_jobstate_context(contents) } def legacyagent_runmemoryacquisition(self, args): if ('caseid' not in args or args['caseid'] is None): args['caseid'] = self.get_processing_case_id()['Contents'] url = 'api/v2/enterpriseapi/agent/' + str(args['caseid']) + \ '/memoryacquistion' data = { 'ips': {'targets': [args['target_ip']]}, 'MemoryAcquistion': {'Operation': 11} } jobID = self.http_request('POST', url, json.dumps(data)) contents = create_contents(args['caseid'], jobID, 'Unknown') contents['Type'] = 'LegacyMemoryDump' return { 'Type': entryTypes['note'], 'ContentsFormat': formats['json'], 'Contents': contents, 'HumanReadable': "JobID: " + str(jobID), 'EntryContext': create_jobstate_context(contents) } def read_casefile(self, args): url = 'api/v2/enterpriseapi/core/readfilecontents' filepath = args['filepath'] data = self.http_request('POST', url, json.dumps(filepath)) return { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': data, 'EntryContext': {'Accessdata.File.Contents': data} } def get_processing_case_id(self): url = 'api/v2/enterpriseapi/processingcaseid' processingcaseId = self.http_request('GET', url) return { 'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': processingcaseId, 'EntryContext': {ACCESS_DATA + '.ProcessingCaseId': processingcaseId} } def test_module(client): return client.test_quinc() def quinc_get_jobstatus_command(client, args): return client.get_jobstatus(args) def quinc_get_jobstatus_processlist_command(client, args): return client.get_jobstatus_processlist(args) def quinc_get_jobstatus_memorydump_command(client, args): return client.get_jobstatus_memorydump(args) def quinc_jobstatus_scan_command(client, args): return client.jobstatus_scan(args) def quinc_legacyagent_runvolatilejob_command(client, args): return client.legacyagent_runvolatilejob(args) def quinc_legacyagent_runmemoryacquisition_command(client, args): return client.legacyagent_runmemoryacquisition(args) def quinc_read_casefile_command(client, args): return client.read_casefile(args) def quinc_get_processing_case_id_command(client): return client.get_processing_case_id() def main(): use_ssl = not demisto.params().get('insecure', True) url = demisto.params().get('server_name') + ':4443/' token = demisto.params()['Token'] if not demisto.params().get('proxy'): if 'HTTP_PROXY' in os.environ: del os.environ['HTTP_PROXY'] if 'HTTPS_PROXY' in os.environ: del os.environ['HTTPS_PROXY'] if 'http_proxy' in os.environ: del os.environ['http_proxy'] if 'https_proxy' in os.environ: del os.environ['https_proxy'] PROXIES = { 'http': None, 'https': None } # type: dict else: PROXIES = { 'http': os.environ['http_proxy'] or os.environ['HTTP_PROXY'], 'https': os.environ['https_proxy'] or os.environ['HTTPS_PROXY'] } LOG('Command being called is %s' % (demisto.command())) try: client = Client(url, use_ssl, PROXIES, token) if demisto.command() == 'test-module': # This is the call made when pressing the integration Test button. demisto.results(test_module(client)) if demisto.command() == 'accessdata-get-jobstatus-processlist': demisto.results( quinc_get_jobstatus_processlist_command( client, demisto.args())) if demisto.command() == 'accessdata-get-jobstatus-memorydump': demisto.results( quinc_get_jobstatus_memorydump_command( client, demisto.args())) if demisto.command() == 'accessdata-jobstatus-scan': demisto.results( quinc_jobstatus_scan_command( client, demisto.args())) if demisto.command() == 'accessdata-legacyagent-get-processlist': demisto.results( quinc_legacyagent_runvolatilejob_command( client, demisto.args())) if demisto.command() == 'accessdata-legacyagent-get-memorydump': demisto.results( quinc_legacyagent_runmemoryacquisition_command( client, demisto.args())) if demisto.command() == 'accessdata-read-casefile': demisto.results( quinc_read_casefile_command( client, demisto.args())) if demisto.command() == 'accessdata-get-processing-case-id': demisto.results( quinc_get_processing_case_id_command(client)) except Exception as e: return_error( "Failed to execute {} command. Error: {}".format( demisto.command(), str(e))) if __name__ in ['__main__', 'builtin', 'builtins']: main()