Osquery
Osquery is an operating system instrumentation framework for Windows, OS X (macOS), Linux, and FreeBSD. Zentral can act as a remote server for Osquery, for configuration, query runs, file carvings, and log collection.
Zentral configuration
To activate the osquery module, you need to add a zentral.contrib.osquery section to the apps section in base.json.
Query tables
Zentral parses the SQL of a query to find the osquery tables that the query reads. The names are in lower case, and sorted. A query that reads no table, a compliance check that only returns a status, has an empty list of tables.
The query page and the query list of the web console show the tables. The run list shows them too, and Zentral finds them in the SQL that the run froze when it started, so a later change to the query does not change them. Zentral computes the tables when it shows them, and does not store them.
Zentral refuses a query with SQL that it cannot parse, and gives an error for the sql attribute. The error gives the position of the problem in the SQL when sqlglot reports one. An import of a standard pack fails if it has such a query, and the errors give the name of every query that does not parse. Correct the SQL and import the pack again.
Audit events
Zentral publishes a zentral_audit event when a user creates, updates or deletes an Osquery object from the web console or from the API: automatic table constructions, configurations, configuration packs, enrollments, file categories, packs, pack queries, queries, and distributed query runs. Each event carries the value of the object before and after the change, with the user, the source IP and the request that made it.
Most of these objects are managed with the Zentral Terraform provider: the automatic table constructions, the configurations, the configuration packs, the enrollments, the file categories, the packs and the queries. For these objects, the event records a change that did not come from the Terraform configuration.
Distributed query runs are not managed with Terraform. A run executes SQL on the machines, and the event records that action.
Two effects of a change have no event of their own:
- A change to a configuration increases the version of each of its enrollments. The event of the configuration records the change.
- A change to a pack query sets the update time of its pack. The event of the pack query records the change.
The “Halt current runs” option of a new run stops the other runs of the same query. Each stopped run has its own event.
Standard pack imports
An import of a standard pack — a PUT on /api/osquery/packs/<slug>/, or an upload in the web console — changes several objects at once. It publishes one osquery_pack_update event that reports the import, and one zentral_audit event for each object it changed. They share one event UUID, and the report is the first of them, so a reader can gather the whole import from any one of its events.
The report answers what the audit events cannot: what the import did as a whole. Its result is created, updated, present or deleted, and present says that the import ran and changed nothing. Its query_results counts the pack queries the import created, updated, deleted, or left as they were.
The report does not carry the difference between the two values of an object. The audit event of that object carries the whole value before and after the change.
HTTP API
Requests
Authentication
API requests are authenticated using a token in the Authorization HTTP header:
Authorization: Token the_token_string
See API authentication for how to create a service account, issue a token for it and set an expiry.
Content type
Zentral will parse the body of the request based on the Content-Type HTTP header:
Content-Type: application/jsonContent-Type: application/x-osquery-confContent-Type: application/yaml
Methods
Use PUT to update an object, and send all its attributes. PATCH is not available, and gives a 405 Method Not Allowed.
Paginated lists
The list endpoints answer with a page and not with an array:
{
"count": 132,
"next": "https://zentral.example.com/api/osquery/queries/?limit=50&offset=50",
"previous": null,
"results": []
}
Use the limit and the offset query parameters to select a page. The default limit is 50, and the maximum limit is 500. Read next until it is null to get all the objects.
/api/osquery/atcs/
List all ATCs.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewAutomaticTableConstruction" - Optional filter parameter:
name: name of the ATC.configuration_id: primary key of the configuration.
Examples:
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/atcs/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/atcs/?name=Santa+rules" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"name": "Santa rules",
"description": "Access the Google Santa rules.db",
"table_name": "santa_rules",
"query": "SELECT * FROM rules;",
"path": "/var/db/santa/rules.db",
"columns": [
"identifier",
"state",
"type",
"custommsg",
"timestamp"
],
"platforms": [
"darwin"
],
"created_at": "2023-01-30T09:39:35.965003",
"updated_at": "2023-01-30T09:39:35.965011"
}
]
Add a new ATC.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createAutomaticTableConstruction"
Example:
atc.json
{
"name": "Access example",
"description": "Access the example example.db",
"table_name": "example_table",
"query": "SELECT * FROM example;",
"path": "/var/db/example/example.db",
"columns": [
"one",
"two",
"three"
],
"platforms": [
"darwin",
"linux"
]
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/atcs/" \
-d @atc.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Access example",
"description": "Access the example example.db",
"table_name": "example_table",
"query": "SELECT * FROM example;",
"path": "/var/db/example/example.db",
"columns": [
"one",
"two",
"three"
],
"platforms": [
"darwin",
"linux"
],
"created_at": "2023-01-31T08:59:14.097316",
"updated_at": "2023-01-31T08:59:14.097333"
}
/api/osquery/atcs/<int:pk>/
Get a ATC.
method: GET
Content-Type: application/json
PBAC action: Osquery::Action::"viewAutomaticTableConstruction"
<int:pk>: the primary key of the ATC.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/atcs/2/" \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Access example",
"description": "Access the example example.db",
"table_name": "example_table",
"query": "SELECT * FROM example;",
"path": "/var/db/example/example.db",
"columns": [
"one",
"two",
"three"
],
"platforms": [
"darwin",
"linux"
],
"created_at": "2023-01-31T08:59:14.097316",
"updated_at": "2023-01-31T08:59:14.097333"
}
Update a ATC.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updateAutomaticTableConstruction" <int:pk>: the primary key of the ATC.
Example
atc_update.json
{
"name": "Access example",
"description": "Access the example example.db on all platforms",
"table_name": "example_table",
"query": "SELECT * FROM example;",
"path": "/var/db/example/example.db",
"columns": [
"one",
"two",
"three",
"four"
],
"platforms": [
"darwin",
"linux",
"windows",
"freebsd"
]
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/atcs/2/" \
-d @atc_update.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Access example",
"description": "Access the example example.db on all platforms",
"table_name": "example_table",
"query": "SELECT * FROM example;",
"path": "/var/db/example/example.db",
"columns": [
"one",
"two",
"three",
"four"
],
"platforms": [
"darwin",
"linux",
"windows",
"freebsd"
],
"created_at": "2023-01-31T08:59:14.097316",
"updated_at": "2023-01-31T09:05:08.326755"
}
Delete a ATC.
- method: DELETE
- PBAC action:
Osquery::Action::"deleteAutomaticTableConstruction" <int:pk>: the primary key of the ATC.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/atcs/2/"
Response (204 No Content)
/api/osquery/configurations/
List all Configurations.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewConfiguration" - Optional filter parameter:
name: Name of the configuration.
Examples:
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configurations/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configurations/?name=example" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"name": "example",
"description": "",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 600,
"options": {
"config_refresh": 120
},
"created_at": "2023-01-06T13:05:02.535763",
"updated_at": "2023-01-30T09:40:23.912582",
"file_categories": [],
"automatic_table_constructions": [
1
]
}
]
Add a new Configuration.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createConfiguration" - Required fields:
name: Name of the configuration.
Example:
configuration.json
{
"name": "example2",
"description": "description of example2",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 600,
"options": {
"config_refresh": 120
},
"file_categories": [
1
],
"automatic_table_constructions": [
1
]
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configurations/" \
-d @configuration.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2",
"description": "description of example2",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 600,
"options": {
"config_refresh": 120
},
"created_at": "2023-02-01T11:37:00.622052",
"updated_at": "2023-02-01T11:37:00.622077",
"file_categories": [
1
],
"automatic_table_constructions": [
1
]
}
/api/osquery/configurations/<int:pk>/
Get a Configuration.
method: GET
Content-Type: application/json
PBAC action: Osquery::Action::"viewConfiguration"
<int:pk>: The primary key of the configuration.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configurations/2/" \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2",
"description": "description of example2",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 600,
"options": {
"config_refresh": 120
},
"created_at": "2023-02-01T11:37:00.622052",
"updated_at": "2023-02-01T11:37:00.622077",
"file_categories": [
1
],
"automatic_table_constructions": [
1
]
}
Update a Configuration.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updateConfiguration" <int:pk>: The primary key of the configuration.- Required fields:
name: Name of the configuration.
Example
configuration_update.json
{
"name": "example2",
"description": "description of example2 updated",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 800,
"options": {
"config_refresh": 120
},
"file_categories": [],
"automatic_table_constructions": []
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configurations/2/" \
-d @configuration_update.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2",
"description": "description of example2 updated",
"inventory": true,
"inventory_apps": true,
"inventory_ec2": false,
"inventory_interval": 800,
"options": {
"config_refresh": 120
},
"created_at": "2023-02-01T11:37:00.622052",
"updated_at": "2023-02-01T11:39:12.664992",
"file_categories": [],
"automatic_table_constructions": []
}
Delete a Configuration.
- method: DELETE
- PBAC action:
Osquery::Action::"deleteConfiguration" <int:pk>: The primary key of the configuration.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/configurations/2/"
Response (204 No Content)
/api/osquery/configuration_packs/
List all Configuration Packs.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewConfigurationPack" - Optional filter parameter:
pack_id: primary key of the pack.configuration_id: primary key of the configuration.
Examples:
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/?pack_id=2" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"configuration": 2,
"pack": 2,
"tags": [
1
]
}
]
Add a new Configuration Pack.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createConfigurationPack" - Required fields:
pack: primary key of an existing pack.configuration: primary key of an existing configuration.
- Optional fields:
tags: list of primary keys of existing tags.
Example:
configurationpack.json
{
"configuration": 1,
"pack": 2,
"tags": [
2
]
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/" \
-d @configurationpack.json \
|python3 -m json.tool
Response:
{
"id": 2,
"configuration": 1,
"pack": 2,
"tags": [
2
]
}
/api/osquery/configuration_packs/<int:pk>/
Get a Configuration Pack.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewConfigurationPack" <int:pk>: The primary key of the configuration pack.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/2/" \
|python3 -m json.tool
Response:
{
"id": 2,
"configuration": 1,
"pack": 2,
"tags": [
2
]
}
Update a Configuration Pack.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updateConfigurationPack" <int:pk>: The primary key of the configurationpack.- Required fields:
pack: primary key of an existing pack.configuration: primary key of an existing configuration.
- Optional fields:
tags: list of primary keys of existing tags.
Example
configurationpack_update.json
{
"configuration": 1,
"pack": 1,
"tags": [
1
]
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/2/" \
-d @configurationpack_update.json \
|python3 -m json.tool
Response:
{
"id": 2,
"configuration": 1,
"pack": 1,
"tags": [
1
]
}
Delete a Configuration Pack.
- method: DELETE
- PBAC action:
Osquery::Action::"deleteConfigurationPack" <int:pk>: The primary key of the configuration pack.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/configuration_packs/2/"
Response (204 No Content)
/api/osquery/file_categories/
List all FileCategories.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewFileCategory" - Optional filter parameter:
name: name of the FileCategory.configuration_id: primary key of the configuration.
Examples:
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/file_categories/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/file_categories/?name=example" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"name": "example",
"slug": "example",
"description": "example description",
"file_paths": [],
"exclude_paths": [],
"file_paths_queries": [],
"access_monitoring": false,
"created_at": "2023-01-31T11:48:53.014319",
"updated_at": "2023-01-31T11:48:53.014332"
}
]
Add a new FileCategory.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createFileCategory"
Example:
file_category.json
{
"name": "example2",
"slug": "example2",
"description": "example2 description",
"file_paths": ["/usr/example2"],
"exclude_paths": ["/home/you/exclude1", "/home/me/exclude2"],
"file_paths_queries": [],
"access_monitoring": true
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/file_categories/" \
-d @file_category.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2",
"slug": "example2",
"description": "example2 description",
"file_paths": [
"/usr/example2"
],
"exclude_paths": [
"/home/you/exclude1",
"/home/me/exclude2"
],
"file_paths_queries": [],
"access_monitoring": true,
"created_at": "2023-01-31T14:09:46.079654",
"updated_at": "2023-01-31T14:09:46.079664"
}
/api/osquery/file_categories/<int:pk>/
Get a FileCategory.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewFileCategory" <int:pk>: the primary key of the FileCategory.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/file_categories/2/" \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2",
"slug": "example2",
"description": "example2 description",
"file_paths": [
"/usr/example2"
],
"exclude_paths": [
"/home/you/exclude1",
"/home/me/exclude2"
],
"file_paths_queries": [],
"access_monitoring": true,
"created_at": "2023-01-31T14:09:46.079654",
"updated_at": "2023-01-31T14:09:46.079664"
}
Update a FileCategory.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updateFileCategory" <int:pk>: the primary key of the FileCategory.
Example
file_category_update.json
{
"name": "example2 updated",
"description": "example2 description updated",
"file_paths": [
"/usr/bin/example2"
],
"exclude_paths": [
"/home/you/exclude1"
],
"file_paths_queries": [],
"access_monitoring": false
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/file_categories/2/" \
-d @file_categories_update.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "example2 updated",
"slug": "example2-updated",
"description": "example2 description updated",
"file_paths": [
"/usr/bin/example2"
],
"exclude_paths": [
"/home/you/exclude1"
],
"file_paths_queries": [],
"access_monitoring": false,
"created_at": "2023-01-31T11:48:53.014319",
"updated_at": "2023-01-31T14:13:39.306239"
}
Delete a FileCategory.
- method: DELETE
- PBAC action:
Osquery::Action::"deleteFileCategory" <int:pk>: the primary key of the FileCategory.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/file_categories/2/"
Response (204 No Content)
/api/osquery/packs/
List all Packs.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewPack" - Optional filter parameter:
name: Name of the pack.configuration_id: primary key of the configuration.
Examples:
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/packs/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/packs/?name=Default" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"name": "Default",
"slug": "default",
"description": "",
"discovery_queries": [],
"shard": null,
"event_routing_key": "",
"created_at": "2023-01-13T07:06:51.000733",
"updated_at": "2023-01-13T07:06:51.000743"
}
]
Add a new Pack.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createPack" - Required fields:
name: Name of the pack.
Example:
pack.json
{
"name": "Example",
"description": "description of the example",
"discovery_queries": ["SELECT 1 FROM users WHERE username like 'www%';"],
"shard": 50
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/packs/" \
-d @pack.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Example",
"slug": "example",
"description": "description of the example",
"discovery_queries": [
"SELECT 1 FROM users WHERE username like 'www%';"
],
"shard": 50,
"event_routing_key": "",
"created_at": "2023-02-02T07:30:42.133421",
"updated_at": "2023-02-02T07:30:42.133434"
}
/api/osquery/packs/<int:pk>/
Get a Pack.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewPack" <int:pk>: The primary key of the pack.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/packs/2/" \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Example",
"slug": "example",
"description": "description of the example",
"discovery_queries": [
"SELECT 1 FROM users WHERE username like 'www%';"
],
"shard": 50,
"event_routing_key": "",
"created_at": "2023-02-02T07:30:42.133421",
"updated_at": "2023-02-02T07:30:42.133434"
}
Update a Pack.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updatePack" <int:pk>: The primary key of the pack.- Required fields:
name: Name of the pack.
Example
pack_update.json
{
"name": "Example Updated",
"description": "description of the example updated",
"discovery_queries": ["SELECT 1 FROM users WHERE username like 'www%';"],
"shard": 30
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H "Content-Type: application/json" \
"https://$ZTL_FQDN/api/osquery/packs/2/" \
-d @pack_update.json \
|python3 -m json.tool
Response:
{
"id": 2,
"name": "Example Updated",
"slug": "example-updated",
"description": "description of the example updated",
"discovery_queries": [
"SELECT 1 FROM users WHERE username like 'www%';"
],
"shard": 30,
"event_routing_key": "",
"created_at": "2023-02-02T07:30:42.133421",
"updated_at": "2023-02-02T07:32:55.258776"
}
Delete a Pack.
- method: DELETE
- PBAC action:
Osquery::Action::"deletePack" <int:pk>: The primary key of the pack.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/packs/2/"
Response (204 No Content)
/api/osquery/packs/<slug:slug>/
Create or update a standard Osquery pack.
- method:
PUT,DELETE
This endpoint is designed to create or update a standard Osquery pack.
Examples
pack.json
{
"name": "First pack",
"platform": "darwin",
"queries": {
"Leverage-A_1": {
"query" : "select * from launchd where path like '%UserEvent.System.plist';",
"interval" : "3600",
"version": "1.4.5",
"description" : "(http://www.intego.com/mac-security-blog/new-mac-trojan-discovered-related-to-syria/)",
"value" : "Artifact used by this malware"
},
"Leverage-A_2": {
"query" : "select * from file where path = '/Users/Shared/UserEvent.app';",
"interval" : "3600",
"version": "1.4.5",
"description" : "(http://www.intego.com/mac-security-blog/new-mac-trojan-discovered-related-to-syria/)",
"value" : "Artifact used by this malware"
}
}
}
PUT the pack.json file to Zentral:
$ curl -XPUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @pack.json \
"https://$ZTL_FQDN/api/osquery/packs/first-pack-slug/" \
|python3 -m json.tool
You should get a response close to this one:
{
"pack": {
"pk": 1,
"slug": "first-pack-slug"
},
"result": "created",
"query_results": {
"created": 2,
"deleted": 0,
"present": 0,
"updated": 0
}
}
If you PUT the same file again, you will get this answer:
{
"pack": {
"pk": 1,
"slug": "first-pack-slug"
},
"result": "present",
"query_results": {
"created": 0,
"deleted": 0,
"present": 2,
"updated": 0
}
}
If you make a DELETE request on the same URL, the pack and all its rules will be deleted:
$ curl -XDELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/json' \
"https://$ZTL_FQDN/api/osquery/packs/first-pack-slug/" \
|python3 -m json.tool
You should get a response close to this one:
{
"pack": {
"pk": 1,
"slug": "first-pack-slug"
},
"result": "deleted",
"query_results": {
"created": 0,
"deleted": 2,
"present": 0,
"updated": 0
}
}
If the pack is in the osquery format (broken JSON), with line-wrapping characters, or comments, use the application/x-osquery-conf content type.
pack.conf (Real examples are available in the osquery repository.)
{
// Do not use this query in production!!!
"platform": "darwin",
"queries": {
"WireLurker": {
"query" : "select * from launchd where \
name = 'com.apple.periodic-dd-mm-yy.plist';",
"interval" : "3600",
"version": "1.4.5",
"description" : "(https://github.com/PaloAltoNetworks-BD/WireLurkerDetector)",
"value" : "Artifact used by this malware - 🔥"
# 🧨
}
}
}
$ curl -XPUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/x-osquery-conf' \
--data-binary @pack.conf \
"https://$ZTL_FQDN/api/osquery/packs/second-pack-slug/" \
|python3 -m json.tool
You should get a response close to this one:
{
"pack": {
"pk": 2,
"slug": "second-pack-slug"
},
"result": "created",
"query_results": {
"created": 1,
"deleted": 0,
"present": 0,
"updated": 0
}
}
You can also use a YAML payload, with the application/yaml content type.
pack.yml
---
# Do not use this query in production!!!
platform: "darwin"
queries:
WireLurker:
query: >-
select * from launchd where
name = 'com.apple.periodic-dd-mm-yy.plist';
interval: 3600
version: 1.4.5
description: (https://github.com/PaloAltoNetworks-BD/WireLurkerDetector)
value: Artifact used by this malware - 🔥
$ curl -XPUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/yaml' \
--data-binary @pack.yml \
"https://$ZTL_FQDN/api/osquery/packs/second-pack-slug/" \
|python3 -m json.tool
You should get a response close to this one:
{
"pack": {
"pk": 2,
"slug": "third-pack-slug"
},
"result": "present",
"query_results": {
"created": 0,
"deleted": 0,
"present": 0,
"updated": 1
}
}
/api/osquery/queries/
List all queries.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewQuery" - Optional filter parameter:
name: name of the query.
Examples
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/queries/" \
|python3 -m json.tool
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/queries/?name=GetApps" \
|python3 -m json.tool
Response:
[
{
"id": 1,
"compliance_check_enabled": false,
"compliance_check_id": null,
"name": "GetApps",
"sql": "SELECT * FROM apps;",
"platforms": [],
"scheduling": null,
"minimum_osquery_version": null,
"description": "Get list of Apps",
"value": "",
"version": 2,
"created_at": "2023-01-13T07:10:12.571288",
"updated_at": "2023-01-13T09:24:39.779067"
}
]
Add a new query.
- method: POST
- Content-Type: application/json
- PBAC action:
Osquery::Action::"createQuery"
NOTE:
compliance_check_enabled: trueonly possible if sql query containsztl_status.
Example
query.json
{
"compliance_check_enabled": false,
"name": "GetApps",
"sql": "SELECT * FROM apps;",
"scheduling": {
"pack": 17,
"interval": 120
}
}
$ curl -X POST \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @query.json \
"https://$ZTL_FQDN/api/osquery/queries/" \
|python3 -m json.tool
Response:
{
"id": 1,
"compliance_check_enabled": false,
"compliance_check_id": null,
"name": "GetApps",
"sql": "SELECT * FROM apps;",
"platforms": [],
"scheduling": {
"can_be_denylisted": true,
"interval": 120,
"log_removed_actions": true,
"pack": 17,
"shard": null,
"snapshot_mode": false
},
"minimum_osquery_version": null,
"description": "Get list of Apps",
"value": "",
"version": 1,
"created_at": "2023-01-13T07:10:12.571288",
"updated_at": "2023-01-13T09:24:39.779067"
}
/api/osquery/queries/<int:pk>/
Get a query.
- method: GET
- Content-Type: application/json
- PBAC action:
Osquery::Action::"viewQuery" <int:pk>: the primary key of the query.
Example
$ curl -H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/queries/1/" \
|python3 -m json.tool
Response:
{
"id": 1,
"compliance_check_enabled": false,
"compliance_check_id": null,
"name": "GetApps",
"sql": "SELECT * FROM apps;",
"platforms": [],
"scheduling": null,
"minimum_osquery_version": null,
"description": "Get list of Apps",
"value": "",
"version": 1,
"created_at": "2023-01-13T07:10:12.571288",
"updated_at": "2023-01-13T09:24:39.779067"
}
Update a query.
- method: PUT
- Content-Type: application/json
- PBAC action:
Osquery::Action::"updateQuery" <int:pk>: the primary key of the query.
Example
query_update.json
{
"name": "GetUsers",
"sql": "SELECT * FROM users;"
}
$ curl -X PUT \
-H "Authorization: Token $ZTL_API_TOKEN" \
-H 'Content-Type: application/json' \
-d @query_update.json \
"https://$ZTL_FQDN/api/osquery/queries/1/" \
|python3 -m json.tool
Response:
{
"id": 1,
"compliance_check_enabled": false,
"compliance_check_id": null,
"name": "GetUsers",
"sql": "SELECT * FROM users;",
"platforms": [],
"scheduling": null,
"minimum_osquery_version": null,
"description": "Get list of Apps",
"value": "",
"version": 2,
"created_at": "2023-01-14T07:10:12.571288",
"updated_at": "2023-01-14T09:24:39.779067"
}
Delete a query.
- method: DELETE
- PBAC action:
Osquery::Action::"deleteQuery" <int:pk>: the primary key of the query.
Example
$ curl -X DELETE \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/queries/1/"
Response (204 No Content)
/api/osquery/runs/<int:pk>/results/export/
Trigger a Osquery run export task.
- method: POST
- PBAC actions:
Osquery::Action::"viewDistributedQueryResult"
- optional parameter:
export_format: One ofcsv,ndjsonorjson. Defaults tocsv.
Use this endpoint to trigger a Osquery run export task. The result of this task will be a file containing all the data collected during the run.
Example
curl -XPOST \
-H "Authorization: Token $ZTL_API_TOKEN" \
"https://$ZTL_FQDN/api/osquery/runs/1/results/export/" \
|python3 -m json.tool
Response
{
"task_id": "b1512b8d-1e17-4181-a1c3-93a7243fddd3",
"task_result_url": "/api/task_result/b1512b8d-1e17-4181-a1c3-93a7243fddd3/"
}