Storm Reference - Data Modification

Storm can be used to modify data in Synapse by:

  • adding or deleting nodes;

  • setting, modifying, or deleting properties on nodes;

  • adding or deleting light edges; and

  • adding or deleting tags from nodes (including tag timestamps or tag properties).

The ability to create or modify data on the fly gives users a powerful degree of flexibility and efficiency.

Warning

The ability to add and modify data directly from Storm is powerful and convenient, but users can inadvertently modify (or even delete) data inappropriately through mistyped syntax, incorrect Storm logic, or premature striking of the “enter” key. While some built-in protections exist within Synapse itself, it is important to remember that there is no “are you sure?” prompt before a Storm query executes.

The following best practices will help prevent inadvertent changes to a Cortex:

  • Where possible, Fork a View and test and perform your changes in the fork. Once you have validated the changes, they can be merged into the parent view; if anything goes wrong, the fork can simply be deleted.

    • Note that in Synapse 2.x, all delete operations must be performed in the layer where the data to be deleted exists; that is, if you are working in forked view, you cannot delete data in the underlying view/layer from the fork.

  • Use extreme caution when constructing complex Storm queries that may modify (or delete) large numbers of nodes. It is strongly recommended that you validate the output of a query by first running the query on its own (without the edit or delete operations) to ensure it returns the expected results (set of nodes) before permanently modifying or deleting those nodes.

  • Use the Synapse permissions system to enforce least privilege. Limit users to permissions appropriate for tasks they have been trained for / are responsible for.

Tip

For adding data at scale, we recommend use of the Synapse csvtool, the Synapse feed utility, the Optic Ingest Tool, or the programmatic ingest of data (e.g., using a Power-Up).)

See Storm Reference - Document Syntax Conventions for an explanation of the syntax format used below.

See Storm Reference - Type-Specific Storm Behavior for details on special syntax or handling for specific data types (Type).

Edit Mode

To perform an edit operation in Storm, you must enter “edit mode”. Edit mode makes use of several conventions to specify what changes should be made and to what data:

Edit Brackets

The use of square brackets ( [ ] ) within a Storm query can be thought of as entering “edit mode” to perform an edit operation. The data in the brackets specifies the changes to be made involving nodes, properties, light edges, and tags. The only exception is deleting nodes, which is done using the Storm delnode command.

The square brackets used for the Storm data modification (edit) syntax indicate “perform the enclosed changes” in a generic way. Edit brackets are used to perform any of the following:

All of the above directives can be specified within a single set of brackets (subject to Storm logic and Storm’s pipeline behavior).

Warning

It is critical to remember that the brackets are NOT a boundary that segregates nodes; the brackets simply indicate the start and end of an edit operation. In other words, the brackets do NOT separate “nodes the modifications should apply to” from “nodes they should not apply to”. Storm Operation Chaining with left-to-right processing order still applies. Editing is simply another Storm operation, so the specified edits will be performed on ALL nodes inbound to the edit operation as part of the Storm pipeline, regardless of whether those nodes are within or outside the brackets.

The exception is modifications that are placed within Edit Parentheses, which can be used to segregate specific edit operations.

Note

For simplicity, syntax examples below demonstrating how to add nodes, modify properties, etc. only use edit brackets. See Combining Data Modification Operations below for examples showing the use of edit brackets with and without edit parentheses.

Edit Parentheses

Storm supports the use of edit parentheses ( ( ) ) inside of Edit Brackets. Edit parentheses (“parens”) explicitly limit a set of modifications to a specific node or nodes by enclosing the node(s) and their associated modification(s) within the parentheses. This “overrides” the default behavior for edit brackets, which is that every change specified within the brackets applies to all nodes inbound to the edit operation. Edit parens thus allow you to make limited changes “inline” with a more complex Storm query instead of having to use a smaller, separate query to make those changes.

Note that multiple sets of edit parens can be used within a single set of edit brackets; each set of edit parens delimits a separate set of edits.

See Combining Data Modification Operations below for examples showing the use of edit brackets with and without edit parentheses.

“Try” Operator

