NAV Navbar
python cUrl

Introduction

Welcome to the Sndbox API! You can use our API to access reports, download and submit samples and much more

Examples are available in Shell and Python in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.

Authentication

You can set the apikey header this way:

import requests # pip install requests

BASE_URL = 'https://api.sndbox.com/developers/'
API_KEY = 'EXAMPLE'

requests.get(BASE_URL, headers={'apikey': API_KEY})
# With cUrl, you can just pass the correct header with each request
curl "https://api.sndbox.com/developers/" -H "apikey: EXAMPLE"

Make sure to replace EXAMPLE with your API key.

Sndbox uses API keys to allow access to the API. You can register a new account to get an API key. If you already have an existing user, your key which can be found in your profile

Sndbox expects for the API key to be included in all API requests to the server in a header that looks like the following:

apikey: d6b1377f-6c6e-4a2f-9c4c-9af320b40181

Analyses

Upload a file

You can upload a local file like this:

import requests

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

sample_to_upload = '/Users/example/Desktop/test_files/wannacry'
upload_options = {'analysis_time': 120, 'private': 0}
headers = {'apikey': API_KEY}
with open(sample_to_upload, 'rb') as sample:
    upload_request = requests.post(BASE_URL.format('files'), headers=headers, files={'file': sample}, data=upload_options)

print(upload_request.json())
curl -X POST \
  https://api.sndbox.com/developers/files \
  -H 'apikey: EXAMPLE' \
  -F file=@/Users/example/Desktop/test_files/wannacry

The above command returns the following JSON structure:

{
  "id": "0a1726f3-1ecc-44b2-8956-20881ac27d2b",
  "name": "wannacry",
  "md5": "d49ba037de7f093dff6fd017e6c9043a",
  "private": false,
  "created_at": "2019-06-05T19:41:08.119Z"
}

This endpoint submits a file for analysis, the analysis process can take 2 to 3 minutes.

The returned ID (0a1726f3-1ecc-44b2-8956-20881ac27d2b in the example) is needed to make future references to this file:

You can check whether the analysis is completed, once it is completed you may request the final report or the PCAP network capture

HTTP Request

POST https://api.sndbox.com/developers/files

FormData Parameters

Parameter Default value Description
file - Required
The file you wish to upload. It is recommended that your files will have a valid extension, however it is not mandatory. We will try our best to detect the file type ourselves.
private false Whether the sample should be kept private or not, public analyses are open for everyone to view
ultrafast_mode false Enable SNDBOX Ultrafast analysis mode
timebombs true When enabled, delay timers will be replaced with a minimal value to trigger process
timebombs_mode calm the mode of the timebomb.
Possible values: calm, aggressive
analysis_time 120 Time for the file to be run in the sandbox
file_monitoring true Monitor process file api calls
registry_monitoring true Monitor process registry api calls
rpc_monitoring true Monitor inter-process RPC communication
platform_id win7_x32 Operation system to be used.
Possible values: win7_x32, win10_x64
command_line - Additional command line arguments that might be required by the program
archive_password - Password required to decrypt and extract files from the archive
tags[] - Tag to be attached to the analysis, this parameter can be sent multiple times to attach more than one tag.
email_notification false Receive email notification upon analysis completion.

Response codes

HTTP Code Meaning
201 File was accepted for analysis
401 Unauthorized, your API key is wrong.
400 One of the provided arguments is invalid, see body message for more info
403 You don't have permission to perform the operation, see body message for more info
413 File exceeded size limits
415 Unsupported file type, see supported file types
429 Exceeded plan limits

Get metadata and status

curl "https://api.sndbox.com/developers/files/94758358-6d6c-4190-91d0-086d0cf45f39" -H "apikey: EXAMPLE"

A request will respond with the following JSON structure:

{
  "id": "94758358-6d6c-4190-91d0-086d0cf45f39",
  "group": "PE32",
  "name": "sciter-glfw-basic-bitmap.exe",
  "md5": "370a9a73a21822a59a5a59ef201b0a47",
  "private": false,
  "status": {
    "static": {
      "code": 1,
      "message": null
    },
    "dynamic": {
      "code": 1,
      "message": null
    }
  },
  "created_at": "2019-06-07T16:10:11.534Z",
  "protected": false,
  "score": 0.311466638896375,
  "verdict": "clean",
  "sha1": "372d2eb596356ce47258ef5d507aeb91008a47d9",
  "sha256": "e4b7b54455aeefceb80fb0f093dab39b77c2801c8bd1d3e396c414472c112e98"
}

Checking the status can be done by polling

import requests
import time

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

PENDING_CODE = 0
COMPLETED_CODE = 1
FAILED_CODE = 2

def get_metadata(analysis_id):
    headers = {'apikey': API_KEY}
    metadata_endpoint = BASE_URL.format('files/' + analysis_id)
    metadata_request = requests.get(metadata_endpoint, headers=headers , stream=True)

    parsed = metadata_request.json()

    return parsed

def main():
    analysis_id = '94758358-6d6c-4190-91d0-086d0cf45f39' # replace this
    metadata = get_metadata(analysis_id)
    while metadata["score"] is None:
        dynamic_status_code = metadata["status"]["dynamic"]["code"]

        if dynamic_status_code == PENDING_CODE:
            print("analysis is in progress")

        if dynamic_status_code == FAILED_CODE:
            # this shouldn't happen
            print("analysis failed")
            return

        time.sleep(10)

        metadata = get_metadata(analysis_id)

    print("analysis is ready!")

if __name__ == '__main__':
    main()

