loghunter-cli 0.1.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- loghunter/__init__.py +3 -0
- loghunter/cli.py +1108 -0
- loghunter/cli_init.py +567 -0
- loghunter/common/__init__.py +1 -0
- loghunter/common/allowlist.py +436 -0
- loghunter/common/clustering.py +326 -0
- loghunter/common/config.py +221 -0
- loghunter/common/display.py +323 -0
- loghunter/common/errors.py +45 -0
- loghunter/common/finding.py +239 -0
- loghunter/common/loader/__init__.py +136 -0
- loghunter/common/loader/diagnostics.py +94 -0
- loghunter/common/loader/discovery.py +335 -0
- loghunter/common/loader/io.py +76 -0
- loghunter/common/loader/pipeline.py +1010 -0
- loghunter/common/loader/sniff.py +184 -0
- loghunter/common/loader/types.py +207 -0
- loghunter/common/loader/windowing.py +523 -0
- loghunter/common/output.py +93 -0
- loghunter/common/paths.py +105 -0
- loghunter/common/sources.py +392 -0
- loghunter/data/allowlist/connections.txt +50 -0
- loghunter/data/allowlist/domains_devices.txt +5 -0
- loghunter/data/allowlist/domains_homelab.txt +5 -0
- loghunter/data/allowlist/domains_universal.txt +125 -0
- loghunter/data/config_example.toml +144 -0
- loghunter/detectors/__init__.py +5 -0
- loghunter/detectors/auth.py +27 -0
- loghunter/detectors/aws.py +671 -0
- loghunter/detectors/beacon.py +258 -0
- loghunter/detectors/dns.py +778 -0
- loghunter/detectors/dnsblock.py +29 -0
- loghunter/detectors/duration.py +178 -0
- loghunter/detectors/protocol.py +26 -0
- loghunter/detectors/scan.py +735 -0
- loghunter/detectors/ssl.py +25 -0
- loghunter/detectors/syslog.py +266 -0
- loghunter/detectors/weird.py +27 -0
- loghunter/digest/__init__.py +43 -0
- loghunter/digest/_stats.py +182 -0
- loghunter/digest/blob.py +698 -0
- loghunter/digest/cloudtrail.py +341 -0
- loghunter/digest/conn.py +367 -0
- loghunter/digest/dns.py +364 -0
- loghunter/digest/syslog.py +269 -0
- loghunter/exporters/__init__.py +534 -0
- loghunter/exporters/cloudtrail.py +499 -0
- loghunter/exporters/splunk.py +222 -0
- loghunter/outputs/__init__.py +1 -0
- loghunter/outputs/allowlist.py +75 -0
- loghunter/outputs/csv.py +70 -0
- loghunter/outputs/email.py +44 -0
- loghunter/outputs/html.py +99 -0
- loghunter/outputs/json.py +77 -0
- loghunter/outputs/text.py +1422 -0
- loghunter/parsers/__init__.py +1 -0
- loghunter/parsers/cloudtrail.py +287 -0
- loghunter/parsers/dnsmasq.py +331 -0
- loghunter/parsers/syslog.py +150 -0
- loghunter/parsers/zeek.py +294 -0
- loghunter/parsers/zeek_tsv.py +310 -0
- loghunter/runner.py +1895 -0
- loghunter_cli-0.1.0.dev0.dist-info/METADATA +336 -0
- loghunter_cli-0.1.0.dev0.dist-info/RECORD +122 -0
- loghunter_cli-0.1.0.dev0.dist-info/WHEEL +5 -0
- loghunter_cli-0.1.0.dev0.dist-info/entry_points.txt +2 -0
- loghunter_cli-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
- loghunter_cli-0.1.0.dev0.dist-info/top_level.txt +4 -0
- migrations/cloudtrail_parquet.py +59 -0
- migrations/conn_fft.py +550 -0
- migrations/conn_scan.py +1097 -0
- migrations/dns_dbscan.py +520 -0
- migrations/get_syslog.py +402 -0
- migrations/syslog_drain3.py +479 -0
- scratch/junk/parquet.py +59 -0
- tests/__init__.py +1 -0
- tests/_cloudtrail_fakes.py +116 -0
- tests/conftest.py +17 -0
- tests/test_allowlist_defaults_accessor.py +90 -0
- tests/test_architecture_spine.py +302 -0
- tests/test_aws_detector.py +504 -0
- tests/test_be_like_water.py +106 -0
- tests/test_cli_help.py +342 -0
- tests/test_cli_multi_positional.py +458 -0
- tests/test_cloudtrail_exporter.py +631 -0
- tests/test_cloudtrail_exporter_botocore.py +207 -0
- tests/test_cloudtrail_parser.py +393 -0
- tests/test_clustering.py +85 -0
- tests/test_clustering_interruptible.py +404 -0
- tests/test_config_cli.py +1006 -0
- tests/test_config_example_drift.py +164 -0
- tests/test_digest_blob.py +1237 -0
- tests/test_digest_cli.py +1040 -0
- tests/test_digest_cloudtrail.py +980 -0
- tests/test_digest_conn.py +1189 -0
- tests/test_digest_dns.py +770 -0
- tests/test_digest_stats.py +282 -0
- tests/test_digest_syslog.py +724 -0
- tests/test_display.py +370 -0
- tests/test_dns_detector.py +1010 -0
- tests/test_dnsmasq_parser.py +467 -0
- tests/test_duration_detector.py +491 -0
- tests/test_export_orchestrator_shape.py +153 -0
- tests/test_init_wizard.py +707 -0
- tests/test_loader.py +3639 -0
- tests/test_loader_package_surface.py +115 -0
- tests/test_loader_window_model.py +215 -0
- tests/test_output_path_cascade.py +575 -0
- tests/test_resolve_path.py +111 -0
- tests/test_root_provenance.py +212 -0
- tests/test_runner.py +2599 -0
- tests/test_scan_detector.py +455 -0
- tests/test_search_paths.py +50 -0
- tests/test_sniff_orchestrator.py +373 -0
- tests/test_sniff_recognizers.py +573 -0
- tests/test_source_resolution_seam.py +471 -0
- tests/test_sources.py +648 -0
- tests/test_splunk_exporter.py +351 -0
- tests/test_syslog_detector.py +458 -0
- tests/test_syslog_parser.py +582 -0
- tests/test_text_output.py +1225 -0
- tests/test_zeek_tsv_parser.py +580 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# LogHunter configuration. Every key is optional — omit any to take the default.
|
|
2
|
+
# Generate this for your environment with `loghunter init`.
|
|
3
|
+
|
|
4
|
+
[loghunter]
|
|
5
|
+
|
|
6
|
+
# Base dir for any RELATIVE path below. "" resolves relative paths from the
|
|
7
|
+
# current dir. Absolute (/…) and ~-anchored paths ignore it. Set it once and
|
|
8
|
+
# write export_dir = "exports". Env override: LOGHUNTER_ROOT.
|
|
9
|
+
root = "~/.loghunter"
|
|
10
|
+
|
|
11
|
+
# Detectors to run: "all" | "dns, beacon" | "all, !syslog". --detect overrides.
|
|
12
|
+
detect = "all"
|
|
13
|
+
|
|
14
|
+
# ── Log sources (read) ──────────────────────────────────────────────
|
|
15
|
+
# Directories holding your logs. Conventional locations shown; uncomment the
|
|
16
|
+
# others if you have them.
|
|
17
|
+
zeek_dir = "/var/log/zeek"
|
|
18
|
+
syslog_dir = "/var/log"
|
|
19
|
+
# pihole_dir = "/var/log/pihole"
|
|
20
|
+
# cloudtrail_dir = "/var/log/cloudtrail"
|
|
21
|
+
|
|
22
|
+
# ── Network ─────────────────────────────────────────────────────────
|
|
23
|
+
# Networks treated as internal for traffic-direction. Topology, not tuning.
|
|
24
|
+
home_net = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
|
25
|
+
|
|
26
|
+
# ── Output (write) ──────────────────────────────────────────────────
|
|
27
|
+
# Findings print to your terminal. Set report_dir (or pass --out) to write
|
|
28
|
+
# files instead — reports land in their own dir, never mixed with pulled logs.
|
|
29
|
+
# report_dir = "reports/"
|
|
30
|
+
# export_dir is a directory BASE: each export auto-segments per source into
|
|
31
|
+
# <base>/<source>/ (e.g. exports/syslog/, exports/cloudtrail/) so pulled logs
|
|
32
|
+
# of different families never share a directory. Override per backend or per
|
|
33
|
+
# query (below) to pin a literal dir; --out is always literal.
|
|
34
|
+
export_dir = "exports/"
|
|
35
|
+
output_format = "text"
|
|
36
|
+
|
|
37
|
+
# ── Analysis window ─────────────────────────────────────────────────
|
|
38
|
+
# default_window: lookback for a directory with no --since/--days ("1d","7d",
|
|
39
|
+
# "24h"; "" or "all" = whole archive; --all overrides one run).
|
|
40
|
+
# warn_above: prompt before analyzing more than this many records.
|
|
41
|
+
default_window = "1d"
|
|
42
|
+
warn_above = 5_000_000
|
|
43
|
+
|
|
44
|
+
# Per-detector total cap on rendered TEXT findings (json/csv/html ignore it —
|
|
45
|
+
# machine formats never truncate). Cap operates post severity-sort; a disclosure
|
|
46
|
+
# line is shown when it trips. 0 = unlimited.
|
|
47
|
+
max_findings_per_detector = 100
|
|
48
|
+
|
|
49
|
+
[allowlist]
|
|
50
|
+
|
|
51
|
+
# Shipped domain lists load automatically; add your own (one glob per line).
|
|
52
|
+
# connection_rules: local-only flow suppressions — start blank, add after review.
|
|
53
|
+
# allowlist_dir: TOML classification stanzas (all *.toml loaded).
|
|
54
|
+
domain_patterns = ["~/.loghunter/allowlist.d/domains_user.txt"]
|
|
55
|
+
connection_rules = ["~/.loghunter/allowlist.d/connections.txt"]
|
|
56
|
+
allowlist_dir = "~/.loghunter/allowlist.d/"
|
|
57
|
+
|
|
58
|
+
# ════════════════════════════════════════════════════════════════════
|
|
59
|
+
# Export backends (configure only what you use)
|
|
60
|
+
# ════════════════════════════════════════════════════════════════════
|
|
61
|
+
# Splunk — a non-empty host activates it. Prefer env LOGHUNTER_SPLUNK_USER /
|
|
62
|
+
# _PASS over plaintext credentials. A query named "default" runs with a bare
|
|
63
|
+
# `loghunter export`; run others by name (`loghunter export auth`).
|
|
64
|
+
#
|
|
65
|
+
# [export.splunk]
|
|
66
|
+
# host = "192.0.2.20"
|
|
67
|
+
# port = 8089
|
|
68
|
+
# Per-backend export_dir: a LITERAL final dir for every query on this backend
|
|
69
|
+
# (no per-source auto-segment). Uncomment to override the global base.
|
|
70
|
+
# export_dir = "/srv/exports/splunk/"
|
|
71
|
+
#
|
|
72
|
+
# [export.splunk.query.default]
|
|
73
|
+
# spl = "search index=main sourcetype=syslog | table _time, host, _raw"
|
|
74
|
+
# output_basename = "syslog"
|
|
75
|
+
# Per-query export_dir: the finest grain, a LITERAL final dir for this query
|
|
76
|
+
# only (no auto-segment). Wins over the per-backend and global tiers.
|
|
77
|
+
# export_dir = "/srv/exports/syslog/"
|
|
78
|
+
#
|
|
79
|
+
# [export.splunk.query.auth]
|
|
80
|
+
# spl = "search index=main sourcetype=linux_secure | table _time, host, _raw"
|
|
81
|
+
# output_basename = "auth"
|
|
82
|
+
#
|
|
83
|
+
# CloudTrail — a non-empty path activates it. AWS auth is NOT here; authenticate
|
|
84
|
+
# your shell and boto3 resolves it.
|
|
85
|
+
#
|
|
86
|
+
# [export.cloudtrail]
|
|
87
|
+
# path = "s3://example-bucket/AWSLogs/"
|
|
88
|
+
# egress_warn_gb = 5.0
|
|
89
|
+
# export_dir = "/srv/exports/cloudtrail/" # literal dir override (no auto-segment)
|
|
90
|
+
|
|
91
|
+
# ════════════════════════════════════════════════════════════════════
|
|
92
|
+
# Detector tuning — the engine room. You rarely need any of this; every
|
|
93
|
+
# detector ships sensible defaults. The values shown ARE those defaults —
|
|
94
|
+
# uncomment a line and change it to tune. Full surface per detector:
|
|
95
|
+
# `loghunter <detector> --help`.
|
|
96
|
+
# ════════════════════════════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
# beacon — periodic C2-style callbacks (FFT over connection timing).
|
|
99
|
+
# [detectors.beacon]
|
|
100
|
+
# threshold = 0.5 # min composite score to report (0–1)
|
|
101
|
+
# min_connections = 20 # min connections for a flow to qualify
|
|
102
|
+
# bin_seconds = 30 # FFT bin; leave at 30 — 10 aliases a 60s beacon
|
|
103
|
+
|
|
104
|
+
# scan — vertical / horizontal / block / slow port scans.
|
|
105
|
+
# [detectors.scan]
|
|
106
|
+
# vertical_threshold = 15 # distinct ports on one target → vertical
|
|
107
|
+
# horizontal_threshold = 15 # distinct hosts on one port → horizontal
|
|
108
|
+
# block_port_threshold = 20 # ports AND…
|
|
109
|
+
# block_host_threshold = 20 # …hosts, both met → block scan
|
|
110
|
+
# block_state_min = 0.30 # min scan-state ratio for block/slow gates
|
|
111
|
+
# slow_state_min = 0.30
|
|
112
|
+
# window_secs = 3600 # detection window for vert/horiz/block
|
|
113
|
+
# slow_min_ports = 8 # slow scan: min ports across the dataset…
|
|
114
|
+
# slow_min_buckets = 4 # …over this many active time windows
|
|
115
|
+
|
|
116
|
+
# duration — abnormally long-lived connections.
|
|
117
|
+
# [detectors.duration]
|
|
118
|
+
# min_duration_seconds = 1800 # 30m floor to flag (LOW; verbose-only)
|
|
119
|
+
|
|
120
|
+
# dns — DNS clustering (HDBSCAN over per-query behavior).
|
|
121
|
+
# [detectors.dns]
|
|
122
|
+
# min_cluster_size = 2000
|
|
123
|
+
# min_samples = 100
|
|
124
|
+
# threshold = 1.5 # keep ≤ thresh_high_entropy
|
|
125
|
+
# thresh_high_entropy = 1.8 # the operative filter — raise to quiet noise
|
|
126
|
+
# [detectors.dns.pihole] # Pi-hole path clusters aggregated per-domain
|
|
127
|
+
# min_cluster_size = 25 # rows, so its sizes run much smaller
|
|
128
|
+
# min_samples = 10
|
|
129
|
+
|
|
130
|
+
# syslog — rare-event / reboot surfacing (drain3 templating + rarity).
|
|
131
|
+
# [detectors.syslog]
|
|
132
|
+
# lookback_days = 7 # default window when no --since/--days
|
|
133
|
+
# rarity_pct = 10 # bottom-N percentile of template count = rare
|
|
134
|
+
# max_count = 1 # templates seen ≤ this many times always flag
|
|
135
|
+
|
|
136
|
+
# aws — per-principal CloudTrail surfacing (rarity + weirdness + bursts).
|
|
137
|
+
# [detectors.aws]
|
|
138
|
+
# min_events = 50 # interactive principals below this are set aside
|
|
139
|
+
# burst_gap_seconds = 300 # first-seen actions closer than this = one burst
|
|
140
|
+
# burst_min_firsts = 3 # min first-seen actions to form a burst
|
|
141
|
+
# burst_high_error_rate = 0.5 # burst → HIGH escalation gate
|
|
142
|
+
# burst_high_service_count = 3 # burst → HIGH escalation gate
|
|
143
|
+
# composite_medium_threshold = 2.0 # ranked-principal severity bands (absolute
|
|
144
|
+
# composite_low_threshold = 1.0 # z, never rank position)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Auth detector — authentication pattern analysis from syslog. (planned)
|
|
2
|
+
|
|
3
|
+
Analyzes auth.log and secure log files for brute-force attempts, unusual
|
|
4
|
+
authentication patterns, privilege escalation, and new account activity.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from loghunter.common.finding import DetectorContext, Finding
|
|
10
|
+
|
|
11
|
+
DETECTOR_NAME = "auth"
|
|
12
|
+
STATUS = "planned"
|
|
13
|
+
|
|
14
|
+
REQUIRED_LOGS = [
|
|
15
|
+
{"source": "syslog_dir", "pattern": "auth.log*"},
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
OPTIONAL_LOGS = [
|
|
19
|
+
{"source": "syslog_dir", "pattern": "secure*"},
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
DEFAULT_CONFIG: dict = {}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run(context: DetectorContext) -> list[Finding]:
|
|
26
|
+
"""Detect anomalous authentication patterns in syslog auth files."""
|
|
27
|
+
raise NotImplementedError("auth detector is planned — not yet implemented")
|