Skip to main content
Version: 2.9

ARMR Rule

The term ARMR Rule is an umbrella term that includes all of the rules mentioned in the ARMR Rules section. Please see each rule type for a more detailed description. Each rule type has a unique set of statements to describe and configure the security control.

ARMR Rule Parts

While each ARMR rule models a different aspect of a system, each rule shares a common set of requirements. Each ARMR rule operates on a set of given conditions that need to be configured so that if and when an event is triggered, then an action will be taken. This style of behavior is analogous to behavioral test-driven development of given-when-then. The documentation will describe how each part is configured.

rule("An ARMR Rule"):
given("various conditions")
when("event occurs")
then("take action")
endrule

Every ARMR Rule is configured in a similar fashion, using these Given, When, Then states. Each rule will use these headings to describe how each specific rule needs to be configured.

Given (Conditions)

Each ARMR rule will allow a user to specify a unique set of conditions (configuration options) that will help to specify the nature of the event or define parameters that need to be enforced should an event be triggered. The configuration of the conditions is specific to each ARMR rule. Please consult each rule to learn how to configure it correctly.

When (Event)

The occurrence of an event is where an attack has been detected under the specified conditions, and an action will need to be taken. The configuration of the event is specific to each ARMR rule. Please consult each rule to learn how to configure it correctly.

If multiple ARMR rules exist for a given security feature, precedence is given to the ARMR rule with the more specific event condition, and this rule will be the one that triggers. For example, if a file path is specified as a condition in which the rule should trigger, then the ARMR rule with the most specific file path will take precedence.

Then (Action)

ARMR rules will perform an action on the basis of an event being triggered. In such cases, an ARMR rule can be configured to take action in a number of ways. Some actions have higher priorities than others, which will override rules with lower priority actions. This makes it possible to chain rules together. For example, it is possible to have a broad rule with a lower priority action that denies all events, and then to have more specific rule with a higher priority action that will allow events under certain conditions.

After event condition specificity, action priority then determines rule precedence. Action priority from highest to lowest is: allow (where supported), protect, detect.

detectUsed for monitoring events that have been triggered. Since this action does not interfere with other actions, it will always run. A log entry will be made in the CEF log file.
allowUsed for allowing specific events to happen, overriding the events that are otherwise protected. A log entry will be made in the CEF log file.
protectUsed for specifying events to protect. The type of protection is dependent on the ARMR rule type. A log entry will be made in the CEF log file.
codeA user-specified block of code that will be run when the event has been triggered. No log entries are recorded on execution unless configured by the ARMR developer. In ARMR 2.0, code blocks are only supported in the ARMR Patch rule; in ARMR 3.0 and above, code blocks are supported in all rules.

The action statement may specify a log message. If a log message is specified then a log entry will be generated. The user can specify a custom message to be included in the log entry or, if the log message parameter is left blank, a default log entry is generated.

The log message parameter is mandatory for an action of detect, and is optional for an action of allow or protect. If the log message parameter is omitted then logging will be switched off.

For an action of detect, allow or protect, the action statement may specify a severity. If no severity value is provided then the default severity is set to Unknown. The user may specify the severity as an integer in the range of 0-10 inclusive (0 being least severe and 10 being most severe). The severity may also be specified as one of the following: Low, Med, High or Very-High (case insensitive).

Metadata

As described in more detail in the Armr Mod section, it is possible to declare a metadata() statement since ARMR/2.6, which can be declared either at the mod or rule levels. This section describes the use case at the rule level.

All rule types support metadata() statements.

The behavior of the metadata at the rule level is to inherit all metadata key value pairs from its originating mod, if there is any, in the addition to those defined within the rule itself. Also, whatever key value pairs defined, that may already exist at the mod level, will be overridden by the metadata at the rule level, if they share the same keys. Considering the example when the mod contains part of a quarterly security update for Java:

app("2021 JULY CPU"):
requires(version: ARMR/2.6)
metadata(
affected-os: any,
affected-product-name: "Java SE",
affected-product-version: {
range: {from: "7u0", to: "7u301"}})