Requesting the metadata of an analysis can be useful in some cases, including checking on the status of it, or simply getting the final verdict.

Usually, you would want to poll this endpoint to check whether the analysis is ready, so when it does, you can download the full report.

This can be done by checking the status code of the dynamic analysis, as it finishes last. The code can be found in the dynamic object inside the status object, the possible codes can be found below:

Analysis status codes

Status code Meaning
0 The analysis is still in progress, check again in a few minutes
1 The analysis is completed
2 The analysis failed, see the message attribute

Getting the final verdict is as easy as parsing the verdict field in the response. We will respond with one of the following verdicts:

Final verdicts

Verdict Meaning
clean No threat was detected
suspicious Unusual activity yet no definite threat was detected
malicious A threat was detected

HTTP request

GET https://api.sndbox.com/developers/files/:id

URL Parameters

Parameter Default value Description
id - Required
The ID of the analysis that was given at upload time

Response codes

HTTP Code Meaning
200 Request was successful
400 One of the provided arguments is invalid, see body message for more info
401 Unauthorized, your API key is wrong.
403 You don't have permission to access this analysis
404 The analysis was not found
429 Exceeded plan limits

Get metadata and status (bulk)

curl -X POST -H "Content-Type: application/json" \
  -H "apikey: EXAMPLE" \
  -d '{"bulk_action": "GET", "query": [{"id": "73ed72bc-d67e-49e1-ba74-facc0c15ab54"}, {"id": "bcdd29d4-8ea7-4b79-85d3-ecfb4b3d64fd"}, {"id": "101e999c-343c-4119-b78f-8bf43439dc30"}, {"id": "7dc6a563-5e45-47d2-85d1-80abd3383aee"}]}' \
  https://api.sndbox.com/developers/files/bulk
import requests

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

headers = {'apikey': API_KEY}
body = {
    "bulk_action": "GET",
    "query": [
        {"id": "73ed72bc-d67e-49e1-ba74-facc0c15ab54"},
        {"id": "bcdd29d4-8ea7-4b79-85d3-ecfb4b3d64fd"},
        {"id": "101e999c-343c-4119-b78f-8bf43439dc30"},
        {"id": "7dc6a563-5e45-47d2-85d1-80abd3383aee"}
    ]
}
metadata_request = requests.post(BASE_URL.format('files/bulk'), headers=headers, json=body)

print(metadata_request.json())

A request will respond with the following JSON structure:

{
  "results": [
    {
      "id": "73ed72bc-d67e-49e1-ba74-facc0c15ab54",
      "status_code": 200,
      "verdict": "suspicious",
      "group": "PE32",
      "name": "Shareit.exe",
      "md5": "c9bffc76bf4473d95a117bf7a3c0c1be",
      "private": false,
      "status": {
        "static": {
          "code": 1
        },
        "dynamic": {
          "code": 1,
          "message": null
        }
      },
      "created_at": "2019-09-03T13:04:15.902Z",
      "protected": false,
      "score": 0.955104223214811,
      "sha1": "1cb5a30b1cbfe77ecfd153ea172f403116689fdf",
      "sha256": "6fbdfbd1b6beab1d2c70d2b1b1a54885f2c1b273169ee4369dbcbec8ec1a98de"
    },
    {
      "id": "bcdd29d4-8ea7-4b79-85d3-ecfb4b3d64fd",
      "status_code": 200,
      "verdict": "malicious",
      "group": "PE32",
      "name": "elarvolume.exe",
      "md5": "baae400188788bef21f7f447ac75c2e5",
      "private": false,
      "status": {
        "static": {
          "code": 1
        },
        "dynamic": {
          "code": 1,
          "message": null
        }
      },
      "created_at": "2019-09-03T12:58:41.980Z",
      "protected": false,
      "score": 1,
      "sha1": "5379695fd4e99f5455da8524386958c1d6dc9f7c",
      "sha256": "748c9b10cf385a5d5cc06c2a9431689633ba6ffb889d9f229da05a2da5a34989"
    },
    {
      "id": "101e999c-343c-4119-b78f-8bf43439dc30",
      "status_code": 403,
      "message": "You don't have a permission to access this resource"
    },
    {
      "id": "7dc6a563-5e45-47d2-85d1-80abd3383aee",
      "status_code": 404,
      "message": "File does not exist"
    }
  ]
}

When working with high volume of analyses, it's possible to save time by querying our servers in bulk instead of requesting the metadata of one resource at a time.

For each one of your queried IDs, we will respond with a corresponding status code(not to be confused with the HTTP status code of the request), which you can use to determine whether or not the query succeeded.

The API supports up to 50 queries in one request.

Query status codes

Status code Meaning
200 Successful query, the fields can be parsed exactly like described here
403 You don't have permission to access this analysis
404 The requested ID was not found

HTTP request

POST https://api.sndbox.com/developers/files/bulk

JSON body parameters

Parameter Default value Description
bulk_action - Required
Name of the bulk action.
Possible values: GET
query - Required
Array of query items, see query.* below
query.id - Required
The ID of the analysis that was given at upload time

Response codes

HTTP Code Meaning
207 Request was successful, see the body for detailed status per query
400 One of the provided arguments is invalid, see body message for more info
401 Unauthorized, your API key is wrong.
429 Exceeded plan limits

Download final report

You can download the JSON report locally this way:

import requests
import shutil

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

analysis_id = '56170840-7ee2-4fd6-ae4b-59b34d38d629' # replace this

