API reference¶
The Vulners Perimeter Scanner API is part of the official Vulners Python SDK v4 (pip install -U vulners): every method lives under the v.vscanner namespace of the Vulners client (with an identical awaitable mirror on AsyncVulners). It provides basic project management and data retrieval API for automation and integration purposes.
Requirements¶
-
Python: 3.10+ (
pip install -U vulners). -
API key: Please sign up to Vulners. Go to your personal menu by clicking on your name at the top right corner. Click on the API KEYS tab. Generate API key with the scope "api" and apply it to the library.
Disclaimer¶
In the examples below, localhost is used as an IP address, but Perimeter Scanner works only with public hosts. Also, uuides are shortened for the sake of examples, this is not the case in real data.
Getting started¶
All the callable methods use Vulners REST API. Automate your audit routines with Vulners. To get started you need to know your license id (daily/hourly quota numbers are reported in the license object of project responses):
from vulners import Vulners
v = Vulners(api_key="YOUR_API_KEY_HERE")
licenses = v.vscanner.licenses.list()
license_id = licenses["licenseList"][0]["id"]
{
"licenseList": [
{
"id": "e0671ce0-..-bbb",
"type": "free",
"expiration": "2999-01-01T00:00:00"
},
{
"id": "d4657eb6-..-9d7",
"type": "vnmap-professional",
"expiration": "2022-04-15T00:00:00"
},
{
"id": "319b1ad1-..-45d",
"type": "professional",
"expiration": "2022-04-15T00:00:00"
}
]
}
Project management¶
To get started, you should create a new project. The project has three required parameters: name, notification, and license id. Notification is an object, containing options such as period ("disabled", "asap", "hourly", or "daily") and method (via either or both email and slack). You can use the v.vscanner.notification() helper to create a notification object, or v.vscanner.disabled_notification() if you do not want to get notifications. So create a new project with this code:
Creating new project¶
notification = v.vscanner.notification(period="asap", emails=["[email protected]"])
# if no notifications needed
# notification = v.vscanner.disabled_notification()
project = v.vscanner.projects.create(
name="my project",
license_id="0305fbd1-..-8a7",
notification=notification,
)
{
"_id": "4e0a9778-..-4d0",
"name": "my project",
"owner": "e5bc65b8-..-675",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"tasks_count": 0,
"tasks": [],
"admins": [],
"viewers": [],
"notification": {
"period": "daily",
"email": ["[email protected]"],
"slack": ["https://hooks.slack.com/services/..."]
}
}
Editing project¶
With projects.update you can edit existing project parameters. To set new values you should additionally specify the project id. It is a full replace — specify all parameters explicitly, otherwise they will be overwritten:
project = v.vscanner.projects.update(
project["_id"],
name="new project name",
license_id=project["license"]["id"],
notification=project["notification"],
result_expire_in=None, # keep results forever
)
{
"_id": "4e0a9778-..-4d0",
"name": "new project name",
"owner": "e5bc65b8-..-675",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"tasks_count": 0,
"tasks": [],
"admins": [],
"viewers": [],
"notification": {
"period": "daily",
"email": ["[email protected]"],
"slack": ["https://hooks.slack.com/services/..."]
}
}
Getting project data¶
Using this method, you can get data about existing projects:
projects = v.vscanner.projects.list()
[{
"_id": "4e0a9778-..-4d0",
"name": "new project name",
"owner": "e5bc65b8-..-675",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"tasks_count": 0,
"tasks": [],
"admins": [],
"viewers": [],
"notification": {
"period": "daily",
"email": ["[email protected]"],
"slack": ["https://hooks.slack.com/services/..."]
}
}]
Deleting project¶
To delete project you can use this method:
result = v.vscanner.projects.delete(project["_id"])
None in case of success, or error message
Task Management¶
The second step is to create tasks. The task schedules a network scan. To create the task you should specify the parent project id, task name, list of networks, list of ports (or port ranges), a scan timing profile ("T1"–"T5", nmap-style), enable flag and schedule string.
The schedule string is a crontab string. It is a set of 5 fields, which represent the time to execute the task. The crontab string contains following fields:
minutes[0-59] hours[0-23] day_of_month[1-31] month[1-12] day_of_week[1-7]
The crontab string construction is quite complicated for our API reference, so you can use this guide and generator: crontab guru.
Below are some examples:
'*/10 * * * *' means "Task will start every 10th minute"
'0 10 * * *' means "Task will start at 10am every day"
'0 10 1 5 *' means "Task will start at 10am every first day of May"
'0 10 * * 1' means "Task will start at 10am every monday"
Creating new task¶
To create a new task use the method below:
first_task = v.vscanner.projects.tasks.create(
project["_id"],
name="first task",
networks=["example.com", "127.0.0.1"],
ports=["1-65535"],
schedule="* 10 * * 1",
timing="T3",
enabled=True,
)
{
"_id": "52d0f18b-..-b60",
"name": "first task",
"schedule": "* 10 * * 1",
"networks": [
"example.com",
"127.0.0.1"
],
"validated_networks": [
"127.0.0.1/32",
"127.0.0.1/32"
],
"enabled": "False",
"valid": "True",
"total_hosts": 1,
"project_id": "4e0a9778-..-4d0",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"next_run": 1621850400.0,
"last_run": 0,
"resolved": [
"127.0.0.1",
"example.com"
],
"state": "disabled"
}
Editing task¶
To modify the task parameters you should also specify the existing task id:
first_task = v.vscanner.projects.tasks.update(
project["_id"],
first_task["_id"],
name="first task",
networks=["example.com", "127.0.0.1"],
ports=["1-65535"],
schedule="* 10 * * 2",
timing="T3",
enabled=True,
)
{
"_id": "52d0f18b-..-b60",
"name": "first task",
"schedule": "* 10 * * 2",
"networks": [
"example.com",
"127.0.0.1"
],
"validated_networks": [
"127.0.0.1/32",
"127.0.0.1/32"
],
"enabled": "False",
"valid": "True",
"total_hosts": 1,
"project_id": "4e0a9778-..-4d0",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"next_run": 1621850400.0,
"last_run": 0,
"resolved": [
"127.0.0.1",
"example.com"
],
"state": "disabled"
}
Forcing task¶
When a task is enabled, it will initiate according to the set schedule. If needed, a task can be forced using the tasks.start method, shown below:
first_task = v.vscanner.projects.tasks.start(project["_id"], first_task["_id"])
{
"_id": "52d0f18b-..-b60",
"name": "first task",
"schedule": "* 10 * * 2",
"networks": [
"example.com",
"127.0.0.1"
],
"validated_networks": [
"127.0.0.1/32",
"127.0.0.1/32"
],
"enabled": "False",
"valid": "True",
"total_hosts": 1,
"project_id": "4e0a9778-..-4d0",
"license": {
"id": "0305fbd1-..-8a7",
"name": "vnmap-professional:7a11ad6558a7",
"exp": 1649970000.0,
"max_hosts": 256,
"max_tasks": 5,
"daily_quota": 102400,
"hourly_quota": 10240,
"timing": 3,
"ports": "False"
},
"next_run": 1621850400.0,
"last_run": 0,
"resolved": [
"127.0.0.1",
"example.com"
],
"state": "disabled"
}
Deleting task¶
You can delete a task using the tasks.delete method:
result = v.vscanner.projects.tasks.delete(project["_id"], first_task["_id"])
None in case of success, or error message
Reporting¶
Getting results¶
The final step is to obtain results. When a task finishes, you can get the scanning results. Just call results.list with the project id. Compared to the v2 client, the filters are renamed: ports are filtered with in_port/ex_port lists, IPs and names are matched via search, and time windows use first_seen/last_seen epoch timestamps:
results = v.vscanner.projects.results.list(
project["_id"],
search="Search text occurrence in fields: name, ip or resolved.",
in_port=["80", "8080"],
ex_port=["81", "8084"],
min_cvss=3.0,
max_cvss=9.0,
sort="max_cvss", # 'ip', 'name', 'last_seen', 'first_seen', 'resolved', 'min_cvss', 'max_cvss'
sort_dir="desc",
offset=0,
limit=100,
)
{
"_id": "62d6eab7-..-92b",
"project_id": "4e0a9778-..-4d0",
"ip": "127.0.0.1",
"addr": 846214729,
"name": "example.com",
"resolved": "",
"published": "2021-04-15T13:59:03Z",
"scan_info": [
{
"port": "22",
"protocol": "tcp",
"service": "ssh",
"product": "OpenSSH",
"version": "8.2p1 Ubuntu 4ubuntu0.1",
"ostype": "Linux",
"extrainfo": "Ubuntu Linux; protocol 2.0",
"cpe": "cpe:/a:openbsd:openssh:8.2p1",
"vulnerabilities": [
{
"id": "CVE-2020-12062",
"cvss": 5.0
},
{
"id": "CVE-2020-14145",
"cvss": 4.3
},
{
"id": "CVE-2020-15778",
"cvss": 6.8
},
{
"id": "CVE-2021-28041",
"cvss": 4.6
},
{
"id": "MSF:AUXILIARY/SCANNER/SSH/FORTINET_BACKDOOR/",
"cvss": 0.0
}
]
}
]
}
Cleaning up results¶
Sometimes, it may be useful to clean up your data. You can delete a scan result using the results.delete method:
result = v.vscanner.projects.results.delete(project["_id"], "62d6eab7-...2b")
None in case of success, or error message