Writing an annotation in ZTag is easy, and consists of writing a short Python class. You define what protocols the annotation should operate on and implement a single process
function, and ZTag handles the rest.
ZTag has two main functions: transforms and annotations. Annotations run on the output of a transformation, and annotate the transformed data with any combination of device information, software and hardware details, and any other relevant information.
For example, one annotation might annotate any hosts that support export RSA ciphers in TLS with the tag freakattack-vulnerable
, whereas another annotation might only annotate ASUS home routers with their make and model.
There are three types of annotated data that can be generated by an annotation: local metadata, global metadata, and tags.
Local Metadata | Key-value pairs added to host data at the given (port, protocol, subprotocol) tuple. Follows a predefined schema. |
local_metadata.manufacturer = Manufacturer.MICROSOFT
|
---|---|---|
Global Metadata | Key-value pairs to host data at the top level. This will be merged across all (port, protocol, subprotocol) tuples. Follows a predefined schema. |
global_metadata.device_type = Type.SOHO_ROUTER
|
Tags | Set of strings added to host data at the top level. Does not follow a specific schema, but try not to needlessly create new values. | tags.add("heartbleed-vulnerable") |
In the root of the repository, run ./new_tag
. This will copy
example/annotation.tmpl
to ztag/annotations/$TAG_NAME.py
and populate it
with values based on your answers to a few questions.
To finish your tag, implement the method def process(self, obj, meta)
function. The argument obj
is a Python dictionary that matches the JSON from
Censys for the specified (port, protocol, subprotocol)
tuple. The meta
argument is a Python object containing the annotated data, and matches the
schema described below. Populate meta
based on the values in obj
.
Your implementation of process
should modify and return meta
, but should not
modify obj
. Only set the properties on meta
that your annotation can
determine. Optionally, your function can also return None
to signify it cannot
annotate obj
. This is functionally identical to returning meta
unmodified.
metadata
.local_metadata
.manufacturer
.product
.version
.revision
.global_metadata
.manufacturer
.product
.version
.revision
.device_type
.os
.os_version
.os_revision
.tags
metadata.local_metadata.manufacturer | String Constant | Manufacturer.MICROSOFT |
---|---|---|
metadata.local_metadata.product | String | "IIS" |
metadata.local_metadata.version | String | "2012" |
metadata.local_metadata.revision | String | "R2" |
metadata.global_metadata.manufacturer | String Constant | Manufacturer.LINKSYS |
metadata.global_metadata.product | String | "WRT54G-L" |
metadata.global_metadata.version | String | "3.1.0" |
metadata.global_metadata.revision | String | "r2236" |
metadata.global_metadata.device_type | String Constant | Type.SOHO_ROUTER |
metadata.global_metadata.os | String Constant | OperatingSystem.WINDOWS |
metadata.global_metadata.os_version | String | "XP" |
metadata.global_metadata.os_revision | String | "SP2" |
metadata.tags | Set of Strings | "heartbleed-vulnerable" |