Add weekly attacker/campaign summary script
Parses fail2ban.log for the past 7 days into two append-only CSVs (per-IP and per-jail rollups) for longitudinal analysis, plus a human-readable summary emailed weekly. Two detection heuristics run on top of the raw data: distributed single-shot-per-IP scans across a /24 (shape of the apache-noscript campaign), and regular-timing evasion on repeat hits (shape of the sshd/dovecot low-and-slow campaigns) - both modeled on real campaigns found earlier this engagement. A live test run against real logs correctly re-identified the same dovecot campaign IPs found manually earlier, with matching interval timing. Runs weekly via cron, Sunday 06:00, clear of logrotate's daily timer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,38 @@ summary to `jens@jayfield.org` via the local mail stack (no external
|
|||||||
dependency). Exits non-zero if anything actually failed (warnings, like
|
dependency). Exits non-zero if anything actually failed (warnings, like
|
||||||
routine pending package upgrades, don't fail the run).
|
routine pending package upgrades, don't fail the run).
|
||||||
|
|
||||||
|
## Weekly attacker summary
|
||||||
|
|
||||||
|
`/usr/local/sbin/attacker-check.py` (added 2026-07-26) parses
|
||||||
|
`fail2ban.log` (current + recent rotations, gzipped or not — reads enough
|
||||||
|
history to cover a full week regardless of exactly when logrotate's daily
|
||||||
|
midnight run lands relative to the cron job) for the past 7 days and
|
||||||
|
turns it into two append-only CSVs for longitudinal analysis, plus a
|
||||||
|
human-readable weekly summary emailed to `jens@jayfield.org`:
|
||||||
|
|
||||||
|
- `/var/log/attacker-check/per_ip_weekly.csv` — one row per (jail, IP)
|
||||||
|
per week: event count, first/last seen, `/24` subnet, and interval
|
||||||
|
statistics (mean, stdev) between repeat hits.
|
||||||
|
- `/var/log/attacker-check/per_jail_weekly.csv` — weekly rollup per jail:
|
||||||
|
total events, distinct IPs, distinct `/24`s, new bans.
|
||||||
|
|
||||||
|
Two detection heuristics run on top of the raw data, both modeled
|
||||||
|
directly on real campaigns found earlier this engagement (see `TODO.md`):
|
||||||
|
- **Distributed single-shot scans**: flags any `/24` subnet with ≥5
|
||||||
|
distinct IPs averaging ≤3 events each against the same jail — the
|
||||||
|
shape of the `apache-noscript` campaign found 2026-07-19.
|
||||||
|
- **Regular-timing evasion**: flags any IP with ≥3 repeat hits on the
|
||||||
|
same jail whose inter-hit timing has a coefficient of variation under
|
||||||
|
15% — the shape of the `sshd`/`dovecot` low-and-slow campaigns found
|
||||||
|
and fixed 2026-07-19/2026-07-25 (attackers spacing requests just past
|
||||||
|
a jail's `findtime` window). A first live run against this week's real
|
||||||
|
logs correctly re-identified the same dovecot campaign IPs from that
|
||||||
|
earlier manual investigation, with matching ~22–28 minute intervals.
|
||||||
|
|
||||||
|
Runs weekly via `/etc/cron.d/attacker-check`, Sunday 06:00 (clear of
|
||||||
|
logrotate's daily midnight timer). Safe to also run manually at any
|
||||||
|
time: `sudo /usr/local/sbin/attacker-check.py`.
|
||||||
|
|
||||||
## System users
|
## System users
|
||||||
|
|
||||||
| User | uid | Home | Purpose |
|
| User | uid | Home | Purpose |
|
||||||
|
|||||||
Reference in New Issue
Block a user