Appendix A: API guide
This section explains how to use the FortiNDR API.
FortiNDR REST API currently supports the following:
- Files submission for scanning
- Retrieve files verdict result
- Get file STIX2 report
- Starting network share scan
- Events API support (detections based on source IP/Mac/hostname and anomaly type)
Get an administrator API key
You can submit files for analysis using API with an API key. You can generate an API key using the GUI or CLI. The API key has all access privileges of the admin user.
The token is only displayed once. If you lose the token, you must generate a new one.
Upload files using API
You can use API to upload files for Express Malware Analysis. The maximum upload file size is 200MB.
To use API to upload files, generate a token. The token is only displayed once. If you lose the token, generate a new one.
To generate a token using CLI:
execute api-key <user-name>
To generate a token using GUI:
- Go to System > Administrator and edit an administrator.
- In the API Key section, click Generate.
Use an API key
When making API calls, the API key is required in the request. You can include the API key in the API request header or URL parameter.
To pass the API token by request header, explicitly add the following field to the request header.
Authorization: Bearer <YOUR-API-TOKEN>
To pass the API token by URL parameter, explicitly include the following field in the request URL parameter.
access_token=<YOUR-API-TOKEN>
Submit files
/api/v1/files
You can submit files for analysis through the /api/v1/files
endpoint with an administrator API key.
For a list of supported file types and formats, see FortiNDR traffic and files input types .
Submit a file using one of the following methods.
Method |
Description |
---|---|
JSON data |
The JSON data must be encoded in base64 format. Encode the file directly into the HTTP body as JSON data using the |
Multi-part file |
The multi-part file does not need to be encoded in base64 format. Include the file in the HTTP body as a multi-part file. |
In both methods, you can use the API key as a URI parameter or the Authorization field in the header. Passwords for zip files are optional. You can view the verdict of submitted files in Virtual Security Analyst > Express Malware Analysis.
Example 1 of submitting a file or zip file via JSON data using the Python Requests module:
self.session.post(url='/api/v1/files?access_token=***API-KEY HERE***', data={" file_name": " b64encode(FILENAME)", "file_content": b64encode(open(PATH_TO_FILE, "rb").read())}, "password":" ***ZIP FILE PASSWORD HERE(OPTIONAL)***")
Example 2 of submitting a file or zip file via JSON data using the Python Requests module:
self.session.post(url='/api/v1/files', headers={'Authorization': 'Bearer ***API-KEY HERE***'} data={" file_name": " b64encode(FILENAME)", "file_content": b64encode(open(PATH_TO_FILE, "rb").read())}, "password":" ***ZIP FILE PASSWORD HERE(OPTIONAL)***")
Example 1 of submitting a file or zip file as a multi-part file using the Python Requests module:
self.session.post(url='/api/v1/files? access_token=***API-KEY HERE***'', data={"password":”***ZIP FILE PASSWORD HERE(OPTIONAL)***”}, files={"file":( os.path.basename(PATH_TO_FILE),open(PATH_TO_FILE,"rb"))})
Example 2 of submitting a file or zip file as a multi-part file using the Python Requests module:
self.session.post(url='/api/v1/files', headers={'Authorization': 'Bearer ***API-KEY HERE***'}, data={"password":”***ZIP FILE PASSWORD HERE(OPTIONAL)***”}, files={"file":( os.path.basename(PATH_TO_FILE),open(PATH_TO_FILE,"rb"))})
Upload file by JSON data
Encode the file name into the HTTP body as JSON data using the file_name
field.
Encode the file contents into the HTTP body as JSON data using the file_content
field. The maximum file size is 200MB.
You have the option to include the password in the HTTP body as JSON data using the password
field where a password is needed to extract an archived file.
The following is an example of Python request module by JSON data.
requests.post(url='/api/v1/files',
params={'access_token': 'u4VvEDpUATpJbFUfpbCzlSduTddCOIs'},
data={ 'file_name': b64encode('samples.zip'),
' file_content': b64encode(open('samples.zip', 'rb').read()),
' password': 'xxxxxxxx'})
Upload file by multi-part file
The following is an example of Python request module by multi-part file.
requests.post(url='/api/v1/files',
params={'access_token': 'u4VvEDpUATpJbFUfpbCzlSduTddCOIs'},
files={'samples.zip':open('samples.zip', 'rb')})
Retrieve file verdict results
/api/v1/verdict
Supported search query parameters |
Description |
---|---|
|
Get file IDs from a submission ID obtained after uploading a file. |
|
Get verdict result from file ID. |
|
Get the latest verdict result from MD5 checksum of the file. |
sha1 |
Get the latest verdict result from SHA1 checksum of the file. |
Sha256 |
Get the latest verdict result from SHA256 checksum of the file. |
The query string can only have one search query parameter.
Examples
GET /api/v1/verdict?sid= ***submission_id***
{ "results": { "fileids": [ 7,8,9,10,11,12,13,14,15
], "total_fileids": 9 } }
Field |
Description |
---|---|
|
File IDs in one file submission. If the file is an archived or compressed file, only files supported by FortiNDR after extraction are accepted and only file IDs of supported files appear. |
total_fileids
|
Total number of file IDs. |
GET /api/v1/verdict?fileid= ***file_id***
{ "results": { "file_id": 5742600, "virus_name": "W32/Miner.VI!tr", "md5": "bbd72472f8d729f4c262d6fe2d9f2c8c", "sha512": "cce8e67772f19bcfe5861e4c1b8eec87016bb7cf298735db633490243bc0391a017c7d6b805f225775405598614be48c5479cb7f1c54d957e6129effbf9cca37", "file_size": 1141544, "source": "http://172.16.77.46/api/sample_download/1106042791/", "severity": "High", "category": "Trojan", "family":"Emotet", "feature_composition": [ { "feature_type": "Trojan", "appearance_in_sample": 986 }, { "feature_type": "Application", "appearance_in_sample": 95 } ], "create_date": "2020-07-31", "confidence": "High", "file_type": "PE", "victim_ip": "172.19.235.225", "attacker_ip": "172.16.77.46", "victim_port": 35400, "attacker_port": 80, "engine_version": 1.013, "kdb_version": 1.037, "tmfc": 0, "pbit": 3 } }
Field |
Description |
---|---|
|
ID of the file. |
virus_name
|
FortiNDR virus name. |
|
For file uploaded by API or GUI, |
|
No Risk, Low, Medium, High, or Critical. |
|
For clean file: Clean. For malicious file, one of the following: Generic Attack, Downloader, Redirector, Dropper, Ransomware, Worm, PWS, Rootkit, Banking Trojan, Infostealer, Exploit, Virus, Application, Multi, CoinMiner, DoS, BackDoor, WebShell, SEP, Proxy, Trojan, Phishing, Fileless, Wiper, or Industroyer. |
|
FortiNDR virus family name. |
|
JSON objects containing feature composition data for malicious file.
|
|
For clean file: N/A. For other file: Low, Medium, or High. |
|
PE, PDF, MSOFFICE, HTML, ELF, VBS, VBA, JS. |
|
Reserved. |
|
Debug only. |
|
The archive file name if the current file was extracted from an archive/zip file. |
Example of problems retrieving results
{ "http_code": 400, "message": "INVALID_PARAM" }
Field |
Description |
---|---|
|
See HTTP status table. |
message
|
Messages include:
|
Submitted file errors explanation:
When using /ap1/v1/verdict?sid=xxx
to retrieve the file verdict in the following two cases:
- Oversized file
- Oversized archive contents
You will get reply: {"http_code": 400, "message":"OVERSIZED_FILE"}
In the other following cases:
- Unextractable archive
- File is still in queue
- File is still scanned
You will get successful reply with only supported file ids in the fileids list:
{ "results": { "fileids": [xx], "total_fileids": x } }
Once you get the fileid
from submit id, using /ap1/v1/verdict?fileid=xxx
In the following two cases:
- File is still in queue
- File is still to be scanned
You will get reply: {"http_code": 200, "message":"DATA_IN_PROCESS"}
Get file stix2 report
/api/v1/report
Supported search query parameters |
Description |
---|---|
fileid
|
Get report from file ID. |
|
Get report of the latest file with the MD5 checksum of the file. |
|
Get report of the latest file with the SHA1 checksum of the file. |
|
Get report of the latest file with the SHA256 checksum of the file. |
The query string can only have one search query parameter.
Examples
GET /api/v1/report?fileid= ***file_id***
{ "results": { *** STIX2 report content *** } }
HTTP status table
HTTP code |
Description |
---|---|
200 |
OK: API request successful. |
400 |
Bad Request. |
403 |
Forbidden: Request is missing authentication token, invalid authentication token, or administrator is missing access profile permissions. |
404 |
Resource Not Found: Unable to find the specified resource. |
405 |
Method Not Allowed: Specified HTTP method is not allowed for this resource. |
413 |
Request Entity Too Large. |
424 |
Failed Dependency. |
500 |
Internal Server Error. |
Start Network Share scan
/api/v1/nfs/scan
Required query parameters |
Description |
---|---|
|
The Network Share profile name under which the scan task will be created. |
Examples
GET /api/v1/nfs/scan?sname= ***network share profile name*** { "http_code": 200, "message": "OK" }
Example of failed to start Network Share scan
{ "http_code": 400, "message": "Scanning in Progress" }
Events API support
/api/v1/events
Query parameters |
Description |
---|---|
ip |
Get anomaly events with device IPv4 or IPv6 address. User needs specify one of [ip, hostname, mac] in the request. |
hostname |
Get anomaly events with device hostname. User needs specify one of [ip, hostname, mac] in the request. |
mac |
Get anomaly events with device mac address. User needs specify one of [ip, hostname, mac] in the request. |
type |
Specify the anomaly type events, one of [ botnet, entrypted-attack, network-attack, fortiguard-ioc, week-communication, ml-discovery, malware ]. |
start_time |
The start time of events, specified as a Unix timestamp in seconds. |
End_time |
The end time of events, specified as a Unix timestamp in seconds. |
start |
The starting point or offset from which the paginated events are returned. Default 0. |
size |
The number of events to be returned per page. Default 500. |
Examples
GET /api/v1/events?ip= 192.168.1.114 &type=network-attack&start_time=1695020154&end_time=1698111999 &start=0&size=2 { "results":[ { "event_time":"2023-10-23 16:15:53", "source_ip":"192.168.1.114", "source_port":38123, "destination_ip":"192.168.1.110", "destination_port":17185, "severity":"Low", "attack_name":"Nmap.Script.Scanner" }, { "event_time":"2023-10-23 16:15:53", "source_ip":"192.168.1.114", "source_port":38124, "destination_ip":"192.168.1.110", "destination_port":17185, "severity":"Low", "attack_name":"Nmap.Script.Scanner" } ] }