fix(profiler): aggregate bash PROMPT_COMMAND lines into attacker profile
SSH/telnet decky containers emit shell commands via `logger -t bash "CMD …"`
which produces RFC 5424 lines with MSGID=NIL. Both parsers were leaving
event_type="-", so the behavioral profiler's `_COMMAND_EVENT_TYPES` filter
silently dropped them — the IP profile existed but no command transcripts
or artifacts. Confirmed in the wild: 44/48 events from one attacker were
event_type="-".
Rewrite event_type to "command" in both parsers when MSGID=NIL and the
msg starts with "CMD ". Correlation parser also extracts the cmd= payload
into fields["command"] so the profiler can build the transcript; collector
parser leaves fields={} to avoid duplicate pills in the dashboard.
This commit is contained in:
@@ -209,6 +209,23 @@ class TestParseRfc5424:
|
||||
assert result["fields"]["src_ip"] == "1.2.3.4"
|
||||
assert result["msg"] == "login attempt"
|
||||
|
||||
def test_bash_prompt_command_normalized_to_command(self):
|
||||
# SSH/telnet decky PROMPT_COMMAND emits free-form `logger -t bash
|
||||
# "CMD …"` with MSGID=NIL. Normalize so the profiler picks it up.
|
||||
# `fields` stays empty — the frontend renders kv pairs from msg.
|
||||
line = (
|
||||
'<14>1 2026-04-28T22:35:58.021674+00:00 dmz-gateway bash - - - '
|
||||
'CMD uid=0 user=root src=31.56.209.39 pwd=/root '
|
||||
'cmd=echo "rm -rf *.sh" | sh'
|
||||
)
|
||||
result = parse_rfc5424(line)
|
||||
assert result is not None
|
||||
assert result["event_type"] == "command"
|
||||
assert result["attacker_ip"] == "31.56.209.39"
|
||||
assert result["fields"] == {}
|
||||
# cmd payload survives in msg for the dashboard renderer.
|
||||
assert "cmd=echo" in result["msg"]
|
||||
|
||||
|
||||
class TestIsServiceContainer:
|
||||
def test_known_container_returns_true(self):
|
||||
|
||||
Reference in New Issue
Block a user