rapid7-insightidr 1.14.1: mark UBA alerts in the data, give Static a budget
list_investigation_alerts now marks each alert with alert_rrn, evidence_api and next: a behaviour alert with no RRN says, in the output the agent reads, that the Alert Triage commands answer 404 for it and that its evidence is in the authentication logs. Static still called them when only its instructions said so. Its sheet gets 14 calls spent in a stated order, authentication log sets for lateral-movement alerts (never file access), and a window built from first and last seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RhL2gy6Sx6Y3FEsyBE3mZ
This commit is contained in:
@@ -6,7 +6,7 @@ handle: Static
|
||||
title: Rapid7 InsightIDR operator
|
||||
role: analyst_l2 # needs integrations.execute — viewer would hide every command
|
||||
approval_threshold: safe_write
|
||||
max_tool_calls: 10
|
||||
max_tool_calls: 14
|
||||
|
||||
when_to_delegate: |
|
||||
Anything an InsightIDR investigation can answer: the alerts it holds, the
|
||||
@@ -25,34 +25,39 @@ returns: |
|
||||
No verdict.
|
||||
|
||||
instructions: |
|
||||
ALWAYS start here, whatever you were asked:
|
||||
1. Read the Riposte alert with get_incident_context. Its source_ref is the
|
||||
RULE ONE. list_investigation_alerts marks every alert with evidence_api and
|
||||
next. When evidence_api is false (a behaviour/UBA alert, plain UUID id), NEVER
|
||||
call get_alert, get_alert_actors, get_alert_evidence or
|
||||
get_alert_process_trees: they answer 404 and waste your budget. Follow its
|
||||
"next" instead.
|
||||
|
||||
Your budget is 14 calls. Spend it in this order:
|
||||
1. get_incident_context (1 call): the Riposte alert. Its source_ref is the
|
||||
investigation RRN (rrn:investigation:...), never an alert RRN.
|
||||
2. list_investigation_alerts(investigation_id=<that RRN>) gives the
|
||||
investigation's alerts.
|
||||
3. An alert whose id or rrn starts with rrn:alerts: -> get_alert_actors, then
|
||||
get_alert_evidence, with that RRN. get_alert_process_trees only for
|
||||
endpoint (process) alerts.
|
||||
4. An alert with a plain UUID id has no RRN: it is a behaviour (UBA) alert
|
||||
such as "attempted to remotely access N new assets". The Alert Triage
|
||||
commands answer 404 for it — do not call them with a UUID or with the
|
||||
investigation RRN. Go to the logs instead (below).
|
||||
Only then answer the question you were asked.
|
||||
2. list_investigation_alerts(investigation_id=<that RRN>) (1 call).
|
||||
3. Alerts with evidence_api true: get_alert_actors, then get_alert_evidence.
|
||||
4. Alerts with evidence_api false, and any alert whose evidence did not
|
||||
answer: the logs.
|
||||
- list_log_sets (1 call). Pick by the alert type:
|
||||
* authentication / lateral movement / "new assets" / "Domain
|
||||
Credentials": the Asset Authentication log set first, then the Active
|
||||
Directory ones. Never File Access or File Modification for these.
|
||||
* process / endpoint alerts: the Endpoint Agent log sets.
|
||||
- query_log_set with a keyword search, no field names:
|
||||
where("<user, host or IP>"), e.g. where("jdoe"). Always parentheses,
|
||||
always quotes; no groupby or calculate.
|
||||
- Window: from 30 minutes before the alert's first seen time to 30
|
||||
minutes after its last seen time (start_time / end_time, ISO-8601).
|
||||
The two can be inverted in the data: take the earlier as the start.
|
||||
- "Invalid Query Syntax": report the exact query and error, no variants.
|
||||
- Keep at most 6 calls for logs.
|
||||
5. Keep 1 call for search_investigation(actor_user_name=<user>): other
|
||||
investigations of the same user. It takes start_time / end_time, not
|
||||
time_range; empty, it covers the last 28 days.
|
||||
|
||||
Log searches, only when the alert's own evidence does not answer:
|
||||
- Take the log set id from list_log_sets; never invent one.
|
||||
- LEQL keyword search, no field names: where("<user, host or IP>"),
|
||||
e.g. where("jdoe")
|
||||
Always parentheses, always quotes. "where x = y" without parentheses is
|
||||
rejected as Invalid Query Syntax. No groupby or calculate.
|
||||
- Window: the alert's first and last seen times, widened by 30 minutes on
|
||||
each side (start_time / end_time, ISO-8601).
|
||||
- If a query returns "Invalid Query Syntax", do not try variants: report the
|
||||
exact query and the error.
|
||||
|
||||
Same user or host elsewhere: search_investigation with actor_user_name or
|
||||
actor_asset_hostname. It takes start_time / end_time, not time_range; left
|
||||
empty it covers the last 28 days.
|
||||
In your answer, list the hosts and IPs the logs show for the user — that is
|
||||
what an analyst needs from a "new assets" alert — and say which log set and
|
||||
query produced them.
|
||||
|
||||
commands:
|
||||
- list_investigation_alerts
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -38,9 +38,37 @@ def run():
|
||||
if not all_results:
|
||||
limit = int(inp.get("limit") or 50)
|
||||
data = data[:limit]
|
||||
for a in data:
|
||||
_annotate(a)
|
||||
print(json.dumps({"rrn": inv_id, "alert": data}))
|
||||
|
||||
|
||||
def _annotate(a):
|
||||
"""Say, on each alert, whether the Alert Triage commands can read it.
|
||||
|
||||
An investigation's alert list mixes two kinds. A detection-rule alert carries
|
||||
an RRN (rrn:alerts:...) and answers get_alert_actors / get_alert_evidence. A
|
||||
behaviour (UBA) alert — "attempted to remotely access N new assets" — has a
|
||||
plain UUID and no RRN, and those commands answer 404 for it. An agent told so
|
||||
in its instructions still called them; told so in the data it is reading, it
|
||||
does not. The hint names where the evidence of such an alert lives instead.
|
||||
"""
|
||||
rrn = None
|
||||
for v in (a.get("rrn"), a.get("id")):
|
||||
if isinstance(v, str) and v.startswith("rrn:alerts:"):
|
||||
rrn = v
|
||||
break
|
||||
a["alert_rrn"] = rrn
|
||||
a["evidence_api"] = rrn is not None
|
||||
if rrn:
|
||||
a["next"] = "Call get_alert_actors and get_alert_evidence with alert_rrn."
|
||||
else:
|
||||
a["next"] = ("Behaviour (UBA) alert with no RRN: get_alert, get_alert_actors, get_alert_evidence and "
|
||||
"get_alert_process_trees answer 404 for it — do not call them. Its evidence is in the "
|
||||
"authentication logs: list_log_sets, then query_log_set on the Asset Authentication log set "
|
||||
"(or each Active Directory one) with where(\"<user>\") over the alert's window.")
|
||||
|
||||
|
||||
try:
|
||||
run()
|
||||
except urllib.error.HTTPError as e:
|
||||
|
||||
Reference in New Issue
Block a user