headers = {'apikey': API_KEY}
report_endpoint = BASE_URL.format('files/' + analysis_id + '/json')
report_request = requests.get(report_endpoint, headers=headers , stream=True)
with open('report.json.gz', 'wb') as f:
        shutil.copyfileobj(report_request.raw, f)
 curl "https://api.sndbox.com/developers/files/56170840-7ee2-4fd6-ae4b-59b34d38d629/json" -H "apikey: EXAMPLE" -o "report.json.gz"

the downloaded file is compressed with gzip

Once the analysis is completed, the final JSON report is available for download. The report contains information from all the building blocks of Sndbox: static, dynamic and network analysis. We go over it in great detail in the final report section

HTTP request

GET https://api.sndbox.com/developers/files/:id/json

URL Parameters

Parameter Default value Description
id - Required
The ID of the analysis that was given at upload time

Response codes

HTTP Code Meaning
200 File is attached
400 The analysis id is not valid
401 Unauthorized, your API key is wrong.
404 Analysis was not found / the analysis still in progress
429 Exceeded plan limits

Download PCAP

You can download the PCAP file locally this way:

import requests
import shutil

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

analysis_id = '56170840-7ee2-4fd6-ae4b-59b34d38d629' # replace this

headers = {'apikey': API_KEY}
report_endpoint = BASE_URL.format('files/' + analysis_id + '/pcap')
report_request = requests.get(report_endpoint, headers=headers , stream=True)
with open('dump.pcap', 'wb') as f:
        shutil.copyfileobj(report_request.raw, f)


 curl "https://api.sndbox.com/developers/files/56170840-7ee2-4fd6-ae4b-59b34d38d629/pcap" -H "apikey: EXAMPLE" -o "dump.pcap"

Once the analysis is completed, the PCAP file is available for download. 8.8.8.8 is defined as the default DNS server of the machine, 57.0.0.1/24 is the local network.

HTTP request

GET https://api.sndbox.com/developers/files/:id/pcap

URL Parameters

Parameter Default value Description
id - Required
The ID of the analysis that was given at upload time

Response codes

HTTP Code Meaning
200 File is attached
400 the analysis id is not valid
401 Unauthorized, your API key is wrong.
404 Analysis was not found / the analysis still in progress
429 Exceeded plan limits

Querying

Request verdict for an MD5 (bulk)

curl -X POST -H "Content-Type: application/json" \
  -H "apikey: EXAMPLE" \
  -d '{"bulk_action": "GET", "query": [{ "hash": "31adbdafc2d7aa959a623851c4b26d82"}, { "hash": "cf7f66d4b1f84537639fdbe50566d1c8"}, { "hash": "9a9de36fc18564526858167eba70d141"}, { "hash": "89b375b11a22e342b2d3a23fc64fd72f"}, {"hash": "152cd7014811ae8980981a825e5843b0" }, {"hash": "d14ed384a50c9cb6da3c478ede849077" }, {"hash": "d14ed384a50c9cb6da3c478ede84aaaa" }]}' \
  http://https://api.sndbox.com/developers/files/verdict/bulk
import requests

BASE_URL = 'https://api.sndbox.com/developers/{}'
API_KEY = 'EXAMPLE'

headers = {'apikey': API_KEY}
body = {
    "bulk_action": "GET",
    "query": [
        {"hash": "31adbdafc2d7aa959a623851c4b26d82"},
        {"hash": "cf7f66d4b1f84537639fdbe50566d1c8"},
        {"hash": "9a9de36fc18564526858167eba70d141"},
        {"hash": "89b375b11a22e342b2d3a23fc64fd72f"},
        {"hash": "152cd7014811ae8980981a825e5843b0"},
        {"hash": "d14ed384a50c9cb6da3c478ede849077"},
        {"hash": "d14ed384a50c9cb6da3c478ede84aaaa"}
    ]
}
verdict_request = requests.post(BASE_URL.format('files/verdict/bulk'), headers=headers, json=body)

print(verdict_request.json())

A request will respond with the following JSON structure:

{
  "results": [
    {
      "hash": "31adbdafc2d7aa959a623851c4b26d82",
      "status_code": 200,
      "verdict": "malicious"
    },
    {
      "hash": "cf7f66d4b1f84537639fdbe50566d1c8",
      "status_code": 200,
      "verdict": "clean"
    },
    {
      "hash": "9a9de36fc18564526858167eba70d141",
      "status_code": 200,
      "verdict": "malicious"
    },
    {
      "hash": "89b375b11a22e342b2d3a23fc64fd72f",
      "status_code": 200,
      "verdict": "malicious"
    },
    {
      "hash": "152cd7014811ae8980981a825e5843b0",
      "status_code": 200,
      "verdict": "malicious"
    },
    {
      "hash": "d14ed384a50c9cb6da3c478ede849077",
      "status_code": 200,
      "verdict": "malicious"
    },
    {
      "hash": "d14ed384a50c9cb6da3c478ede84aaaa",
      "status_code": 404
    }
  ]
}

Our verdict API allows you to search over millions of samples analyzed by us and get a verdict for your files easily and quickly.

The verdict API is comes handy when dealing with large volume of files, allowing you to iterate and get a verdict for them so you can decide which files are worth uploading for a full analysis.

For each one of your queried MD5s, we will respond with a corresponding status code(not to be confused with the HTTP status code of the request), which you can use to determine whether or not the query succeeded.

The API supports up to 50 queries in one request.

Query status codes

Status code Meaning
200 Successful query, the different verdict types are described here
404 The requested MD5 was not found in our records

HTTP request