patch("CVE-2021-2432 - JNDI component"):
metadata(
cve: "CVE-2021-2432",
cvss: {
score: 3.7,
version: 3.0,
vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L"},
description: "The vulnerability allows a remote non-authenticated attacker to
perform service disruption. The vulnerability exists due to improper
input validation within the JNDI component in Java SE. A remote
non-authenticated attacker can exploit this vulnerability to perform
service disruption.",
affected-product-version: {
range: {from: "7u171", to: "7u301"}})
...
endpatch
endapp

The patch above will inherit the following metadata key value pairs: affected-os, affected-product-name and affected-product-version; but will also contain the following additional ones: cve, cvss and description. As for the value of affected-product-version, since the rule overwrites its inherited value from the mod, it will now be:

affected-product-version: {
range: {from: "7u171", to: "7u301"}}

Logging metadata

Similarly to the Armr Mod section, the log key must be used whenever a metadata key value pair should be logged in security events. At the rule level, this means that every event for that rule will contain any key value pairs marked for logging. Equally with the case example above, metadata at the rule level takes precedence and it will override any behavior or value set out by the originating ARMR mod. So, if the metadata with key affected-product-version is marked for logging at the rule level, it will be logged in security events, thus, overwriting the value set out in the originating mod.

Valid ARMR Example

This example shows how an ARMR Mod may be configured using the ARMR HTTP rule to detect requests to the endpoint "/webapp/index.jsp" which do not have an origin of "host1", "host2", or "host3:8080". In this case, the conditions of this rule is predicated on a URI endpoint of "/webapp/index.jsp". Any request that matches that endpoint are then checked for the CSRF same origin event, indicated by csrf() statement. The event needs to be configured as a same origin event using the same-origin keyword. In this case, the request must have the origin header that contains a host that matches one of the hosts specified in the rule. Should a request fail the parameters declared in the event, then an action will be taken. In this case, the detect() action will take place, alerting the user that an invalid request was detected.

app("Security Rules"):
requires (version: "ARMR/2.0")

http("Detect HTTP requests with invalid origin header"):
request(paths: "/webapp/index.jsp")
csrf(same-origin,
options: {
hosts: ["host1", "host2", "host3:8080"]})
detect(message: "HTTP Same Origin validation failed", severity: 7)
endhttp

endapp

Invalid ARMR Example

Unrecognized but well-formatted rule declarations inside the app will be ignored by the parser. Consider the example below. The foo block will be ignored but the http rule will still be loaded. If an invalid ARMR Rule exists, an error message will be printed to the CEF log.

app("Security Rules"):
requires (version: "ARMR/2.0")

foo("a foo rule"):
endfoo

http("Deny HTTP requests with invalid origin header"):
request(paths: "/webapp/index.jsp")
csrf(same-origin,
options: {
hosts: ["host1", "host2", "host3:8080"]})
detect(message: "HTTP Same Origin validation failed", severity: 7)
endhttp

endapp

ARMR Rule Life-Cycle

Every ARMR Rule transitions through a five-stage lifecycle inside the ARMR Engine. Understanding this
lifecycle is important in order to understand the state of the rules inside the ARMR Engine. With the
exception of execute, each state of the rules lifecycle is shown in the CEF log. The following table
describes each state.

loadThe syntax of the ARMR rule is valid and the rule has been loaded into the ARMR Engine.
linkThe ARMR rule has been compiled into the running application and is ready to begin executing on the next occurrence of the defined event.
executeThe ARMR rule has executed and the action of the rule has been applied. Each unique execution of the ARMR rule is a unique execute event. Execute events are not recorded in the CEF log file, although some ARMR Engine implementations may provide special configuration options to enable CEF logging of execute events.
unlinkThe ARMR rule has been uncompiled from the running application and will no longer execute on future occurrences of the defined event.
unloadThe ARMR rule has been unloaded from the ARMR Engine.
reloadRule(s) will be reloaded by ARMR engine on detection of a change to rule content

Reloading of rules will only occur when the rule’s configuration and desired behavior has changed such as log message and/or Java code, otherwise the rule will not be reloaded.

Only changed ARMR mods will be reloaded.

The output of the Security CEF log file will have the following format.

<14>1 2020-03-10T14:51:34.493Z localhost.localdomain java 52928 - - CEF:0|ARMR:ARMR|ARMR|2.3|CVE-2019-2769 :01|Link Rule|Low|outcome=success procid=52928 dvchost=localhost.localdomain rt=Mar 10 2020 14:51:34.493 +0000 appVersion=1
<14>1 2020-03-10T14:51:34.493Z localhost.localdomain java 52928 - - CEF:0|ARMR:ARMR|ARMR|2.3|CVE-2019-2769 :01|Link Rule|Low|outcome=success procid=52928 dvchost=localhost.localdomain rt=Mar 10 2020 14:51:34.494 +0000 appVersion=1

Limiting ARMR rules to specific Operating Systems

Additionally, each ARMR rule can be restricted to run on specific operating systems. This is particularly useful for security protections that are OS-dependent (e.g. file reads and writes) and allows for large-scale deployments of whole policies with ARMR Mods that target different Operating Systems. It also notifies agents of whether the rule is applicable and should be applied to the OS that it is currently running on.

To enable the OS constraint, pass the OS name, or a comma-separated list of names, as an argument to the rule. Examples:

  • rule(”my_rule”, os: [windows]):

  • rule(“my_rule2”, os: [linux, solaris]):

The valid constants are:

  • windows

  • linux

  • aix

  • solaris

  • any

When the ARMR Mod is loaded, if it does not satisfy the OS constraint, a log-entry such as the following will be produced:

<14>1 2020-07-10T11:12:06.213Z I-dev05 java 91730 - - CEF:0|ARMR:ARMR|ARMR|2.3|CVE-2019-2933 :04|Load Rule|Low|rt=Jul 10 2020 11:12:06.213 +0100 dvchost=I-dev05 procid=91730 outcome=failure reason=rule is not applicable to the currently running operating system appVersion=1