The Storm “try” operator can be used in edit operations when setting properties ( ?= ) or adding tags ( +?# ).

Properties in Synapse are subject to Type Enforcement. Type enforcement makes a reasonable attempt to ensure that a value “makes sense” for the property in question - that the value you specify for an inet:ipv4 node looks reasonably like an IPv4 address (and not an FQDN or URL). If you try to set a property value that does not pass Synapse’s type enforcement validation, Synapse will generate a BadTypeValu error. The error will cause the currently executing Storm query to halt and stop processing.

When using the try operator, Synapse will to attempt (try) to set the property value. With the try operator, instead of halting in the event of a BadTypeValu error, Synapse will ignore the error (silently fail on that specific edit operation) but continue processing the rest of the Storm query.

The try operator is especially useful for Storm-based automated ingest of data where the data source may contain bad (improperly typed or poorly formatted) data, where a single badly-formatted entry could cause an ingest query to fail in the middle.

For example:

[ inet:ipv4 ?= woot.com ]

will silently fail to create an inet:ipv4 node with the improper value woot.com.

In contrast:

[ inet:ipv4 = woot.com ]

will throw a BadTypeValu error and exit.

Tip

See the array section of the Storm Reference - Type-Specific Storm Behavior for specialized “try” syntax when working with arrays.

Tags and the “Try” Operator

Tags are also nodes (syn:tag nodes), and tag values are also subject to type enforcement. As such, the “try” operator can also be used when applying tags:

inet:ipv4 = 58.158.177.102 [ +?#cno.infra.dns.sink.hole ]

While Synapse automatically normalizes tag elements (e.g., by replacing dash characters ( - ) or spaces with underscores ( _ )), some characters (such as ASCII symbols other than the underscore) are not allowed. The “try” operator may be useful when ingesting third-party data or constructing a tag using a Variable where the variable may contain unexpected values. For example:

inet:ipv4 = 8.8.8.8 [ +?#foo.$tag ]

… where $tag is a variable representing a tag element derived from the source data.

See the syn:tag section of the Storm Reference - Type-Specific Storm Behavior for additional detail on tags / syn:tag forms.

Autoadds and Depadds

Synapse makes use of two optimization features when adding nodes or setting secondary properties: automatic additions (Autoadd) and dependent additions (Depadd).

Autoadd is the process where, on node creation, Synapse will automatically set any secondary properties that are derived from a node’s primary property. Because these secondary properties are based on the node’s primary property (which cannot be changed once set), the secondary properties are read-only.

For example, when creating the email address inet:email=visi@vertex.link, Synapse will automatically set the node’s secondary properties (the username inet:email:user=visi and domain inet:email:fqdn=vertex.link).

Depadd is the process where, on setting a node’s secondary property value, if that property is of a type that is also a form, Synapse will automatically create the form with the corresponding primary property value. (You can view this as the secondary property “depending on” the existence of a node with the corresponding primary property.)

To use the same example, when creating the email inet:email=visi@vertex.link and setting the secondary properties above, Synapse willl also create the associated nodes inet:user=visi and inet:fqdn=vertex.link.

Autoadd and depadd work together (and recursively) to simplify adding data to Synapse.

Add Nodes

Operation to add the specified node(s) to a Cortex.

Syntax:

[ <form> = | ?= <valu>]

Tip

You can optionally use the “Try” Operator ( ?= ) when adding nodes.

Examples:

Create a simple node (FQDN):

[ inet:fqdn = woot.com ]

Create a composite (comp) node (DNS A record):

[ inet:dns:a=(woot.com, 12.34.56.78) ]

Create a GUID node by generating an arbitrary guid using the asterisk character:

[ risk:threat='*' ]

Create a GUID node by specifying a list of string values used to generate a predictable guid:

[ risk:threat=(mandiant, apt1) ]

Tip

For information on the differences and use cases for arbitrary vs. predictable / deconflictable guids, see the guid section of the Storm Reference - Type-Specific Storm Behavior.

Storm also includes various gen (“generate”) commands to simplify the creation of some common guid forms.

Create a digraph (edge) node:

[ edge:refs=((media:news, 00a1f0d928e25729b9e86e2d08c127ce), (inet:fqdn, woot.com)) ]

Note

In many cases, the use of an Edge (Digraph) Form has been replaced by a Lightweight (Light) Edge.

Create multiple nodes in a single edit operation:

[ inet:fqdn=woot.com inet:ipv4=12.34.56.78 hash:md5=d41d8cd98f00b204e9800998ecf8427e ]

Usage Notes:

  • If a node specified within the edit brackets does not exist, Synapse creates and returns the node. If the node already exists, Synapse simply returns (lifts) the node.

  • When creating a <form> whose <valu> consists of multiple components, the components must be passed as a comma-separated list enclosed in parentheses.

  • Once a node is created, its primary property (<form> = <valu>) cannot be modified. The only way to “change” a node’s primary property is to create a new node (and optionally delete the old node).

Add or Modify Properties

Operation to add (set) or change one or more properties on the specified node(s).

The same syntax is used to apply a new property or modify an existing property.

Syntax:

<query> [ : <prop> = | ?= <pval>]

Tip

You can optionally use the “Try” Operator ( ?= ) when setting or modifying properties.

Note

Synapse supports secondary properties that are arrays (lists or sets of typed forms), such as ou:org:names. See the array section of the Storm Reference - Type-Specific Storm Behavior guide for the syntax used to add or modify array properties.

Examples:

Add (or modify) a secondary property:

<inet:ipv4> [ :loc=us.oh.wilmington ]

Add (or modify) a universal property:

<inet:dns:a> [ .seen=("2017/08/01 01:23", "2017/08/01 04:56") ]

Usage Notes:

  • Specifying a property will set the <prop> = <pval> if it does not exist, or modify (overwrite) the <prop> = <pval> if it already exists. There is no prompt to confirm overwriting of an existing property.

  • Storm will return an error if the inbound set of nodes contains any forms for which <prop> is not a valid property. For example, attempting to set a :loc property when the inbound nodes contain both domains and IP addresses will return an error as :loc is not a valid secondary property for a domain (inet:fqdn).

  • Properties to be set or modified must be specified by their relative property name. For example, for the form foo:bar with the property baz (i.e., foo:bar:baz) the relative property name is specified as :baz.

Add or Modify Properties Using Subqueries

Secondary property values can be set using a subquery to assign the value. The subquery executes a Storm query to lift the node(s) whose primary property should be assigned as the value of the secondary property.

This is a specialized use case that is most useful when working with property values that are guids (see GUID) as it avoids the need to type or copy and paste the guid value. Using a subquery allows you to reference the guid node using a more “human friendly” method.

(See Storm Reference - Subqueries for additional detail on subqueries.)

Tip

You can optionally use the “Try” Operator ( ?= ) when setting or modifying properties using a subquery.

Syntax:

<query> [ : <prop> = | ?= { <query> }]

Examples:

Use a subquery to assign an organization’s (ou:org) guid as the secondary property of a ps:contact node:

storm> ps:contact:orgname="U.S. Department of Justice" [ :org={ ou:org:alias=usgovdoj } ]
ps:contact=d41d8cd98f00b204e9800998ecf8427e
        :address = 950 pennsylvania avenue nw, washington, dc, 20530-0001
        :loc = us.dc.washington
        :org = 0fa690c06970d2d2ae74e43a18f46c2a
        :orgname = u.s. department of justice
        :phone = +1 (202) 514-2000
        .created = 2024/12/13 18:41:22.467

In the example above, the subquery ou:org:alias=usgovdoj is used to lift the organization node with that :alias property value and assign the ou:org node’s guid value to the :org property of the ps:contact node.

Use a subquery to assign one or more industries (ou:industry) to an organization (ou:org):

storm> ou:org:name=apple [ :industries+={ ou:industry:name="computers and electronics" ou:industry:name="telecommunications" } ]
ou:org=2848b564bf1e68563e3fea4ce27299f3
        :alias = apple
        :industries = ['778e334bee7a3542b31e70d3d411d648', '8555160e35674492e1e9eb7e741c39de']
        :loc = us.ca.cupertino
        :name = apple
        :names = ['apple', 'apple, inc.']
        :phone = +1 (408) 996-1010
        .created = 2024/12/13 18:41:22.530

In the example above, the subquery is used to lift the specified industry nodes (ou:industry) and assign both nodes’ guid values to the ou:org:industries property for Apple’s organization node.

Note

The ou:org:industries property is an array (a list or set of typed forms), so the query above uses array-specific syntax. See the array section of the Storm Reference - Type-Specific Storm Behavior guide for detail on the syntax used to add or modify array properties.

Usage Notes:

  • When using a subquery to assign a property value, Storm will throw an error if the subquery fails to lift any nodes.

  • When using a subquery to assign a value to a property that takes only a single value, Storm will throw an error if the subquery returns more than one node.

  • When using a subquery to assign a property value, the subquery cannot iterate more than 128 times or Storm will throw an error. For example, attempting to assign “all the industries” to a single organization ( ou:org=<guid> [ :industries+={ ou:industry } ] ) will error if there are more than 128 ou:industry nodes.

Delete Properties

Operation to delete (fully remove) one or more properties from the specified node(s).

Note

In Synapse 2.x, a property must be deleted from the Layer where the property exists. Generally speaking, this means you must be in the View where the relevant layer is the topmost (writeable) layer in order to delete the property.

Syntax:

<query> [ -: <prop>]

Examples:

Delete the :loc property from an inet:ipv4 node:

<inet:ipv4> [ -:loc ]

Delete multiple properties from a media:news node:

<media:news> [ -:author -:summary ]

Usage Notes:

  • Deleting a property fully removes the property from the node; it does not set the property to a null value.

Delete Nodes

Nodes can be deleted from a Cortex using the Storm delnode command.

Add Light Edges

Operation that links the specified node(s) to another node or set of nodes (as specified by a Storm expression) using a lightweight edge (light edge).

See Lightweight (Light) Edge for details on light edges.

Syntax:

<query> [ +( <verb> )> { <storm> } ]

<query> [ <( <verb> )+ { <storm> } ]

Note

The query syntax used to create light edges will yield the nodes that are inbound to the edit brackets (that is, the nodes represented by <query>).

The nodes specified by the Storm expression ( { <storm> } ) must already exist in the Cortex or must be created as part of the Storm expression (i.e., using edit brackets) in order for the light edges to be created.

Examples:

Link the specified FQDN and IPv4 to the media:news node referenced by the Storm expression using a “refs” light edge:

inet:fqdn=woot.com inet:ipv4=1.2.3.4 [ <(refs)+ { media:news=a3759709982377809f28fc0555a38193 } ]

Link the specified media:news node to the set of indicators tagged APT1 (#rep.mandiant.apt1) using a “refs” (references) light edge:

media:news=a3759709982377809f28fc0555a38193 [ +(refs)> { +#rep.mandiant.apt1 } ]

Link the inet:whois:iprec netblock registration (whois) record to any IP address within the specified netblock range (as referenced by the Storm expression) that already exists in Synapse using an “ipwhois” light edge:

inet:whois:iprec:name=OVH-CUST-3399212 [ +(ipwhois)> { inet:ipv4=198.50.240.220-198.50.240.223 } ]

Link the inet:whois:iprec netblock registration (whois) record to every IP in the specified netblock range (as referenced by the Storm expression) using an “ipwhois” light edge, creating the IPs if they do not exist:

inet:whois:iprec:name=OVH-CUST-3399212 [ +(ipwhois)> { [ inet:ipv4=198.50.240.220-198.50.240.223 ] } ]

Usage Notes:

  • The plus sign ( + ) used with the light edge expression within the edit brackets is used to create the light edge(s).

  • Light edges can be created in either “direction” (e.g., with the directional arrow pointing either right ( +(<verb>)> ) or left ( <(<verb>)+ ) - whichever syntax is easier.

  • Synapse does not include any pre-existing light edges / light edge verbs. Users can create and define light edges to meet their needs.

  • Synapse’s data model documentation for Forms lists various light edges that can be used with each form, based on The Vertex Project’s recommendations. Use of these specific edges is not enforced by Synapse, although these edges may be created by various Vertex-provided Power-Ups.

  • Light edge verbs are created “on the fly” when they are first used to link nodes; they do not need to be created or defined in advance before they can be used.

  • A light edge’s verb typically has a logical direction (a report “references” a set of indicators that it contains, but the indicators do not “reference” the report). It is up to the user to create the light edges in the correct direction and use forms that are sensical for the light edge verb. That is, there is nothing in the Storm syntax itself to prevent users linking arbitrary nodes in arbitrary directions using arbitrary light edges.

  • The Storm edges, lift, and model commands can be used to work with light edges in Synapse.

Delete Light Edges

Operation that deletes the light edge linking the specified node(s) to the set of nodes specified by a given Storm expression.

See Lightweight (Light) Edge for details on light edges.

Note

In Synapse 2.x, a light edge must be deleted from the Layer where the edge exists. Generally speaking, this means you must be in the View where the relevant layer is the topmost (writeable) layer in order to delete the edge.

Syntax:

<query> [ -( <verb> )> { <storm> } ]

<query> [ <( <verb> )- { <storm> } ]

Caution

The minus sign ( - ) used with a light edge outside any edit brackets simply instructs Storm to traverse (“walk”) the specified light edge (see Traversal Operations). The minus sign used with a light edge inside edit brackets instructs Storm to delete the specified edges.

Examples:

Delete the “refs” light edge linking the MD5 hash of the empty file to the specified media:news node:

hash:md5=d41d8cd98f00b204e9800998ecf8427e [ <(refs)- { media:news=a3759709982377809f28fc0555a38193 } ]

Delete the “ipwhois” light edge linking IP 1.2.3.4 to the specified netblock registration (whois) record:

inet:whois:iprec:name=OVH-CUST-3399212 [ -(ipwhois)> { inet:ipv4=1.2.3.4 } ]

Usage Notes:

  • The minus sign ( - ) used with the light edge expression within the edit brackets is used to delete the light edge(s).

  • Light edges can be deleted in either “direction” (e.g., with the directional arrow pointing either right ( -(<verb>)> ) or left ( <(<verb>)- ) - whichever syntax is easier.

Add Tags

Operation to add one or more tags to the specified node(s).

Tip

You can optionally use the “Try” Operator ( +?# ) when adding tags.

Syntax:

<query> [ +# | +?# <tag>]

Examples:

Add a single tag:

<inet:ipv4> [ +#cno.infra.anon.tor.exit ]

Add multiple tags:

<inet:fqdn> [ +#rep.mandiant.apt1 +#cno.infra.dns.sink.holed ]

Add Tag Timestamps or Tag Properties

Synapse supports the use of Tag Timestamps and Tag Properties to provide additional context to tags where appropriate.

Tip

You can optionally use the “Try” Operator when setting or modifying tag timestamps or tag properties.

  • When using the try operator with tag timestamps, the operator is used with the tag name ( +?#<tag>=<time> or +?#<tag>=(<min_time>,<max_time>) ).

  • When using the try operator with a tag property, the operator is used with the tag property value ( +#<tag>:<tagprop>?=<pval> ).

Note that the tag and tag timestamp(s) or the tag and tag property are evaluated as a whole; if any part of the tag expression is invalid, the full edit operation will fail. For example, when attempting to add a tag with timestamps where the tag is valid but the timestamp values are not, neither the tag nor the timestamps will be applied.

Syntax:

Add tag timestamps:

<query> [ +# | +?# <tag> = <time> | ( <min_time> , <max_time> )]

Add tag property:

<query> [ +# <tag> : <tagprop> = | ?= <pval>]

Examples:

Add tag with single timestamp:

<inet:fqdn> [ +#cno.infra.dns.sink.holed=2018/11/27 ]

Add tag with a time interval (min / max):

<inet:fqdn> [ +#cno.infra.dns.sink.holed=(2014/11/06, 2016/11/06) ]

Tip

Tag timestamps are intervals (ival types). See the ival section of the Storm Reference - Type-Specific Storm Behavior for details on interval behavior and working with intervals.

Add tag with custom tag property and value:

<inet:fqdn> [ +#rep.symantec:risk = 87 ]

Tip

Tag properties must be defined and added to the data model before they can be used. See Tag Properties for additional information.

Usage Notes:

  • Tag Timestamps and Tag Properties are applied only to the tags to which they are explicitly added. For example, adding a timestamp to the tag #foo.bar.baz does not add the timestamp to tags #foo.bar and #foo.

Modify Tags

Tags are “binary” in that they are either applied to a node or they are not. Tag names cannot be changed once set. To “change” the tag applied to a node, you must add the new tag and delete the old one.

Tip

The Storm movetag command can be used to modify tags in bulk - that is, migrate an entire set of tags (i.e., effectively “rename” the tags by creating and applying new tags and removing the old ones) or move a tag to a different tag tree.

Modify Tag Timestamps or Tag Properties

Tag timestamps or tag properties can be modified using the same syntax used to add the timestamp or property.

Tip

Tag timestamps are intervals (ival types). See the ival section of the Storm Reference - Type-Specific Storm Behavior for details on interval behavior when modifying interval values.

Remove Tags

Operation to delete one or more tags from the specified node(s).

Removing a tag from a node differs from deleting the node representing a tag (a syn:tag node), which can be done using the Storm delnode command.

Note

In Synapse 2.x, a tag must be deleted from the Layer where the tag exists. Generally speaking, this means you must be in the View where the relevant layer is the topmost (writeable) layer in order to delete the tag.

Syntax:

<query> [ -# <tag>]

Examples:

Remove a leaf tag (i.e., the final or rightmost element of the tag):

<inet:ipv4> [ -#cno.infra.anon.tor.exit ]

Remove a full tag (i.e., the entire tag):

<inet:ipv4> [ -#cno ]

Usage Notes:

  • Deleting a leaf tag deletes only the leaf tag from the node. For example, [ -#foo.bar.baz ] will delete the tag #foo.bar.baz but leave the tags #foo.bar and #foo on the node.

  • Deleting a non-leaf tag deletes that tag and all tags below it in the tag hierarchy from the node. For example, [ -#foo ] used on a node with tags #foo.bar.baz and #foo.hurr.derp will remove all of the following tags:

    • #foo.bar.baz

    • #foo.hurr.derp

    • #foo.bar

    • #foo.hurr

    • #foo

Tip

The Storm tag.prune command can be used to recursively remove tags (i.e., from a leaf tag up through parent tags that do not have other children).

Remove Tag Timestamps

To remove a tag timestamp from a tag, you must remove the tag element that contains the timestamp. The tag element can be re-added without the timestamp if needed.

Remove Tag Properties

Removing a tag property deletes the property and any property value. The tag element to which the property was appended will remain.

Syntax:

Remove a tag property:

<query> [ -# <tag> : <tagprop>]

Example:

Remove the custom tag property ‘:risk’ from a tag:

<inet:fqdn> [ -#rep.symantec:risk ]

Combining Data Modification Operations

Storm allows you to perform multiple edits within a single edit operation (set of edit brackets).

Simple Examples

Create a node and add secondary properties:

[ inet:ipv4=94.75.194.194 :loc=nl :asn=60781 ]

Create a node and add a tag:

[ inet:fqdn=blackcake.net +#rep.mandiant.apt1 ]

Edit Brackets and Edit Parentheses Examples

Edit parentheses can be used within edit brackets to isolate edit operations (e.g., so a particular edit does not apply to all inbound nodes).

The following examples illustrate the differences in Storm behavior when using Edit Brackets alone vs. with Edit Parentheses.

When performing simple edit operations (i.e., Storm queries that add / modify a single node, or apply a tag to the nodes retrieved by a Storm lift operation) users can generally use edit brackets alone without delimiting edit operations within additional edit parentheses (edit parens).

Edit parens may be necessary when creating and modifying multiple nodes in a single query, or performing edits within a longer or more complex Storm query. In these cases, understanding the difference between edit brackets’ “operate on everything inbound” vs. edit parens’ “limit modifications to the specified nodes” is critical to avoid unintended data modifications.

Example 1:

Consider the following Storm query that uses only edit brackets:

inet:fqdn#rep.mandiant.apt1 [ inet:fqdn=somedomain.com +#rep.eset.sednit ]

The query will:

  • Lift all domains that Mandiant associates with APT1 (i.e., tagged #rep.mandiant.apt1).

  • Create the new domain somedomain.com (if it does not already exist) or lift it (if it does).

  • Apply the tag #rep.eset.sednit to the domain somedomain.com and to all of the domains tagged #rep.mandiant.apt1 (because those FQDNs are inbound to the edit operation / edit brackets).

We can see the effects in the output of our example query:

storm> inet:fqdn#rep.mandiant.apt1 [ inet:fqdn=somedomain.com +#rep.eset.sednit ]
inet:fqdn=newsonet.net
        :domain = net
        :host = newsonet
        :issuffix = false
        :iszone = true
        :zone = newsonet.net
        .created = 2024/12/13 18:41:22.726
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.eset.sednit
        #rep.mandiant.apt1
inet:fqdn=staycools.net
        :domain = net
        :host = staycools
        :issuffix = false
        :iszone = true
        :zone = staycools.net
        .created = 2024/12/13 18:41:22.734
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.eset.sednit
        #rep.mandiant.apt1
inet:fqdn=blackcake.net
        :domain = net
        :host = blackcake
        :issuffix = false
        :iszone = true
        :zone = blackcake.net
        .created = 2024/12/13 18:41:22.938
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.eset.sednit
        #rep.mandiant.apt1
inet:fqdn=purpledaily.com
        :domain = com
        :host = purpledaily
        :issuffix = false
        :iszone = true
        :zone = purpledaily.com
        .created = 2024/12/13 18:41:22.748
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.eset.sednit
        #rep.mandiant.apt1
inet:fqdn=hugesoft.org
        :domain = org
        :host = hugesoft
        :issuffix = false
        :iszone = true
        :zone = hugesoft.org
        .created = 2024/12/13 18:41:22.741
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.eset.sednit
        #rep.mandiant.apt1
inet:fqdn=somedomain.com
        :domain = com
        :host = somedomain
        :issuffix = false
        :iszone = true
        :zone = somedomain.com
        .created = 2024/12/13 18:41:23.221
        #rep.eset.sednit

Consider the same query using edit parens inside the brackets:

inet:fqdn#rep.mandiant.apt1 [ ( inet:fqdn=somedomain.com +#rep.eset.sednit ) ]

Because we used the edit parens, the query will:

  • Lift all domains that Mandiant associates with APT1 (i.e., tagged #rep.mandiant.apt1).

  • Create the new domain somedomain.com (if it does not already exist) or lift it (if it does).

  • Apply the tag rep.eset.sednit only to the domain somedomain.com.

We can see the difference in the output of the example query:

storm> inet:fqdn#rep.mandiant.apt1 [ ( inet:fqdn=somedomain.com +#rep.eset.sednit ) ]
inet:fqdn=newsonet.net
        :domain = net
        :host = newsonet
        :issuffix = false
        :iszone = true
        :zone = newsonet.net
        .created = 2024/12/13 18:41:22.726
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.mandiant.apt1
inet:fqdn=staycools.net
        :domain = net
        :host = staycools
        :issuffix = false
        :iszone = true
        :zone = staycools.net
        .created = 2024/12/13 18:41:22.734
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.mandiant.apt1
inet:fqdn=blackcake.net
        :domain = net
        :host = blackcake
        :issuffix = false
        :iszone = true
        :zone = blackcake.net
        .created = 2024/12/13 18:41:22.938
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.mandiant.apt1
inet:fqdn=purpledaily.com
        :domain = com
        :host = purpledaily
        :issuffix = false
        :iszone = true
        :zone = purpledaily.com
        .created = 2024/12/13 18:41:22.748
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.mandiant.apt1
inet:fqdn=hugesoft.org
        :domain = org
        :host = hugesoft
        :issuffix = false
        :iszone = true
        :zone = hugesoft.org
        .created = 2024/12/13 18:41:22.741
        #cno.infra.dns.sink.holed = (2014/11/06 00:00:00.000, 2018/11/27 00:00:00.001)
        #rep.mandiant.apt1
inet:fqdn=somedomain.com
        :domain = com
        :host = somedomain
        :issuffix = false
        :iszone = true
        :zone = somedomain.com
        .created = 2024/12/13 18:41:23.221
        #rep.eset.sednit

Example 2:

Consider the following Storm query that uses only edit brackets:

[inet:ipv4=1.2.3.4 :asn=1111 inet:ipv4=5.6.7.8 :asn=2222]

The query will:

  • Create (or lift) the IP address 1.2.3.4.

  • Set the IP’s :asn property to 1111.

  • Create (or lift) the IP address 5.6.7.8.

  • Set the :asn property for both IP addresses to 2222.

We can see the effects in the output of our example query:

storm> [inet:ipv4=1.2.3.4 :asn=1111 inet:ipv4=5.6.7.8 :asn=2222]
inet:ipv4=1.2.3.4
        :asn = 2222
        :type = unicast
        .created = 2024/12/13 18:41:23.338
inet:ipv4=5.6.7.8
        :asn = 2222
        :type = unicast
        .created = 2024/12/13 18:41:23.344

Consider the same query using edit parens inside the brackets:

[ (inet:ipv4=1.2.3.4 :asn=1111) (inet:ipv4=5.6.7.8 :asn=2222) ]

Because the brackets separate the two sets of modifications, IP 1.2.3.4 has its :asn property set to 1111 while IP 5.6.7.8 has its :asn property set to 2222:

storm> [ (inet:ipv4=1.2.3.4 :asn=1111) (inet:ipv4=5.6.7.8 :asn=2222) ]
inet:ipv4=1.2.3.4
        :asn = 1111
        :type = unicast
        .created = 2024/12/13 18:41:23.338
inet:ipv4=5.6.7.8
        :asn = 2222
        :type = unicast
        .created = 2024/12/13 18:41:23.344