N2OS UserManual
N2OS UserManual
Legal notices
Publication Date
February 2021
Copyright
Copyright © 2013-2020, Nozomi Networks. All rights reserved.
Nozomi Networks believes the information it furnishes to be
accurate and reliable. However, Nozomi Networks assumes no
responsibility for the use of this information, nor any infringement of
patents or other rights of third parties which may result from its use.
No license is granted by implication or otherwise under any patent,
copyright, or other intellectual property right of Nozomi Networks
except as specifically described by applicable user licenses. Nozomi
Networks reserves the right to change specifications at any time
without notice.
| Table of Contents | v
Table of Contents
Chapter 2: OpenAPI.............................................................................. 29
Setup............................................................................................................................................30
Errors........................................................................................................................................... 31
Query endpoint............................................................................................................................ 32
CLI endpoint................................................................................................................................ 33
Import CSV endpoint...................................................................................................................34
Import JSON endpoint.................................................................................................................35
Alerts endpoint.............................................................................................................................36
Traces endpoint...........................................................................................................................41
Users endpoint............................................................................................................................ 43
PCAPs endpoint.......................................................................................................................... 47
1
Scriptable protocols
Topics: In this manual we will cover the Lua scripting API for building a
custom protocol decoder.
• Setup
• Writing a scriptable protocol
• API reference
| Scriptable protocols | 8
Setup
To add a new scriptable protocol:
1. Copy the Lua script in /data/scriptable_protocols/
2. Configure Guardian with this rule probe scriptable-protocol <protocol_name>
<script_name> in n2os.conf.user (<script_name> is the name of the file including the extension)
3. Execute service n2osids stop, the ids process will be restarted automatically.
After this steps the new protocol is loaded in Guardian and will analyze the network traffic.
| Scriptable protocols | 9
function can_handle()
return true
end
From the example we can see that the only mandatory thing to do is to define a function called
can_handle which returns true if it recognize the target protocol.
Of course this implementation is not very useful and it will try to handle every packet so let's write
something more complex to detect and analyze some modbus traffic:
function can_handle()
return packet.source_port() == 502 or packet.destination_port() == 502
end
Here we can see a usage of the API to retrieve the packet ports. In this way the check is a bit more
accurate but it's still insufficient to detect a modbus packet in the real world.
Let's start to do some deep packet inspection:
function can_handle()
if data_size() < 8 then
return false
end
fwd(2)
local has_right_protocol_id = consume_n_uint16() == 0
local expected_length = consume_n_uint16()
WARNING: don't use global variables. Variables defined outside of the can_handle and
update_status functions are global and their status is shared across every session of the same
protocol.
NOTE: the fwd and consume_* functions will move forward the payload pointer.
NOTE: the result of the remaining_size function depends on the position of the payload pointer.
In this example we use the API to inspect the content of the payload. First we check that there are
enough bytes, a modbus packet is at least 8 bytes long. Then we check the port in the same we did
in the previous example, then we skip two bytes with the function fwd and we read the next two 16 bit
integers. We check that the protocol id is zero and that the length written in the packet match with the
remaining bytes in our payload. If every check pass we return true saying to Guardian that the next
packets in this session should be analyzed by this protocol decoder.
| Scriptable protocols | 10
A protocol with just the can_handle function implemented will only create the node and the session in
the network view but the link is still missing from the graph, no additional information will be displayed
in the process view.
To extract more information from the modbus packets we are going to implement the update_status
function:
function get_protocol_type()
return ProtocolType.SCADA
end
function can_handle()
return is_modbus()
end
function update_status()
if not is_modbus() then
return
end
if is_request then
is_packet_from_src_to_dst(true)
set_roles("consumer", "producer")
if fc == 6 then
local address = consume_n_uint16()
execute_update_with_variable(FunctionCode.new(fc), RtuId.new(rtu_id),
"r"..tostring(address), value)
return
end
end
execute_update()
end
NOTE: to avoid duplication we created a is_modbus function from the content of the previous
can_handle function.
NOTE: the is_modbus function has the effect to advance the payload pointer by 6 bytes, so when can
directly read the rtu_id without further payload pointer manipulations.
NOTE: we defined the get_protocol_type function to define the protocol type
In this example of update_status we read more data from the payload and we decode the
write single register request. We can understand the direction of the communication so we call
is_packet_from_src_to_dst with true to notify Guardian and create a link and we call
set_roles to set the roles on the involved nodes.
To insert a variable in Guardian there is the execute_update_with_variable function, it takes 4
arguments: the function code, the rtu id, the variable name and the value. The FunctionCode and
RtuId objects can be constructed from a string or a number, the DataValue object can be constructed
with the empty constructor and then filled with the available information.
| Scriptable protocols | 11
With the next example we cover a more complex case and we store some data in the session to handle
a request and a response:
local PENDING_FC = 1
local PENDING_START_ADDR = 2
local PENDING_REG_COUNT = 3
function update_status()
if not is_modbus() then
return
end
rwd()
if is_request then
is_packet_from_src_to_dst(true)
set_roles("consumer", "producer")
session.set_pending_request_number(transaction_id, PENDING_FC, fc)
if fc == 3 then
if remaining_size() < 4 then
return
end
session.set_pending_request_number(transaction_id, PENDING_START_ADDR,
start_addr)
session.set_pending_request_number(transaction_id, PENDING_REG_COUNT,
registers_count)
end
else
is_packet_from_src_to_dst(false)
local req_fc = session.read_pending_request_number(transaction_id,
PENDING_FC)
if fc == req_fc then
if fc == 3 then
local start_addr = session.read_pending_request_number(transaction_id,
PENDING_START_ADDR)
local reg_count = session.read_pending_request_number(transaction_id,
PENDING_REG_COUNT)
session.close_pending_request(transaction_id)
if remaining_size() ~= byte_count or
reg_count * 2 ~= remaining_size() then
send_alert_malformed_packet("Packet is too small")
return
end
for i = 0, reg_count - 1, 1 do
local value = DataValue.new()
value.value = consume_n_uint16()
| Scriptable protocols | 12
value.cause = DataCause.READ_SCAN
value.type = DataType.ANALOG
value.time = packet.time()
execute_update_with_variable(FunctionCode.new(fc),
RtuId.new(rtu_id),
"r"..tostring(start_addr+i),
value)
end
return
end
end
end
execute_update()
end
This time we are focusing on the read holding register function code, to understand the communication
and create a variable we need to analyze both the request and the response and we need to keep
some data from the request and use it in the response. To achieve this we can use the functions
provided by the session object.
| Scriptable protocols | 13
API reference
Data types
Class FunctionCode
Constructors • FunctionCode.new(<string>)
• FunctionCode.new(<number>)
Class RtuId
Constructors • RtuId.new(<string>)
• RtuId.new(<number>)
Class DataValue
Constructors • DataValue.new()
Class Variable
Methods • set_label(<string>)
Class Node
Methods • set_property(<key>, <value>)
• get_property(<key>)
• delete_property(<key>)
Enum DataCause
Values • DataCause.READ_SCAN
• DataCause.READ_CYCLIC
• DataCause.READ_EVENT
• DataCause.WRITE
Enum DataType
| Scriptable protocols | 14
Values • DataType.ANALOG
• DataType.DIGITAL
• DataType.BITSTRING
• DataType.STRING
• DataType.DOUBLEPOINT
• DataType.TIMESTAMP
Enum ProtocolType
Values • ProtocolType.SCADA
• ProtocolType.NETWORK
Functions
Syntax data(<index>)
Parameters • index: the position of the byte to read, starting from 0
Description Return the value of the byte from the specified position, return 0 if index is
out of bounds
Syntax data_size()
Description Return the total size of the payload
Syntax remaining_size()
Description Return the size of the payload from the pointer to the end. The result
depends on the usage of functions fwd(), rwd() and consume_*().
Syntax fwd(<amount>)
Parameters • amount: the number of bytes to skip
Syntax rwd()
Description Move the payload pointer to the beginning of the payload.
Syntax read_uint8()
Description Read an unsigned 8bit integer at the payload pointer position.
Syntax read_int8()
Description Read an signed 8bit integer at the payload pointer position.
Syntax read_n_uint16()
Description Read a network order unsigned 16bit integer at the payload pointer position.
Syntax read_h_uint16()
Description Read a host order unsigned 16bit integer at the payload pointer position.
Syntax read_n_int16()
| Scriptable protocols | 15
Description Read a network order signed 16bit integer at the payload pointer position.
Syntax read_h_int16()
Description Read a host order signed 16bit integer at the payload pointer position.
Syntax read_n_uint32()
Description Read a network order unsigned 32bit integer at the payload pointer position.
Syntax read_h_uint32()
Description Read a host order unsigned 32bit integer at the payload pointer position.
Syntax read_n_int32()
Description Read a network order signed 32bit integer at the payload pointer position.
Syntax read_h_int32()
Description Read a host order signed 32bit integer at the payload pointer position.
Syntax read_n_uint64()
Description Read a network order unsigned 64bit integer at the payload pointer position.
Syntax read_h_uint64()
Description Read a host order unsigned 64bit integer at the payload pointer position.
Syntax read_n_int64()
Description Read a network order signed 64bit integer at the payload pointer position.
Syntax read_h_int64()
Description Read a host order signed 64bit integer at the payload pointer position.
Syntax read_n_float()
Description Read a network order float at the payload pointer position.
Syntax read_h_float()
Description Read a host order float at the payload pointer position.
Syntax read_n_double()
Description Read a network order double at the payload pointer position.
Syntax read_h_double()
Description Read a host order double at the payload pointer position.
Syntax read_string()
Description Read a string at the payload pointer position until the null terminator.
Syntax read_string_with_len(str_len)
| Scriptable protocols | 16
Description Read a string at the payload pointer position for str_len bytes.
Syntax consume_uint8()
Description Read an unsigned 8bit integer at the payload pointer position and move the
pointer after the data.
Syntax consume_int8()
Description Read an signed 8bit integer at the payload pointer position and move the
pointer after the data.
Syntax consume_n_uint16()
Description Read a network order unsigned 16bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint16()
Description Read a host order unsigned 16bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_int16()
Description Read a network order signed 16bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int16()
Description Read a host order signed 16bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_uint32()
Description Read a network order unsigned 32bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint32()
Description Read a host order unsigned 32bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_int32()
Description Read a network order signed 32bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int32()
Description Read a host order signed 32bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_uint64()
Description Read a network order unsigned 64bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_uint64()
| Scriptable protocols | 17
Description Read a host order unsigned 64bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_int64()
Description Read a network order signed 64bit integer at the payload pointer position
and move the pointer after the data.
Syntax consume_h_int64()
Description Read a host order signed 64bit integer at the payload pointer position and
move the pointer after the data.
Syntax consume_n_float()
Description Read a network order float at the payload pointer position and move the
pointer after the data.
Syntax consume_h_float()
Description Read a host order float at the payload pointer position and move the pointer
after the data.
Syntax consume_n_double()
Description Read a network order double at the payload pointer position and move the
pointer after the data.
Syntax consume_h_double()
Description Read a host order double at the payload pointer position and move the
pointer after the data.
Syntax consume_string()
Description Read a string at the payload pointer position until the null terminator and
move the pointer after the data.
Syntax consume_string_with_len(str_len)
Description Read a string at the payload pointer position for str_len bytes and move
the pointer after the data.
Description Set the roles of the involved nodes, valid values are: "consumer",
"producer", "historian", "terminal", "web_server", "dns_server", "db_server",
"time_server", "other"
Syntax set_source_type(<node_type>)
Parameters • node_type: the type of the source node
Description Set the type of the source node, valid values are: "switch", "router", "printer",
"group", "OT_device", "broadcast", "computer"
| Scriptable protocols | 18
Syntax variables_are_on_client()
Parameters
Description Notify to Guardian that the variables should be added to the client node
syntax is_packet_from_src_to_dst(<is_from_src>)
parameters • is_from_src: true is the direction is from src to dst, false otherwise
description notify Guardian about the direction of the packet, this function must be
called to obtain a link creation
syntax execute_update()
parameters
description notify Guardian about the a packet, at least one variant of execute_update
should be called for every packet
description notify Guardian about the a packet with a function code and a rtu id
description notify Guardian about the a packet with a function code, a rtu id, a variable
name and a variable value
description notify Guardian about the a packet with a function code, a rtu id, a variable
name, a variable value and a function that give the possibility to directly
access the variable
syntax AlertFactory.new().new_net_device()
description raise an alert of type VI:NEW-NET-DEV
syntax AlertFactory.new().firmware_change()
| Scriptable protocols | 19
syntax AlertFactory.new().protocol_error(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().wrong_time(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().sync_asked_again(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().protocol_flow_anomaly(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().variable_flow_anomaly(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().dhcp_request(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().invalid_ip(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_arp(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().duplicated_ip(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().link_reconnection(<reason>)
| Scriptable protocols | 20
syntax AlertFactory.new().rst_from_producer(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_syn(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_syn_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().tcp_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().protocol_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().mac_flood(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().network_scan(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().cleartext_password(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().ddos_attack(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().unsupported_func(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().illegal_parameters(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().weak_password(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malware_detected(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().unknown_rtu(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().missing_variable(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().scada_injection(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_variable(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().new_variable_value(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().device_state_change(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().configuration_change(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malicious_protocol(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().weak_encryption(<reason>)
parameters • reason: a message to be displayed in the alert
syntax AlertFactory.new().malformed_ot_packet(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().malformed_network_packet(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().suspicious_time(<triggerId>,
<reason>)
parameters • triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().new_node(<nodeId>)
parameters • nodeId: identifier of the node
syntax AlertFactory.new().new_target_node(<nodeId>)
parameters • nodeId: identifier of the node
syntax AlertFactory.new().new_node_malicious_ip(<nodeId>,
<threatName>)
| Scriptable protocols | 23
syntax AlertFactory.new().new_mac_vendor(<nodeId>,
<macAddress>)
parameters • nodeId: identifier of the node
• macAddress: MAC Address
syntax AlertFactory.new().malicious_domain(<domain>,
<threatName>, <reason>)
parameters • domain: the malicious domain
• threatName: the name of the threat
• reason: a message to be displayed in the alert
syntax AlertFactory.new().configuration_mismatch(<nodeId>,
<triggerId>, <reason>)
parameters • nodeId: identifier of the node
• triggerId: identifier of the triggering engine entity
• reason: a message to be displayed in the alert
syntax AlertFactory.new().multiple_ot_device_reservations(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
| Scriptable protocols | 24
syntax AlertFactory.new().multiple_unsuccessful_logins(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
parameters • sNodeId: identifier of the source node
• dstNodeId: identifier of the destination node
• protocolId: identifier of the protocol
• bpfFilter: BPF filter
• protocolType: type of the protocol according to the ProtocolType type
• reason: a message to be displayed in the alert
syntax AlertFactory.new().multiple_access_denied(<sNodeId>,
<dNodeId>, <protocolId>, <bpfFilter>, <protocolType>,
<reason>)
parameters • sNodeId: identifier of the source node
• dNodeId: identifier of the destination node
• protocolId: identifier of the protocol
• bpfFilter: BPF filter
• protocolType: type of the protocol according to the ProtocolType type
• reason: a message to be displayed in the alert
syntax send_alert_malformed_packet(<reason>)
parameters • reason: a message to be displayed in the alert
description notify a captured URL to the system. Note that captured URLs need to
be explicitly enabled by specifying the vi captured_urls enabled
configuration setting.
description notify a link event to the system. Note that link events need to be explicitly
enabled by specifying the vi link_events enabled configuration
setting.
syntax packet.source_id()
description return the source node id
syntax packet.destination_id()
description return the destination node id
syntax packet.source_ip()
description return the source node ip
syntax packet.destination_ip()
description return the destination node ip
syntax packet.source_mac()
description return the source node mac
syntax packet.destination_mac()
description return the destination node mac
syntax packet.source_port()
description return the source node port
syntax packet.destination_port()
description return the destination node port
syntax packet.is_ip()
description return true if the packet is an ip packet
| Scriptable protocols | 26
syntax packet.transport_type()
description return the transport layer type, can be "tcp", "udp", "ethernet", "icmp" or
"unknown"
syntax packet.source_node()
description returns the source node
syntax packet.destination_node()
description returns the destination node
syntax packet.time()
description return the packet time
syntax session.has_pending_request(<request_id>)
parameters • request_id: a number used to uniquely identify the request
description return true if there are values stored with the request_id
description return true if there are values stored with the request_id and key
syntax session.close_pending_request(<request_id>)
parameters • request_id: a number used to uniquely identify the request
description close the pending request and delete the associated data
syntax log_d(<msg>)
parameters • msg: the message to log
syntax log_e(<msg>)
parameters • msg: the message to log
2
OpenAPI
Topics: In this chapter we will cover our OpenAPI implementation, which
consists of an HTTP endpoint for executing custom queries.
• Setup
• Errors
• Query endpoint
• CLI endpoint
• Import CSV endpoint
• Import JSON endpoint
• Alerts endpoint
• Traces endpoint
• Users endpoint
• PCAPs endpoint
| OpenAPI | 30
Setup
To perform a call to the endpoint you need to pass authentication credentials as headers, the examples
provided use Postman, an HTTP client.
Remember to use your Nozomi Networks Solution's web interface IP instead of the example one.
Nozomi Networks suggests to create dedicated users for OpenAPI usage, with minimal permissions
necessary to access the required data sources.
Errors
If you fail to provide valid authentication credentials the expected error will be 401 Unauthorized, as
shown below.
If you ask for a data source that does not exist you will receive a proper message in the error field.
Query endpoint
You can manipulate data sources through the use of queries, which are commands piped one after
another. Please refer to the Queries chapter of the User Manual, or head over to /#/query in your
Nozomi Networks Solution web interface to see some examples.
For example, to see how many nodes are in the system, call the following URL:
https://10.0.1.10/api/open/query/do?query=nodes | count
As you can see there's no need to escape the query, let's see a more complex one:
https://10.0.1.10/api/open/query/do?query=nodes | where_link protocol ==
http | head 5. In the image we've used Postman's interface to collapse the results so you could
clearly see it's five as we wanted.
CLI endpoint
You can apply changes to the system by issuing CLI commands over this endpoint.
The endpoint is located at /api/open/cli and requires to be invoked with the cmd parameter with a
POST.
CLI commands allow to change virtually anything inside the system, please refer to the Configuration
section of the User Manual for a more complete reference.
| OpenAPI | 34
label
firmware_version
vendor
product_name
serial_number
os
mac_address
label
firmware_version
vendor
product_name
serial_number
os
mac_address
Alerts endpoint
A POST to /api/open/alerts/close request allows you to close a group of alerts passed as a
json list of ids in the body of the request. You must also pass as parameter the close_action field
containing delete_rules or learn_rules in case you want to close alerts as security or as change.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. The input data must be a JSON dictionary containing a ids key whose value must be an array of
alert 'id' and a 'close_action' constant field.
3. In case the request body does not adhere to the format described above the call returns a 422
error.
4. In case the request is well formed, the result will contain the id of the job in charge of the task. You
can monitor the status of the job via the alerts/close/status/:id API.
{
"ids": ["uuid"],
"close_action": "learn_rules"
}
{
"data": [
{
"id": "uuid",
"ack": true
}
]
}
2. As last parameter of the path you need to specify the id of the job returned by the alerts/ack
API.
3. The result will contain the status of the job, which can have one of the following values: SUCCESS,
PENDING or FAIL
4. In case of FAIL status, the error field will report the error reason.
A GET to /api/open/alerts/all request allows you to get the IDs of alerts matching a condition.
You can specify a filter query in the query parameter and an additional parameter named has_trace
to get the status of the corresponding trace.
Requirements and Restrictions
1. The authenticated user has to belong to a group having admin role or with Alerts section enabled.
2. The query parameter should be in Nozomi Networks Query Language format, where the table
name is implicit, i.e. alerts.
3. The has_trace parameter type is boolean.
4. If no alert matches the specified conditions, a 404 error will be returned.
A GET to /api/open/alerts/:id/trace request allows you to get a file containing the trace of the
alert, whose id is specified as a parameter.
| OpenAPI | 39
Traces endpoint
A GET to /api/open/traces/all request allows you to get the traces matching a condition. You
can specify a filter query in the query parameter. You have to specify the operation parameter
defining the requested operation. So far the only allowed value for operation is download.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As a result you will get a file containing the trace or the traces filtered according to the specified
condition
3. If the trace is still in progress or it is not found, a 422 error with a proper reason string will be
returned.
4. This operation relies on the presence of trace_request records. By default, the persistence of
trace_request records for traces automatically generated by alerts is disabled. Should you need
to enable it, please set the trace persist_alerts_trace_requests configuration setting
to true. For a detailed explanation of the traces configuration please also check the Configuring
Trace section of the User Manual.
A GET to /api/open/traces/bpf_filter request allows you to select traces using a BPF filter.
This call returns a job id, while the actual disk search is performed asynchronously. The search will
return a list of the first PCAP traces that match the filter. The maximum number of PCAP traces is 50
by default and can be configured with the open_api bpf_filter traces_limit setting. There
can’t be more than a limited number of concurrent BPF trace searches at a time. This number is 2
by default and can be configured with the open_api bpf_filter max_concurrent_searches
setting.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
| OpenAPI | 42
Users endpoint
A GET to /api/open/users allows you to get a list of all the users.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. The result contains the list of all users.
3. It's possible to use pagination adding page and count params
4. The page param get the number of the page to return, the count is the dimension of the page.
5. If count is nil or 0 the default value will be 100, if page is nil or 0 the request will not be paginated.
6. This api is disabled by default, to enable it add api users enabled true to the user
configuration file.
A GET to /api/open/users/:id allows you to get the users having the id passed as path
parameter.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As last parameter of the path you need to specify the id of the user.
3. The result will contain the user
4. In case the user with that id is not found you'll get a 404.
| OpenAPI | 44
{
"username": "user_under_test22",
"password": "aValidP4ss!",
"user_group_ids": [2],
"strategy": "local",
"is_suspended": false,
"should_update_pwd": false,
"ssh_keys": "an_ssh_key",
"allow_root_ssh": true
}
| OpenAPI | 45
A PUT to /api/open/users/:id allows you to update the user with the id passed as path param.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role.
2. As last parameter of the path you need to specify the id of the user you want to update.
3. The input must be a JSON dictionary containing the user field properly populated
4. If the update goes well the call return 204 (No content) response
5. You can't update the password here because updating password is not idempotent so you can't do
via PUT.
6. The fields you can update are listed below.
7. user_group_ids must contain at least one valid id.
{
"username": "user_under_test22",
"strategy": "local",
"user_group_ids": [1,2],
"is_suspended": false,
"should_update_pwd": false,
"ssh_keys": "a_new_key",
"allow_root_ssh": true
}
{
"password": "4ValidP4ssw0rd!"
}
PCAPs endpoint
A GET request to /api/open/pcaps request allows you to get the list of all PCAPs available on the
machine. You can pass the ID of a given PCAP to get information only for that PCAP.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload PCAPs section
enabled.
2. In case the request body does not adhere to the format described above, the call returns a 422
error.
3. If you specify an ID of a PCAP that does not exist, the call returns a 404 error.
4. If the request is accepted, the result will contain useful information on the retrieved PCAP.
1. The authenticated user must be in a group having admin role or with Upload PCAPs section
enabled.
2. In case the request body does not adhere to the format described above, the call returns a 422
error.
3. If you specify an ID od a PCAP that does not exist, the call returns a 404 error.
4. If the request is accepted, the PCAP will be deleted.
A POST request to /api/open/pcaps/import request allows you to import a PCAP file that is
already present in the machine.
| OpenAPI | 49
A PATCH request to /api/open/pcaps request allows you to replay a PCAP that has been
previously uploaded or imported.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload PCAPs section
enabled.
2. The PCAP should be present in the list of the available PCAPs returned by the GET request to /
api/open/pcaps.
3. The id parameter of the request should contain the ID of the PCAP.
4. The use_packet_time boolean parameter should be set to true if you want to use the time of
the packets; false otherwise.
5. The data_to_reset_before_play parameter should be set to {} if you do not want to reset
data before playing the PCAP. Otherwise, you need to specify a JSON dictionary with the sections
you want to reset, for example {"alerts": true, "vi": true}. The list of all available
sections is the following:
• alerts
• traces
• network_data
• process_data
• assets_data
• vi
• timemachine
• queries
• smart_polling_points
• assertions
The list above reflects the options available for Data reset in the UI.
6. In case the request body does not adhere to the format described above, the call returns a 422
error.
7. If you specify an ID of a PCAP that does not exist, the call returns a 404 error.
8. If the request is accepted, the PCAP will be replayed.
A PATCH request to /api/open/pcaps/note request allows you to change the note field of a
PCAP.
Requirements and Restrictions
1. The authenticated user must be in a group having admin role or with Upload PCAPs section
enabled.
2. The PCAP should be present in the list of the available PCAPs returned by the GET request to /
api/open/pcaps.
3. The id parameter of the request should contain the ID of the PCAP.
4. The note parameter of the request should contain the text you want to change.
5. In case the request body does not adhere to the format described above, the call returns a 422
error.
6. If the request is accepted, the note will be changed.
3
Data Model
Topics: In this chapter we will cover our Data Model reference for query
entities.
• Data Model reference
| Data Model | 52
alerts
Alerts represent events raised by the Guardian
appliances
This query source contains any kind of appliance on the CMC and Remote Collectors -- if any -- on the
Guardian
assertions
An assertion represent an automatic check against other query sources
assets
Assets represent a local, physical system to care about, and can be composed of one or more Nodes
captured_logs
Logs captured passively over the network
captured_urls
URLs and other protocol calls found in the network. Access to files, requests to DNS, requested URLs
and other are available in this query source.
function_codes
Function Codes used in the environment
health_log
Health-related events about the system - like high resource utilization or hardware-related issues or
events
link_events
Events that can occurr on a Link, like it being available or not
links
Links are protocol relations between two Nodes and with a specific protocol. They model the interaction
between Nodes
node_cpe_changes
On the event of update of a CPE, an entry in this query source is created to keep track of software
updates or better detection of software
node_cpes
List CPEs (Common Platform Enumeration), that is software or component connected to a specific
Node in the system
node_cves
Vulnerabilities matched against current CPEs
node_points
Data points polled via Smart Polling from monitored Nodes
nodes
List of Nodes, where is node is an L2 or L3 or other entity able to speak some protocol
report_files
Generated reports available for consultation
sessions
Live, mostly open Sessions between Nodes. A Session is a specific application-level connection
between nodes. A Link can hold one or more Session at a given time.
sessions_history
Archived Sessions. See the sessions query source for more information
variable_history
History of values for Variables where history has been enabled
| Data Model | 68
variables
Variables extracted via DPI from the monitored system
4
Data Integrations Best Practices
Topics: This chapter details the best practices when using Nozomi Networks
data integration that is obtained via Syslog integration or OpenAPI
• Data Sources for Integration calls.
• Nozomi Syslog Data Types
• OpenAPI Data
• Certify Your Integration with
Nozomi
| Data Integrations Best Practices | 72
cs3 cs3Label Id: The Alert ID (not Alert Type ID) of the alert in the
Nozomi system
Ensure that your integration recognizes these custom labels and deals with them appropriately.
Syslog Messages
Alert Events
There are many alert types in the Nozomi environment. The N2OS User Manual contains a full
reference of Alert Types.
Alert Events in CEF have the following format, e.g.:
| Data Integrations Best Practices | 73
Note the highlighted part of the Alert message. This is the Alert Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
Health Events
Health Events in CEF have the following format, e.g.:
Note the highlighted part of the Health message. This is the Health Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
Audit Events
Audit Events in CEF have the following format, e.g.:
| Data Integrations Best Practices | 74
Note the highlighted part of the Audit message. This is the Audit Type ID. This should be used as
the key for performing searches once Nozomi syslog events have been ingested into the integration
platform.
Best Practice: Ensure that your parsing logic extracts the appropriate data. If you are integrating with
CEF messages, a CEF parser must be used. Do not use regular expressions. This will ensure the
integration integrity in the future. When using the correct parser for the data that is expected, be sure to
test different inputs to ensure that data is correctly extracted from the messages.
OpenAPI Data
API Users
Nozomi recommends the practice of creating a user specifically for the purposes of api access. This
provides a demarcation of responsibilities that is straight forward for auditing and traceability.
Best Practice: Create a user specifically for accessing the OpenAPI.
Authentication
Each call to one of the OpenAPI methods requires authentication. Currently, the OpenAPI supports
Basic Authentication. So, for example using CURL, if you have a Username and Password for your api
user, then you will pass the following header along with your query:
-H "Authorization: Basic <AUTH_TOKEN>"
Where <AUTH_TOKEN> is the base64 encoding of Username:Password.
Note that the language and method of implementation (e.g. CURL vs Java) will dictate how the
specifics of the Basic Authentication are performed.
Note: In case of querying the OpenAPI for data, the -k –user Username:Password option may be
used instead for Basic Authentication.
{
"header": [
All of the headers…
],
"result": [
{ First Node data },
{ Second Node data }
],
"total": 2
}
{
"nodes": [
{
"ip": "1.2.3.8",
"label": "JSON_Uploaded_Asset_1",
"mac_address": "00:00:00:11:11:11",
"firmware_version": "1.2.3",
| Data Integrations Best Practices | 76
"product_name": "ACME_PLC_2",
"serial_number": "1-789A10-2",
"vendor": "ACME"
},
{
"ip": "1.2.3.3",
"label": "JSON_Uploaded_Asset_2",
"mac_address": "00:00:00:11:11:15",
"firmware_version": "1.2.2",
"product_name": "ACME_PLC_1",
"serial_number": "1-789A10-6",
"vendor": "ACME"
}
]
}
Depending on your CURL implementation, the file may have to be submitted using -d as in the example
below.
The following command will upload these assets into the Guardian or CMC:
Import Commands
Downloading PCAPs
Traces associated with an alert can be downloaded via the api as well. We will need the alert ID in
order to accomplish this. The following command will download a trace associated with an alert ID
<YourAlertID> to the file specified by <YourTraceFile>:
curl -k -X GET https://<YourHost>/api/open/alerts/<YourAlertID>/trace -H
"Authorization: Basic <AUTH_TOKEN>" -H "Content-Type: application/js on" --
output <YourTraceFile>
In addition, you will be required to perform a live demonstration of your integration with the Nozomi
platform.
To have your integration certified by Nozomi we will require the following items:
• When performing searches on messages, only search on message type IDs.
• This is especially important with regards to Alert Type ID’s.
• For CEF Syslog integrations, ensure that custom fields are mapped as necessary for your
environment.
• Nozomi has custom string labels defined in our CEF implementation.
• Please provide a configuration guide for integrating your product with the Nozomi Network platform.
• Please provide any relevant sales collateral you have produced (including solution briefs, videos,
etc.) for the integration with Nozomi.
• Schedule a live demo of the integration. This should include a complete walkthrough of the
integration from initial configuration to events flowing from the Nozomi platform into your
environment. Any Nozomi discovered discrepancies must be addressed prior to certification.
• Once Nozomi technical personnel have approved the materials then the integration will be
considered completed. The integration will then be granted Certified Technology Partner status.