POST https://api.sndbox.com/developers/files/verdict/bulk

JSON body parameters

Parameter Default value Description
bulk_action - Required
Name of the bulk action.
Possible values: GET
query - Required
Array of query items, see query.* below
query.hash - Required
The MD5 hash of the file you wish to get a verdict for.

Response codes

HTTP Code Meaning
207 Request was successful, see the body for detailed status per query
400 One of the provided arguments is invalid, see body message for more info
401 Unauthorized, your API key is wrong.
429 Exceeded plan limits

Final report

structure of the JSON report:

{
  "Signatures": [],
  "Dynamic": {},
  "Static": {},
  "networking_analysis": {},
  "machine_learning": {}
}

The report consists of 5 main sections:

Dynamic analysis

Example of a truncated version of the dynamic section

{
  "Dynamic": {
    "ProcessTree": [
      {
        "command_line": "",
        "process_path": "\\Device\\HarddiskVolume2\\Users\\Petra\\AppData\\Local\\Temp\\wannacry.exe",
        "process_name": "wannacry.exe",
        "pid": 2148,
        "children": [
          {
            "command_line": "",
            "process_path": "\\Device\\HarddiskVolume2\\Windows\\System32\\cmd.exe",
            "process_name": "cmd.exe",
            "pid": 2400,
            "children": [
              {
                "command_line": "",
                "process_path": "\\Device\\HarddiskVolume2\\Windows\\System32\\cscript.exe",
                "process_name": "cscript.exe",
                "pid": 2500
              }
            ]
          }
        ]
      }
    ],
    "Processes": {
      "2148": {
        "ProcessName": "wannacry.exe",
        "CommandLine": null,
        "Features": {
          "file_created": [
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\b.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\c.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\msg",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\msg\\m_english.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\r.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\s.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\t.wnry",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\taskdl.exe",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\taskse.exe",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\u.wnry",
            "00000000.pky",
            "00000000.eky",
            "00000000.res",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\@WanaDecryptor@.exe",
            "228901560156947.bat",
            "@Please_Read_Me@.txt",
            "C:\\Users\\<USER>\\Desktop\\~SD7F99.tmp",
            "C:\\Users\\<USER>\\Documents\\~SD8795.tmp",
            "C:\\Users\\<USER>\\Documents\\mQgKNFmgmaeIOrVgVWf.doc.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\TsCcAJiRRSN.pptx.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\wjAsEmTrXqd.rtf.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\@Please_Read_Me@.txt",
            "C:\\Users\\<USER>\\Documents\\@WanaDecryptor@.exe",
            "C:\\Users\\<USER>\\Documents\\JClPdxrLKJCjjNFe.docm.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\kSNsFPLnHi.docm.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\mIzIwGQmmCoqgqK.docm.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\pUyAOxdbAZgmaNQP.docm.WNCRYT",
            "C:\\~SD9CF8.tmp",
            "C:\\@Please_Read_Me@.txt",
            "C:\\@WanaDecryptor@.exe"
          ],
          "registry_opened": ["\\REGISTRY\\MACHINE\\Software\\WanaCrypt0r"],
          "file_opened": [
            "C:\\tmpfdmyf3\\",
            "C:\\Windows\\SYSTEM32\\sechost.dll",
            "C:\\Windows\\system32\\IMM32.DLL",
            "C:\\Windows\\system32\\IMM32.DLL",
            "C:\\Windows\\system32\\IMM32.DLL",
            "C:\\Users\\<USER>\\AppData\\Local\\Temp"
          ],
          "file_written": [
            "C:\\Users\\<USER>\\AppData\\Local\\Temp\\@WanaDecryptor@.exe",
            "228901560156947.bat",
            "@Please_Read_Me@.txt",
            "C:\\Users\\<USER>\\Documents\\mQgKNFmgmaeIOrVgVWf.doc.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\mQgKNFmgmaeIOrVgVWf.doc",
            "00000000.res",
            "C:\\Users\\<USER>\\Documents\\TsCcAJiRRSN.pptx.WNCRYT",
            "C:\\Users\\<USER>\\Documents\\TsCcAJiRRSN.pptx"
          ],
          "mutex": [
            "MsWinZonesCacheCounterMutexA",
            "Global\\MsWinZonesCacheCounterMutexA0"
          ],
          "registry_read": [
            {
              "data": "43003A005C00550073006500720073005C00500065007400720061005C0041007000700044006100740061005C004C006F00630061006C005C004D006900630072006F0073006F00660074005C00570069006E0064006F00770073005C00540065006D0070006F007200610072007900200049006E007400650072006E00650074002000460069006C00650073000000",
              "value": "Cache",
              "key": "\\REGISTRY\\USER\\S-1-5-21-1119815420-2032815650-2779196966-1000\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
            },
            {
              "data": null,
              "value": "Type",
              "key": "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Microsoft Enhanced RSA and AES Cryptographic Provider"
            }
          ],
          "file_read": [
            "c.wnry",
            "C:\\Windows\\system32\\attrib.exe",
            "C:\\Windows\\system32\\icacls.exe",
            "t.wnry"
          ],
          "registry_written": [
            {
              "data": "C:\\Users\\<USER>\\AppData\\Local\\Temp",
              "value": "wd",
              "key": "\\REGISTRY\\MACHINE\\Software\\WanaCrypt0r"
            }
          ]
        },
        "CallsByHandle": [
          {
            "tid": 2152,
            "index": 3867,
            "api": "ZwCreateFile",
            "arguments": {
              "Status": "0x00000000",
              "ShareAccess": "0x00000000",
              "CreateOptions": "0x00000064",
              "Handle": "0x0000221C",
              "FilePath": "\\??\\C:\\Users\\Petra\\Documents\\@Please_Read_Me@.txt",
              "TransactionHandle": "0x00000000",
              "Information": "0x00000002",
              "DesiredAccess": "0x40110081",
              "CreateDisposition": "0x00000002",
              "RootDirectory": "(null)"
            },
            "time": 1560150884.857417
          },
          {
            "tid": 2152,
            "index": 3899,
            "api": "ZwWriteFile",
            "arguments": {
              "Status": "0x00000000",
              "ApcRoutine": "0x00000000",
              "ByteOffsetHigh": "0x00000000",
              "ByteOffsetLow": "0x00000000",
              "Length": "0x000003A5",
              "Key": "0x00000000",
              "ApcContext": "0x002B227C",
              "FileHandle": "0x0000221C",
              "IoStatusBlock": "0x002B227C",
              "Event": "0x0000224C"
            },
            "time": 1560150884.918417
          },
          {
            "tid": 2152,
            "index": 3913,
            "api": "ZwClose",
            "arguments": {
              "Status": "0x00000000",
              "Handle": "0x0000221C"
            },
            "time": 1560150884.948417
          }
        ],
        "ApiStats": {
          "ZwCreateFile": 297,
          "ZwReadFile": 100,
          "ZwClose": 5417
        },
        "ApiCalls": [
          {
            "tid": 2152,
            "index": 0,
            "api": "ZwOpenKey",
            "arguments": {
              "Status": "0x00000000",
              "DesiredAccess": "0x80000000",
              "KeyHandle": "0x00000004",
              "RootDirectory": "(null)",
              "ObjectName": "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
            },
            "time": 1560150867.212417
          },
          {
            "tid": 2152,
            "index": 1,
            "api": "ZwClose",
            "arguments": {
              "Status": "0x00000000",
              "Handle": "0x00000004"
            },
            "time": 1560150867.212417
          }
        ]
      },
      "2400": {},
      "2500": {}
    }
  }
}

