Recipes
SALO recipes are a configuration file that define a log generation scenario. With recipes, it is possible to tell SALO what log events to generate, what their values should be, the order logged events should be in, and many other customizations. They enable SALO to generate highly flexible and repeatable synthetic log objects in a simple way. There are multiple configuration options available – let’s explore them here.
Configuration Options
Root Options
Root options may only be defined at the root of the recipe. Meaning, they may not be used within an event. If they are defined elsewhere, they will simply be ignored.
sessions
sessions is a list of event configuration options. Each item, or session, in the list of sessions will be treated independently of other sessions.
Each event
in a session will pass along their own attributes to spawns
as defined:
sessions:
# First session
- event: salo.event.zeek.ConnModel
spawns:
# Attributes from the parent event, ConnModel, will be passed to each spawned event
- event: salo.event.zeek.DNSModel
# Second session
- event: salo.event.zeek.ConnModel
spawns:
- event: salo.event.zeek.HTTPModel
Global Options
Global options may be used at the root of the recipe, or on a per-event basis. If defined at the root of the recipe, they will be the default values for all event configurations in each session within the recipe.
Note
All global options can be defined on a per event
basis.
options
options
can be used to define the values of a SaloEventModel
or SaloStencilModel
attribute. For example, if the src_ip
for all events in
a recipe should be 1.2.3.4
, we can define it like so:
options:
src_ip: 1.2.3.4
Note
options
will be inherited from any and all parent event
objects in the same session. Additionally, options
defined within an event
will override any parent options
defined.
time
The time
configuration option is used to define multiple attributes of the timestamp for an event
. Several options are available, to include the
start time, jitter, and the cadence of event
timestamps. All options below may be used in concert with each other.
start
start
is the datetime
value an event
must start at:
time:
start: 2021-12-25T01:00:00.000000
jitter_min
jitter_min
is the minimum amount of jitter in seconds to introduce into the timestamp:
time:
jitter_min: 600
jitter_max
jitter_max
is the maximum amount of jitter in seconds to introduce into the timestamp:
time:
jitter_max: 3600
cadence
cadence
is a crontab-style configuration option to define the delta between an event
. The format for cadence is identical to a crontab configuration,
except that second repetition is supported.:
second minute hour day month year
For example, to define a cadence of one event per second:
time:
cadence: "*/1 * * * * *"
Or, only at 3am on the first of the month:
time:
cadence: "* * 03 01 * *"
Event Options
An event
is a subsection of the sessions
option. Each top-level event in sessions
is considered it’s own session.
event
An event
may be a SaloEventModel
or SaloStencilModel
object path. The value must be a python importable library:
sessions:
- event: salo.events.suricata.DNSModel
Note
For custom events, the SALO_PATH
environment variable may be set to include this in the import search path. (i.e., export SALO_PATH "/path/to/my/events"
)
If it is a SaloStencilModel
, it will only be used for defining the attributes for spawns
. It will not generate any output itself. Stencils are designed to
generate complex programmatic log scenarios which would be otherwise impossible to do with just a recipe:
sessions:
- event: salo.stencils.sunburst.SunBurstDNSQuery
spawns:
- event: salo.events.zeek.DNSModel
- event: salo.events.suricata.DNSModel
If it is a SaloEventModel
, it will produce output in the form of a log object:
sessions:
- event: salo.events.zeek.ConnModel
spawns
spawns
are children of an event
and are recursively chained together. All spawns
of an event
will inherit the parents attribute values.
If the attributes are a member of the spawned event
, they will be defined. Otherwise, they will be simply ignored and passed along to any additional
child spawns
:
sessions:
- event: salo.events.zeek.ConnModel
spawns:
- event: salo.events.zeek.DNSModel
- event: salo.events.zeek.ConnModel
spawns:
- event: salo.events.zeek.SMTPModel
repeat
Repeat the event
, and all spawns
, the number of times that are defined:
sessions:
- event: salo.events.suricata.DNSModel
repeat: 100
save_values
Save the values from the event
as a variable for use in a later event
or session
:
sessions:
- event: salo.events.suricata.DNSModel
save_values:
first_dns_query: dns_query
options:
dns_query: totallybadsite.com
- event: salo.event.suricata.HTTPModel
options:
http_hostname: $first_dns_query
This example will save the value of dns_query
from the first event
into the variable $first_dns_query
. It is then accessed and used to define
the value of http_hostname
in the second event
, resulting in the http_hostname
value being totallybadsite.com
.
Additionally, if the value is a list, the resulting value can be of a specific index or random. Let’s take a look at using a specific index value first:
sessions:
- event: salo.events.suricata.DNSModel
save_values:
first_dns_query: dns_query
first_dns_rdata: dns_rdata
options:
dns_query: totallybadsite.com
dns_rdata:
- 1.2.3.4
- 5.6.7.8
- event: salo.event.suricata.HTTPModel
options:
http_hostname: $first_dns_query
dest_ip: $first_dns_rdata.0
This will work exactly the same as the previous example above, but will also define the dest_ip
as the value at index 0
, or 1.2.3.4
.
If the value of dest_ip
could be any of the values defined in dns_rdata
, then we could leverage the random
option:
sessions:
- event: salo.events.suricata.DNSModel
save_values:
first_dns_query: dns_query
first_dns_rdata: dns_rdata
options:
dns_query: totallybadsite.com
dns_rdata:
- 1.2.3.4
- 5.6.7.8
- event: salo.event.suricata.HTTPModel
options:
http_hostname: $first_dns_query
dest_ip: $first_dns_rdata.random
This allows for an easy and flexible way to define attribute values of an event
within a different session.
likelihood
likelihood
will introduce a defined degree of randomness as to whether an event
will be created:
sessions:
- event: salo.events.zeek.ConnModel
spawns:
- event: salo.events.zeek.DNSModel
- event: salo.events.zeek.ConnModel
likelihood: 50
spawns:
- event: salo.events.zeek.SMTPModel
In the above example, the first event
and it’s spawns
will always produce a log object. However, the second event will only produce a log object
approximately 50% of the time.