feat(rapid7-insightidr): render the detection as Markdown, and fix four gaps (v1.10.0)
An "Multiple User Accounts Were Disabled" investigation came back with one entity — the actor — while the layout stayed nearly empty. Four separate reasons, and the last one is why the first three keep recurring. evidences was an OBJECT, not an array. JSONata returns a bare object when the path yields one item, so the key had one shape on an investigation with a single alert and another with two. Bracketed to force an array. Only the actor was mapped. An ad_admin rule names who acted AND who it was done to, and on this alert the disabled accounts are the point of it. Target account, target user and both domains now map to the OCSF Target User group, the actor to Actor — the distinction that lets the sentence be read in one line. The domain controller was nowhere. A Windows event puts it in source_json.computerName and nowhere else, and source_json was skipped whole because the Azure AD one runs to kilobytes. Its top-level SCALARS are now read — bounded, and where computerName, osVersion and callerIpAddress live — while its nested part stays skipped. source_asset was the string "unknown". Mapped as-is it becomes an asset named "unknown" in the entity index, shared by every incident that had no asset: a pivot that groups things by the absence of a fact. Placeholders are dropped, and a key whose value cleans away to nothing is removed rather than kept empty, since "" is not nil and would still be written to its OCSF field. Five entities now, from one: both accounts, both display names, the DC. And the reason this kept happening. The layout builder's field picker is a closed <select> over the OCSF catalogue in web/src/lib/ocsf.ts, so a path absent from it cannot be placed on a layout at all — which is what `detection` and `evidence` are, and what every unanticipated key will be. Mapping each one to a real OCSF field is right where a field exists, but rule_keys_of_interest is an open vocabulary: four spellings turned up in as many days. So the whole of it is also rendered as a Markdown table into custom:rapid7_summary — keys of interest first, since the rule itself says those are what matter, then the evidence fields. Declare a custom field of type markdown with that name, put it on the layout, and a new rule type is readable the day it appears instead of after another mapping round. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,11 @@ field_mappings:
|
||||
"custom:rapid7_logset_id": "first_alert_logset_id"
|
||||
"custom:rapid7_rule_rrn": "first_alert_rule_rrn"
|
||||
"custom:rapid7_event_type": "first_alert_event_type"
|
||||
# Every key the detection emitted, rendered as Markdown. Declare a custom field
|
||||
# named rapid7_summary of type markdown and place it on the layout: it shows
|
||||
# what no OCSF mapping can, because the layout's field picker only offers paths
|
||||
# from the OCSF catalogue and this vocabulary is open-ended.
|
||||
"custom:rapid7_summary": "summary_markdown"
|
||||
ocsf:
|
||||
# ── Finding: the investigation ────────────────────────────────────
|
||||
- { source_path: "rrn", ocsf_field: "finding_info.uid" }
|
||||
@@ -177,6 +182,23 @@ ocsf:
|
||||
# offers, unlike `evidence` above, which only ever shows in the Context tab.
|
||||
- { source_path: "alerts[0].evidence_raw_line", ocsf_field: "raw_data" }
|
||||
- { source_path: "alerts[0].evidence_fields.msg ? alerts[0].evidence_fields.msg : alerts[0].evidence_fields.logdesc", ocsf_field: "message" }
|
||||
# ── Who did it to whom ────────────────────────────────────────────
|
||||
# An ad_admin rule names an actor and a target account, and mapping only the
|
||||
# actor loses the victims — on "Multiple User Accounts Were Disabled" the
|
||||
# disabled accounts are the whole point of the alert.
|
||||
- { source_path: "alerts[0].evidence_fields.target_account", ocsf_field: "user.name" }
|
||||
- { source_path: "alerts[0].evidence_fields.target_user", ocsf_field: "user.full_name" }
|
||||
- { source_path: "alerts[0].evidence_fields.target_user_domain", ocsf_field: "user.domain" }
|
||||
- { source_path: "alerts[0].evidence_fields.source_user", ocsf_field: "actor.user.full_name" }
|
||||
- { source_path: "alerts[0].evidence_fields.source_user_domain", ocsf_field: "actor.user.domain" }
|
||||
- { source_path: "alerts[0].evidence_fields.source_account", ocsf_field: "actor.user.name" }
|
||||
# The machine the event was recorded on. A Windows event puts it in
|
||||
# source_json.computerName and nowhere else; source_asset is the parsed field
|
||||
# when the source fills it, and is dropped when it says "unknown".
|
||||
- { source_path: "alerts[0].evidence_fields.source_asset", ocsf_field: "device.hostname" }
|
||||
- { source_path: "alerts[0].evidence_fields.computername", ocsf_field: "device.hostname" }
|
||||
- { source_path: "alerts[0].evidence_fields.osversion", ocsf_field: "device.os.name" }
|
||||
- { source_path: "alerts[0].evidence_fields.calleripaddress", ocsf_field: "src_endpoint.ip" }
|
||||
# ── Process tree ──────────────────────────────────────────────────
|
||||
# The layout block reads ctx.process_tree: N flat chains, root first, each
|
||||
# {alert_id, rule, host, user, nodes[]}. Rapid7 nests its tree through
|
||||
@@ -190,8 +212,11 @@ ocsf:
|
||||
# the SECOND and THIRD alert are indexed as entities too — the extractor walks arrays
|
||||
# and classifies on the path's suffix, so `.hostname` under here counts exactly as
|
||||
# `device.hostname` does above.
|
||||
# The brackets force an array. Without them JSONata returns a bare OBJECT when
|
||||
# the investigation holds a single alert and an array when it holds two, so the
|
||||
# same key had two shapes depending on how busy the attacker was.
|
||||
- source_path: >
|
||||
alerts.{
|
||||
[alerts.{
|
||||
"uid": rrn,
|
||||
"title": title,
|
||||
"time": alerted_at,
|
||||
@@ -207,5 +232,5 @@ ocsf:
|
||||
"technique": rule.mitre_tcodes[$substring($, 0, 2) != 'TA'][0],
|
||||
"detection": rule_keys_of_interest{key: values[0]},
|
||||
"evidence": evidence_fields
|
||||
}
|
||||
}]
|
||||
ocsf_field: "evidences"
|
||||
|
||||
Reference in New Issue
Block a user