The dynamic analysis focuses of the file execution aspect. It answers the question "what did it do in the system" and provides insights into windows API calls made per process as well as registry, mutex and file operations.

Inside the dynamic analysis you will find 2 main sections:

ProcessTree

Provides a tree-like structure of spawned processes, each process can have nested children. Children can be either created processes (for example, by CreateUserProcess) or a different process that has a relationship with the parent, for example, an injected process.

Processes

List of process objects, the keys are the PIDs used by the processes. For each process we provide insights:

Processes.pid.ApiCalls

List of observed API calls made by the process, along with the arguments and return values.

Processes.pid.CallsByHandle

Same as Processes.pid.ApiCalls but the API calls are grouped by the same handle to aid analysis

Processes.pid.Features

This object contains high level view of registry, mutex, and files operations. This data is generated from the ApiCalls observed.

Although not always present, we support supported the following features:

Files related:

Registry related:

Mutex related:

In this section we normalize the paths, the name of the current user will be replaced with <USER>

Process.pid.ApiStats

Count of API calls, the key is the name of the API used

Machine learning and scoring

Example of the machine learning section

{
  "machine_learning": {
    "version": 2.01,
    "dynamic_ml_prediction": {
      "file_recreated_prediction": 0.9937365055084229,
      "file_read_prediction": 0.9999125003814697,
      "file_renamed_prediction": 0.998776376247406,
      "file_exists_prediction": 0.9245164394378662,
      "file_opened_prediction": 0.9996418952941895,
      "file_written_prediction": 0.9987816214561462,
      "handle_prediction": 0.999686598777771,
      "mutex_prediction": 0.9991567134857178,
      "process_tree_prediction": 0.970740795135498
    },
    "static_ml_prediction": {
      "prediction": 1.0,
      "label": 1.0
    },
    "sndbox_score": {
      "prediction": 1.0,
      "label": 1
    }
  }
}

Sndbox is an AI product, we utilize Machine Learning technologies to better detect malicious behavior.

We evaluate features from both the static and the dynamic level. Based on data we already have seen, we predict the chances of each feature being malicious. For instance, we can see in the example that based on the files that were written (file_written_prediction) and read (file_read_prediction), there's a high chance of it being malicious.

The final score (sndbox_score) is calculated taking into account all predictions. For most use cases this is enough, but the full breakdown is also available (dynamic_ml_prediction and static_ml_prediction)

Each prediction can range between 0.0 (legitimate) to 1.0 (malicious)

Signatures and behavior patterns

Example of a truncated signatures section

