tahovig/poc-logids

GitHub: tahovig/poc-logids

一个基于 Go 的迷你日志 IDS 命令行工具,通过解析 auth.log 检测 SSH 暴力破解尝试并支持实时监控告警。

Stars: 0 | Forks: 0

# poc-logids — 基于日志的异常检测工具 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/tahovig/poc-logids/actions/workflows/ci.yml) 一个用于解析日志数据并标记可疑模式的 Go CLI —— 一款用于日志分析的“迷你 IDS”。首个检测目标:auth.log 风格日志中的 SSH 暴力破解尝试(在特定时间窗口内,来自单一来源的重复身份验证失败尝试)。 这是一系列从软件工程转向网络安全工程的作品集中的第二个项目。第一个项目是:[poc-osint](https://github.com/tahovig/poc-osint),一款自动化的子域名侦察工具。 ## 状态 ``` $ poc-logids -file resources/loghub-linux/Linux.log SOURCE ATTEMPTS FIRST SEEN LAST SEEN USERS TRIED unknown.sagonet.net 23 Jun 11 09:45:45 Jun 11 09:46:48 root 218.188.2.4 11 Jun 12 01:12:13 Jun 12 01:12:27 test 218.38.14.205 13 Jun 12 14:10:40 Jun 12 14:10:54 ... (327 alerts total, spanning the full 263.9-day dataset) $ poc-logids -file auth.log -follow No brute-force activity detected. Watching auth.log for new activity (threshold=5, window=1m0s)... press Ctrl+C to stop [ALERT] Jul 17 22:41:05 source=203.0.113.7 attempts=5 users=root ``` 针对 [loghub](https://github.com/logpai/loghub) 完整的真实 Linux syslog 数据集(`resources/loghub-linux/`)运行 —— 跨越 263.9 天的真实生产数据,而非合成数据。该数据集确实跨越了日历年的边界,这就是为什么解析器会在 `Dec 31 -> Jan 1` 之间推断出一致的年份(见 `internal/parser`),而不是假设所有记录都发生在同一年。 ## 用法 ``` go build -o poc-logids ./cmd/poc-logids ./poc-logids -file [-json] [-threshold N] [-window 60s] [-follow] ``` - `-threshold`(默认为 5)—— 来自单一来源的最低失败尝试次数,达到该值即标记为暴力破解。 - `-window`(默认为 60s)—— 连续尝试之间允许的最大间隔,在此范围内才会被视为同一个爆发期。 - `-json` —— 输出 JSON 格式,而不是表格/单行格式。 - `-follow` —— 在初始扫描之后,持续监视文件并在检测到新警报时立即打印(按 Ctrl+C 停止)。与只有在爆发期完全结束后才报告的批量扫描不同,`-follow` 会在爆发期首次达到 `-threshold` 的瞬间立即发出警报,因为如果等到正在进行的攻击停止后才去报告,就违背了实时监控的意义。 ## 工作原理 有几个决策值得一提,因为它们源于真实的 bug/数据,而不是一开始就显而易见的: - **syslog 时间戳的年份推断。** 经典的 syslog 格式(`Jun 14 15:16:01 ...`)没有年份字段。解析器会按顺序处理日志行,并在某行的月份早于前一行的月份时,增加内部年份计数器 —— 这是一种标准的启发式方法,因为只有真正的 Dec→Jan 年份更迭才会触发它,而不是普通的乱序抖动。在确认完整的 loghub 数据集确实跨越了年份边界后,发现并修复了这个问题;验证了真实年份更迭期间的时间差计算结果是秒数,而不是错误的约 364 天跳跃。 - **`-follow` 中的日志轮转处理。** 处理了 logrotate 的两种常见策略:重命名+重建(不断重试打开该路径,直到新文件出现)和原位 `copytruncate` 截断。截断的情况曾存在一个真实的约 50% 概率触发的竞态条件 —— 截断后紧接着重写,可能会导致在下一次检查时文件大小并不小于上次读取的位置,因此单纯的大小比较会漏掉它。通过有界的尾部内容验证修复了该问题,而不是仅仅依赖大小。 - **实时警报在爆发期达到阈值的瞬间触发**,而不是在结束后。专门为此设计了一个独立的流式检测器(`internal/detector.Live`)—— 批量检测器的“等到爆发期完全结束”方法适用于分析静态文件,但对于实时监控毫无用处,因为在实时监控中,你希望在攻击正在发生时就能得知。 - **在关键之处使用真实数据而非合成数据。** 自动化测试使用合成夹具(确定性的,无实时依赖),但演示/验证数据使用的是 [loghub](https://github.com/logpai/loghub) 真实的生产 syslog 数据 —— 真实的攻击者行为,而非虚构的日志行。 ## 仓库结构 - `cmd/poc-logids/` —— CLI 入口点 - `internal/parser/` —— 从日志行中提取失败的 SSH 身份验证事件(syslog `pam_unix` 和现代 OpenSSH 格式),并在 Dec 31 -> Jan 1 边界之间推断一致的年份,因为 syslog 时间戳不携带年份 - `internal/detector/` —— 标记每个来源的暴力破解爆发期(批量模式,以及用于 `-follow` 的流式变体) - `internal/output/` —— JSON / ASCII 表格 / 单行渲染 - `internal/tail/` —— 用于 `-follow` 的基于 `fsnotify` 的文件追踪,处理日志轮转 - `resources/` —— 辅助/参考材料(非代码),包括真实世界的日志样本 ## 技术栈 Go。完整的架构设计和理由请参见 `CLAUDE.md`。
标签:EVTX分析, Go, Ruby工具, 动态分析, 异常检测, 文档结构分析, 日志审计