Skip to content

Commit 005c09e

Browse files
authored
Merge pull request #59 from stacknil/stacknil/loglens-rule-catalog
Add rule catalog documentation
2 parents c4c4e82 + 46b064a commit 005c09e

1 file changed

Lines changed: 197 additions & 0 deletions

File tree

docs/rule-catalog.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Rule Catalog
2+
3+
The rule catalog documents how LogLens turns normalized authentication events into triage findings. It is intended for reviewers who want to inspect rule logic without reading the C++ implementation first.
4+
5+
The rule catalog is Sigma-informed but not a Sigma-compatible export format.
6+
7+
Sigma's `detection`, `logsource`, and `metadata` framing is useful as a mental model: define what the rule looks for, name the evidence source, and keep rule boundaries explicit. LogLens keeps a narrower local format because its rules operate on normalized `Event` and `AuthSignal` objects, not on arbitrary backend query syntax.
8+
9+
## Catalog Scope
10+
11+
Logsource equivalent:
12+
13+
- Linux authentication evidence parsed by LogLens from `syslog_legacy` input, such as `auth.log` or `secure`
14+
- Linux authentication evidence parsed by LogLens from `journalctl_short_full` input, such as `journalctl --output=short-full`
15+
16+
Detection equivalent:
17+
18+
- Rule logic runs after parser normalization and signal mapping.
19+
- Unsupported parser warnings do not become rule input.
20+
- Parsed events only become rule input when the signal mapping marks them as relevant evidence for that rule family.
21+
22+
Metadata equivalent:
23+
24+
- Rule names are stable report values.
25+
- Windows and thresholds are configurable through `config.json`.
26+
- Default values below match the built-in detector configuration.
27+
28+
## Brute Force
29+
30+
### Rule name
31+
32+
`brute_force`
33+
34+
### Input event types
35+
36+
Default terminal SSH failure evidence:
37+
38+
- `ssh_failed_password`
39+
- `ssh_invalid_user`
40+
- `ssh_failed_publickey`
41+
- `ssh_failed_keyboard_interactive`
42+
- `ssh_max_auth_tries`
43+
44+
`pam_auth_failure` is not terminal SSH failure evidence by default. It can be configured differently through `auth_signal_mappings`, but the built-in default keeps it lower-confidence.
45+
46+
### Grouping key
47+
48+
`source_ip`
49+
50+
Signals without a source IP are not grouped for this rule.
51+
52+
### Window
53+
54+
10 minutes by default.
55+
56+
The detector uses a sliding timestamp window within each source-IP group.
57+
58+
### Threshold
59+
60+
5 terminal SSH failure signals by default.
61+
62+
### Output subject
63+
64+
`subject_kind`: `source_ip`
65+
66+
`subject`: the source IP that met the threshold
67+
68+
### False-positive boundary
69+
70+
This rule identifies concentrated failed SSH authentication evidence from one source IP. It does not decide whether the source is malicious, shared infrastructure, a vulnerability scanner, an internal test, a NAT gateway, or replayed lab traffic.
71+
72+
The finding is a triage signal. It is not a compromise verdict, attribution claim, or recommendation to block an address.
73+
74+
### Why unsupported evidence is not counted
75+
76+
Unsupported lines are parser warnings, not `AuthSignal` records. They may appear in `top_unknown_patterns`, but they do not carry the `counts_as_terminal_auth_failure` flag required by this rule.
77+
78+
This prevents unsupported preauth noise, malformed lines, and unmodeled auth-family messages from silently increasing brute-force counts.
79+
80+
## Multi-User Probing
81+
82+
### Rule name
83+
84+
`multi_user_probing`
85+
86+
### Input event types
87+
88+
Default attempt evidence:
89+
90+
- `ssh_failed_password`
91+
- `ssh_invalid_user`
92+
- `ssh_failed_publickey`
93+
- `ssh_failed_keyboard_interactive`
94+
- `ssh_max_auth_tries`
95+
- `pam_auth_failure`
96+
97+
The rule uses signal mapping, not raw event names directly. By default, `pam_auth_failure` counts as attempt evidence but not terminal SSH failure evidence.
98+
99+
### Grouping key
100+
101+
`source_ip`
102+
103+
Signals without a source IP are not grouped for this rule. Distinct username counting only uses signals that carry a non-empty username.
104+
105+
### Window
106+
107+
15 minutes by default.
108+
109+
The detector uses a sliding timestamp window within each source-IP group.
110+
111+
### Threshold
112+
113+
3 distinct usernames by default.
114+
115+
The reported event count is the number of attempt-evidence signals in the selected window. The rule fires when the distinct username count reaches the threshold.
116+
117+
### Output subject
118+
119+
`subject_kind`: `source_ip`
120+
121+
`subject`: the source IP that targeted multiple usernames
122+
123+
The finding also reports the username set observed in the selected window.
124+
125+
### False-positive boundary
126+
127+
This rule identifies username spread from one source IP. Username spread can be consistent with probing, but it can also appear in administrative testing, shared bastion traffic, noisy monitoring, or replayed sample data.
128+
129+
The rule does not infer intent. It only states that one source IP produced attempt evidence against multiple usernames inside the configured window.
130+
131+
### Why unsupported evidence is not counted
132+
133+
Unsupported records do not provide normalized usernames, source IPs, or attempt-evidence flags. Counting them would turn parser uncertainty into detector confidence.
134+
135+
Keeping them in parser warnings preserves evidence visibility without allowing unknown log patterns to inflate username-probing findings.
136+
137+
## Sudo Burst
138+
139+
### Rule name
140+
141+
`sudo_burst`
142+
143+
### Input event types
144+
145+
Default sudo burst evidence:
146+
147+
- `sudo_command`
148+
149+
Other sudo-adjacent or session events are not counted by default, including:
150+
151+
- `sudo_auth_failure`
152+
- `sudo_policy_denied`
153+
- `session_opened`
154+
155+
### Grouping key
156+
157+
`username`
158+
159+
Signals without a username are not grouped for this rule.
160+
161+
### Window
162+
163+
5 minutes by default.
164+
165+
The detector uses a sliding timestamp window within each username group.
166+
167+
### Threshold
168+
169+
3 sudo command signals by default.
170+
171+
### Output subject
172+
173+
`subject_kind`: `username`
174+
175+
`subject`: the user who met the sudo burst threshold
176+
177+
### False-positive boundary
178+
179+
This rule identifies concentrated sudo command activity by one user. It does not decide whether the activity is malicious, authorized maintenance, incident response, package management, service repair, or a scripted administrative task.
180+
181+
The finding is strongest when reviewed with session context, change windows, host ownership, and the command text preserved in the report.
182+
183+
### Why unsupported evidence is not counted
184+
185+
Unsupported sudo-like lines are parser warnings, not sudo burst signals. They do not carry `counts_as_sudo_burst_evidence`.
186+
187+
This prevents malformed or unmodeled privilege-related records from becoming silent evidence for privileged activity bursts.
188+
189+
## Rule Boundary Summary
190+
191+
| Rule | Default grouping key | Default window | Default threshold | Output subject |
192+
| --- | --- | ---: | ---: | --- |
193+
| `brute_force` | `source_ip` | 10 minutes | 5 terminal SSH failures | `source_ip` |
194+
| `multi_user_probing` | `source_ip` | 15 minutes | 3 distinct usernames | `source_ip` |
195+
| `sudo_burst` | `username` | 5 minutes | 3 sudo commands | `username` |
196+
197+
LogLens findings are deterministic rule outputs over normalized evidence. They are not incident verdicts. Parser coverage, warning buckets, and unsupported patterns remain visible so reviewers can see what the detector did not count.

0 commit comments

Comments
 (0)