{
  "Signatures": [
    {
      "indicator": true,
      "description": "Creates a file that usually instructs the ransomware victims on how to pay the ransom and get their files back",
      "process_relationship": false,
      "severity": 5,
      "type": "Ransomware",
      "id": 48,
      "name": "Create instructions",
      "marks": [
        {
          "calls_by_handle": [
            {
              "category": "thunder",
              "index": 2568,
              "stacktrace": [],
              "status": 1,
              "api": "ZwCreateFile",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "ShareAccess": "0x00000003",
                "CreateOptions": "0x00020060",
                "Handle": "0x00001CE8",
                "FilePath": "@Please_Read_Me@.txt",
                "TransactionHandle": "0x00000000",
                "Information": "0x00000002",
                "DesiredAccess": "0x40100080",
                "CreateDisposition": "0x00000005",
                "RootDirectory": "\\Device\\HarddiskVolume2\\Users\\Petra\\AppData\\Local\\Temp"
              },
              "time": 1560150880.571417,
              "tid": 2152,
              "return_value": 0
            }
          ],
          "pid": 2148
        }
      ]
    },
    {
      "indicator": false,
      "description": "Process creation by it self is relatively considered a normal behavior for programs to do, for example a browser usually opens child processes and it's legitimate. However in a different context a process creation can be considered malicious. There are processes which in their normal behavior, they do not execute a new process. When an event of such weird behavior occurs, of a not legitimate process creation by an unusual process, there is a high chance it is malicious.",
      "marks": [
        {
          "calls_by_handle": [
            {
              "category": "thunder",
              "index": 4164,
              "stacktrace": [],
              "status": 1,
              "api": "ZwCreateUserProcess",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "ProcessFlags": "0x00000001",
                "ProcessDesiredAccess": "0x02000000",
                "CommandLine": "cscript.exe  //nologo m.vbs",
                "ThreadHandle": "0x00000B44",
                "ThreadDesiredAccess": "0x02000000",
                "ImagePathName": "C:\\Windows\\system32\\cscript.exe",
                "ProcessHandle": "0x00000B48",
                "ThreadFlags": "0x00000004",
                "ChildPID": "0x000009C4"
              },
              "time": 1560140165.541594,
              "tid": 2404,
              "return_value": 0
            }
          ],
          "command_line": "cscript.exe  //nologo m.vbs",
          "pid": 2400,
          "child": 2500
        }
      ],
      "process_relationship": true,
      "severity": 0,
      "type": "Process Relationship",
      "id": 1,
      "name": "Creation"
    },
    {
      "indicator": true,
      "description": "Creates files with a known ransomware extension, for example (cv.txt.encrypted)",
      "marks": [
        {
          "calls_by_handle": [
            {
              "category": "thunder",
              "index": 9903,
              "stacktrace": [],
              "status": 1,
              "api": "ZwOpenFile",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "ShareAccess": "0x00000007",
                "Handle": "0x00002C90",
                "FilePath": "s.wnry",
                "OpenOptions": "0x00200000",
                "Information": "0x00000001",
                "DesiredAccess": "0x00020080",
                "RootDirectory": "\\Device\\HarddiskVolume2\\Users\\Petra\\AppData\\Local\\Temp"
              },
              "time": 1560150901.611475,
              "tid": 2236,
              "return_value": 0
            }
          ],
          "pid": 2232
        }
      ],
      "process_relationship": false,
      "severity": 5,
      "type": "Ransomware",
      "id": 47,
      "name": "Extensions"
    },
    {
      "indicator": true,
      "description": "Triggered when a process creates an executable",
      "marks": [
        {
          "calls_by_handle": [
            {
              "category": "thunder",
              "index": 6146,
              "stacktrace": [],
              "status": 1,
              "api": "ZwWriteFile",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "ApcRoutine": "0x00000000",
                "ByteOffsetHigh": "0x00000000",
                "ByteOffsetLow": "0x00010000",
                "Length": "0x00010000",
                "Key": "0x00000000",
                "ApcContext": "0x002B227C",
                "FileHandle": "0x00002DE4",
                "IoStatusBlock": "0x002B227C",
                "Event": "0x00002E34"
              },
              "time": 1560150889.544417,
              "tid": 2152,
              "return_value": 0
            },
            {
              "category": "thunder",
              "index": 11780,
              "stacktrace": [],
              "status": 1,
              "api": "ZwCreateFile",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "ShareAccess": "0x00000000",
                "CreateOptions": "0x00000064",
                "Handle": "0x00004C88",
                "FilePath": "\\??\\C:\\Python27\\Lib\\idlelib\\@WanaDecryptor@.exe",
                "TransactionHandle": "0x00000000",
                "Information": "0x00000002",
                "DesiredAccess": "0x40110081",
                "CreateDisposition": "0x00000002",
                "RootDirectory": "(null)"
              },
              "time": 1560150897.856417,
              "tid": 2152,
              "return_value": 0
            }
          ],
          "pid": 2148
        }
      ],
      "process_relationship": false,
      "severity": 3,
      "type": "Dropper",
      "id": 67,
      "name": "File Dropped"
    },
    {
      "indicator": true,
      "description": "Obtain the hostname of the machine.",
      "marks": [
        {
          "calls_by_handle": [
            {
              "category": "thunder",
              "index": 1777,
              "stacktrace": [],
              "status": 1,
              "api": "ZwQueryValueKey",
              "flags": {},
              "arguments": {
                "Status": "0x00000000",
                "Name": "ComputerName",
                "Length": "0x00000080",
                "KeyHandle": "0x000015C4",
                "ValueName": "ComputerName",
                "Data": "500045005400520041002D00500043000000",
                "KeyValueInformationClass": "0x00000001"
              },
              "time": 1560150875.664417,
              "tid": 2152,
              "return_value": 0
            }
          ],
          "pid": 2148
        }
      ],
      "process_relationship": false,
      "severity": 1,
      "type": "Environment Check",
      "id": 4,
      "name": "Computer Name"
    },
    {
      "indicator": false,
      "severity": 3,
      "name": "ET WEB_CLIENT SUSPICIOUS Possible automated connectivity check (www.google.com)",
      "signature_type": "network",
      "marks": [
        {
          "src_port": 49172,
          "event_type": "alert",
          "proto": "TCP",
          "pcap_cnt": 119,
          "timestamp": "2019-06-04T07:31:45.073230+0000",
          "app_proto": "http",
          "src_ip": "57.0.0.102",
          "tx_id": 0,
          "alert": {
            "category": "Potentially Bad Traffic",
            "severity": 2,
            "rev": 3,
            "gid": 1,
            "signature": "ET WEB_CLIENT SUSPICIOUS Possible automated connectivity check (www.google.com)",
            "action": "allowed",
            "signature_id": 2018430
          },
          "flow_id": 1724365454467418,
          "dest_ip": "172.217.212.100",
          "dest_port": 80
        }
      ],
      "type": "Suricata",
      "description": "Suricata Alert"
    }
  ]
}

