Many customers have used various API scripts to extract job results from MSV to facilitate results reporting. One method that is much quicker than using the jobs API is the search API. The search API is what is used by Report Builder and it pulls back a subset of the job results. It's fairly simple to use and can make reports much simpler because there's not the mound of data that is returned by the jobs API.
The input to the search api is a JSON blob with the details of the search and what fields you would like to bring back. From any report in report builder, you can just click "View Request Data" to see a working example of the JSON such as the one below:
{
"conditions": [
{
"conditions": [
{
"match_field": "id",
"match_object": "job",
"operator": "in",
"value": [
2498,
2499,
2500,
2501
]
}
],
"operator": "and"
}
],
"operator": "or",
"time": {
"start": "2022-09-30T23:37:44Z",
"end": "2024-09-30T23:37:44Z"
},
"include": {
"actions": [
"vid",
"name",
"tags"
],
"job_actions": [
"actors",
"detecting_technologies",
"blocking_technologies"
]
}
}
For this search, you are looking for the results of 4 specific jobs (that were ran in the two years) . The job numbers are 2498, 2499, 2500 and 2501.
The data returned is: Action VID, Action Name, Action Tags, Source Actor, Blocking Technology, Detecting Technology. This is seen in the response below:
{
"job_actions": [
{
"id": 47091,
"status": "ran",
"began_at": "2024-09-25T12:32:33.543Z",
"ended_at": "2024-09-25T12:33:27.351Z",
"blocked": true,
"detected": true,
"alerted": false,
"passed": true,
"action_id": 27656,
"attacker_ip": "192.168.34.100",
"target_ip": "192.168.34.100",
"attack_node_id": 63,
"target_node_id": 63,
"blocking_technologies": [],
"detecting_technologies": [
10,
14
],
"unix_ended_at": 1727267607
},
{
"id": 47092,
"status": "ran",
"began_at": "2024-09-25T12:34:07.410Z",
"ended_at": "2024-09-25T12:34:35.707Z",
"blocked": true,
"detected": true,
"alerted": true,
"passed": true,
"action_id": 22210,
"attacker_ip": "192.168.101.10",
"target_ip": "192.168.101.10",
"attack_node_id": 27,
"target_node_id": 27,
"blocking_technologies": [
2
],
"detecting_technologies": [
2,
9
],
"unix_ended_at": 1727267675
},
{
"id": 47093,
"status": "ran",
"began_at": "2024-09-25T13:42:50.803Z",
"ended_at": "2024-09-25T13:43:44.561Z",
"blocked": true,
"detected": false,
"alerted": false,
"passed": true,
"action_id": 27656,
"attacker_ip": "192.168.34.100",
"target_ip": "192.168.34.100",
"attack_node_id": 63,
"target_node_id": 63,
"blocking_technologies": [],
"detecting_technologies": [],
"unix_ended_at": 1727271824
},
{
"id": 47094,
"status": "ran",
"began_at": "2024-09-25T13:48:49.467Z",
"ended_at": "2024-09-25T13:49:02.202Z",
"blocked": true,
"detected": true,
"alerted": true,
"passed": true,
"action_id": 32116,
"attacker_ip": "192.168.101.10",
"target_ip": "192.168.101.10",
"attack_node_id": 27,
"target_node_id": 27,
"blocking_technologies": [
2
],
"detecting_technologies": [
2
],
"unix_ended_at": 1727272142
}
],
"security_technologies": [
{
"id": 2,
"vendor": "CrowdStrike",
"product": "Falcon Endpoint Security",
"product_type": "EDR / Endpoint Security Platform",
"sectech_type": "endpoint"
},
{
"id": 9,
"vendor": "McAfee",
"product": "Endpoint Security Platform",
"product_type": "Endpoint Protection",
"sectech_type": "endpoint"
},
{
"id": 10,
"vendor": "Check Point",
"product": "Next Generation Firewall",
"product_type": "Firewall",
"sectech_type": "network"
},
{
"id": 14,
"vendor": "Symantec",
"product": "Endpoint Protection",
"product_type": "Antivirus",
"sectech_type": "endpoint"
}
],
"actions": [
{
"id": 22210,
"name": "Protected Theater - STONEBRIDGE, VALEFOR, Execution",
"vid": "A105-456",
"tags": [
"20-00015071",
"Malware:STONEBRIDGE",
"Malware:VALEFOR",
"ATT&CK:Defense Evasion",
"ATT&CK:T1055",
"CWE:706",
"ATT&CK:Privilege Escalation",
"ATT&CK:T1071.001",
"ATT&CK:Command and Control"
]
},
{
"id": 27656,
"name": "Host CLI - EICAR TXT File Download via PowerShell",
"vid": "A104-281",
"tags": [
"ATT&CK:Execution",
"ATT&CK:T1059.001",
"ATT&CK:T1086",
"EICAR"
]
},
{
"id": 32116,
"name": "Protected Theater - SODINOKIBI, Execution, Variant #2",
"vid": "A104-984",
"tags": [
"ATT&CK:T1486",
"Impact:Availability",
"Ransomware",
"ATT&CK:Impact",
"Malware:SODINOKIBI"
]
}
],
"actors": [
{
"id": 63,
"security_zone_id": 24,
"name": "win19-sep-cloud",
"hostname": "win19-sep-cloud",
"mgmt_ip": "192.168.34.100",
"sim_ip": null,
"monitor_ip": null,
"os_base": "windows",
"fq_hostname": "win19-sep-cloud.mandiant.local",
"user_tags": [
"EndpointActor"
]
},
{
"id": 27,
"security_zone_id": 21,
"name": "win10-pa-crowdstrike",
"hostname": "win10-pa-crowdstrike",
"mgmt_ip": "192.168.101.10",
"sim_ip": null,
"monitor_ip": null,
"os_base": "windows",
"fq_hostname": "win10-pa-crowdstrike",
"user_tags": []
}
]
}
That response is much easier to deal with than the massive nested JSON returned by /jobs/xxxx.json.
Try it out and let me know what you think. I can add sample code if anyone is interested.
Hi @TomAtGoogle can you please post some more details or an example about this?
I understood how to see examples of JSON for the request, but I didn't understand which API you have to pass them to. Is it done with a POST?
Thank you,
Paolo
@paolocarrara - you are correct. Check out this method
def runQuery(myQuery):
endpoint = session.post("https://" + str(director_ip) + "/search", json=myQuery)
if endpoint.status_code != 200:
print(f'Unable to connect with status code {endpoint.status_code}')
sys.exit(-1)
search_results = json.loads(endpoint.text)
return search_results
One would simply pass the JSON into this method and it will run the query using POST.
Hi @TomAtGoogle thank you, I was able to use the API with a browser extension like API Tester (I added header Authorization: Bearer <api key> for authentication).
One more question please.
How do I know the name of the fields to be included?
For example, you have included these fields:
‘include": {
‘actions': [
‘vid’,
‘name’,
‘tags’,
[..]
What if in addition to these, for the action, I also wanted to include the ‘type’?
Using /jobs/xxxx.json I see that ‘type’ is in the ‘action_type’ field, but if I include ‘action_type’ in the request json, I don't get the desired information.
Another example. ‘tags’ that you used in your example, refers to “verodin_tags” in the json.
How do I know the exact name of the fields to be included?
Thank you very much!
Paolo
I usually go into Report Builder and just create a data table to show me what fields are available and/or what fields I want. Check out this screenshot:
The request data is the what I need to get those fields back.