We aggregate information from all layers (Static, Dynamic, Network) and detect behavior patterns used by malware, the detected patterns/behavior are called Signatures.

Signatures aids analysis by providing human-readable explanation (no more reading lengthy log files), and improves detection.

Structure

All signatures share the following metadata specific fields:

field description
name The name of the signature, for example Browser secrets for credential stealing
severity Ranges from 0 to 5, the higher the severity the higher the malicious impact is
description Human readable description of what triggered the signature or how it is being used in the wild
type The group of the signature, we group signatures by their nature of behavior. For example, The signatures Email and Browser secrets will have the type Stealer
process_relationship whether or not this signature indicates a relationship between two processes. A relationship can be a simple process creation, injection and more
marks the evidence, what triggered the signature

Since signatures are aggregated from different origin layers, the marks field structure will change based of the origin.

For example, for a signature that originated from the dynamic layer, you will have an array of API calls as well as the pid of the process that made them.

For a signature that originated from the network layer, you will have the metadata of the packet(s).

Available signatures

name type description severity
Bitsadmin Download Dropper Uses the bitsadmin utility to transfer a file over the network, usually used to maliciously drop an executable file 5
Browser secrets Stealer Tries to access the login/web data file where saved browser passwords are stored 5
Certificate tempering Abnormal Behavior Modifies system certificates 5
Create instructions Ransomware Creates a file that usually instructs the ransomware victims on how to pay the ransom and get their files back 5
Cryptominer Abnormal Behavior Opens a crypto-currency miner (trying to to connect to a crypto mining pool) 5
Delete Shadow Volume Copies Ransomware Delete machine snapshots. 5
Disables Security Abnormal Behavior Attempts to disable System Restore 5
Disk Partition Ransomware Writes directly to the hard drive, usually to modify the master boot record in order to execute a malicious code right after the BIOS 5
Doppelganging Process Relationship Process doppelganging is a technique that allows execution of a process without actually writing a file to the system, becoming truly evasive and fileless. 5
Email Stealer Tries to extract email credentials and conversations from email clients 5
Extensions Ransomware Creates files with a known ransomware extension, for example (cv.txt.encrypted) 5
FTP Stealer Tries to access FTP credentials from FTP clients 5
Hides shortcut icon Abnormal Behavior Hides the LNK shortcut icon, usually it is done when placing a malicious shortcut. 5
Hijack CLSID Persistency Changing CLSID properties, can be used as an evasive persistence method 5
Hijacking Process Relationship Take over a remote process thread. 5
Hollowing Process Relationship Process hollowing mechanism. Creating a process with a legitimate name, and replaces its content with a malicious file. 5
Injection Process Relationship Code injection to remote process. 5
Injection Process Relationship Code injection to remote process 5
Modify Proxy Abnormal Behavior Modifies proxy configuration file for traffic interception 5
MS Creation Process Relationship When an Office process creates another process, it is safe to assume the created process is malicious 5
MS RPC Process Relationship An Office process performs an unusual RPC communication with another process 5
Office Equation Abnormal Behavior Equation Editor is a legitimate process created by microsoft, however it can be used to run various exploits on the machine by bad actors. 5
Open Instructions Ransomware Opens instructions on how to decrypt the files and pay ransom, usually happens in the post-encryption stage 5
Powershell Download Dropper Opens powershell to download a file over the network, usually used to maliciously drop an executable file 5
Self Delete Abnormal Behavior The sample deleted itself from the disk. 5
System restore Abnormal Behavior Attempts to disable System Restore. 5
Wallpaper Ransomware Changes wallpaper image, usually used to show the ransom message to the infected user 5
WinDefender Abnormal Behavior Using service control to disable or delete the Windows Defender firewall 5
Create Thread Process Relationship 4
Deleted Executed Process Abnormal Behavior One of the executed processes was removed from the disk. 4
Interface Abnormal Behavior Modifies network interfaces 4
Javascript Abnormal Behavior Executing javascript. 4
Possible instruction creation Ransomware Creates a readme-like file in the system, usually instructs the ransomware victims on how to pay the ransom and get their files back. 4
Schtasks Persistency Using the schtasks (task scheduler) to execute a file in a scheduled manner. 4
Base64 decode Abnormal Behavior Uses the certutil certificate service to decode base64 string. 3
Browser data Stealer Access browser data such as bookmarks, cookies and history. 3
File Dropped Dropper Triggered when a process creates an executable 3
Hosts file Abnormal Behavior Changing content of hosts file. 3
IE Creation Process Relationship Browser creating a new process is an abnormal behavior and shouldnt normally happen. 3
Startup Persistency Persistency Generic persistency using the startup registry key. 3
Touch Wallpaper Ransomware Changes wallpaper or wallpaper registry settings, usually used to show the ransom message to the infected user 3
Wallpaper Settings Ransomware Changes wallpaper settings in registry. 3
WMI Process Relationship WMI communication detected. 3
Firewall Modifying Windows Rules Reading firewall rules from the registry. 2
Long Sleep Generic Long sleep has been detected 2
Multi Spawn Abnormal Behavior Spawns multiple processes 2
Open Multiple Browser Process Relationship Multiple browser processes have been executed. 2
Powershell Abnormal Behavior Executing powershell script 2
Registry Checking AntiVM Reading a VirtualMachine related registry data. 2
Service Process Relationship RPC Communication with services. 2
UAC Modifying Windows Rules Reading UAC (User Account Control) rules from the registry. 2
VM Port AntiVM Checking existence of VM port. 2
Computer Name Environment Check Obtain the hostname of the machine. 1
Device Enumeration AntiVM Hardware devices enumeration. 1
Disk Size AntiVM Checking size of disk. 1
File Existence AntiVM Check if VirtualMachine related file exists. 1
Generic Persistency Persistency File was both created on the disk, and written to the registry as a key value, indicating a possibly persistency. 1
Installed Processes Environment Check Check the registry for installed processes. Alternatively, can be used to find malware detection / research applications installed. 1
Internet Cache Abnormal Behavior Read Internet cache settings. 1
Machine GUID Environment Check Unique machine identifier 1
Process crash Abnormal Behavior Windows error reporting process is executing when a process crash occurred. 1
Process List AntiVM Processes enumeration, can be used to detect VirtualMachine related processes. Alternatively, can be used to find malware detection / research processes. 1
Process Termination Generic Process was terminated. 1
Uptime AntiVM Checking machine uptime. Sandbox machines up time tend to be low. 1
Uptime Plus AntiVM Checks Machine's Uptime and Memory Size. 1
Write To Temp Generic Writing files to Windows temp folder. 1
Creation Process Relationship Process creation by it self is relatively considered a normal behavior for programs to do, for example a browser usually opens child processes and it's legitimate. However in a different context a process creation can be considered malicious. There are processes which in their normal behavior, they do not execute a new process. When an event of such weird behavior occurs, of a not legitimate process creation by an unusual process, there is a high chance it is malicious. 0
Host Without DNS Anomaly host Communication with hosts without dns lookup. Direct communication may imply static ip of C&C hosts 4
Multiple User-Agents Anomaly host 4
Failed DNS Anomaly host Failed dns requests lookup of hosts. Might indicate dead or temporary C&C hosts. 3
Arp Count Network scan Multiple arp requests indicate network tempering 3
Failed HTTP Requests Anomaly host Failed http requests. Might indicated dead C&C hosts 3

Working with the report

This section features Python code examples of how to parse and work with the final report

Example 1: checking the existence of signatures

import json

with open('report.json', 'r') as report_file:
    report = json.load(report_file)

signatures = report["Signatures"]

ransomware_signatures = list(filter(lambda s: s["type"] == 'Ransomware', signatures))
if ransomware_signatures:
    print("Found ransomware related signatures!")

hollowing_signature = list(filter(lambda s: s["name"] == 'Hollowing', signatures))
if hollowing_signature:
    print("Found process hollowing signature!")


This can be useful if you are only interested in a subset of signatures, for list of available signatures see the Signatures section.

If you have a specific use-case for a signature that is not already implemented, feel free to send us signatures suggestions or see how to implement it yourself in the next example

Example 2: writing a custom signature logic - process injection via remote thread creation

import json


class Signature:
    def __init__(self, report):
        self._report = report

    def _find_processes(self, name):
        """
        Find pids of processes that match a given name
        :param name: string, name of the process we wish to find
        :return: list of int pids
        """
        processes = self._report["Dynamic"]["Processes"]
        pids_matched_name = [int(pid) for pid, process in processes.items() if process["ProcessName"] == name]
        return pids_matched_name


class ExplorerInjection(Signature):
    def __init__(self, *args):
        super().__init__(*args)

    @staticmethod
    def _is_remote_thread_creation(call, originating_pid, remote_pids):
        """
        Check if a given API call is responsible for a remote thread creation
        :param call: dict, the API call object
        :param originating_pid: int, which pid made this call
        :param remote_pids: list of int pids that are considered "remote"
        :return: boolean
        """
        if call["api"] not in ["ZwCreateThreadEx", "ZwCreateThread"]:
            return

        # PID arguments are passed as hexadecimal (base 16)
        create_in_pid = int(call["arguments"]["ChildPID"], 16)
        is_created_in_remote = create_in_pid in remote_pids
        is_created_in_self = create_in_pid == originating_pid

        return is_created_in_remote and not is_created_in_self

    def match(self):
        """
        Get pids of processes that create remote threads
        :return: int, pid
        """
        explorer_pids = self._find_processes("explorer.exe")

        processes = self._report["Dynamic"]["Processes"]
        for pid, process in processes.items():
            calls = process["ApiCalls"]
            thread_creations = [c for c in calls if self._is_remote_thread_creation(c, int(pid), explorer_pids)]

            if not thread_creations:
                continue

            yield pid


def main():
    with open("dll_injection.json", "r") as report_file:
        report = json.load(report_file)

    matches = ExplorerInjection(report).match()
    for match in matches:
        print("found remote thread creation from pid {} to explorer.exe!".format(match))


if __name__ == "__main__":
    main()

Output of the script

found remote thread creation from pid 2152 to explorer.exe!

In this example, we have implemented a signature that matches creation of a thread in a remote explorer.exe process.

We can verify it works by testing it against the report of multiple DLL injectors:

it's not limited to DLL injection, it should work for any type of injection that involves creating a remote thread.