stacknil/LogLens
GitHub: stacknil/LogLens
LogLens 是一个 C++20 编写的防御性 CLI 工具,用于解析 Linux 身份验证日志并检测可疑登录活动,生成 Markdown 和 JSON 格式的确定性报告。
Stars: 0 | Forks: 0
# LogLens
[](./.github/workflows/ci.yml)
[](./.github/workflows/codeql.yml)
LogLens 是一个用于 Linux 身份验证日志的 C++20 防御性日志分析 CLI。
它解析 `auth.log` / `secure` 风格的 syslog 输入以及 `journalctl --output=short-full` 风格的输入,对身份验证证据进行标准化,应用可配置的基于规则的检测,并生成确定性的 Markdown 和 JSON 报告。
## 项目初衷
许多小型安全工具可以检测少量已知的日志模式。但很少有工具能让其解析限制可见。
LogLens 围绕三个理念设计:
- 检测工程优于攻击功能
- 解析器可观测性优于静默失败
- 仓库规范优于一次性脚本
该项目在报告可疑登录活动的同时,也展示解析器覆盖率、未知行分类、CI 状态和代码扫描健康状况。
## 范围
LogLens 是一个防御性的、公开安全的仓库。
它旨在用于日志解析、检测实验和工程实践。
它不提供漏洞利用、持久化、凭据攻击自动化或实时攻击能力。
LogLens 是一个防御性的 C++20 CLI,用于解析 Linux 身份验证日志,并为可疑的身份验证活动生成简洁的 Markdown 和 JSON 报告。该项目旨在展示达到作品集级别的检测工程工作,而非攻击性安全或攻击自动化。
这些徽章是此工作副本中的本地工作流标记,因为该仓库目前没有配置 GitHub 远程地址。发布仓库后,请将其替换为特定于仓库的 GitHub 状态徽章 URL。
## 仓库检查
LogLens 包含两个最小化的 GitHub Actions 工作流:
- `CI` 在 `ubuntu-latest` 和 `windows-latest` 上构建并测试项目
- `CodeQL` 在推送、Pull Request 和每周计划任务中对 C/C++ 运行 GitHub 代码扫描
这两个工作流旨在保持足够稳定,以便在针对 `main` 分支的 Pull Request 上要求通过。仓库加固说明位于 [`docs/repo-hardening.md`](./docs/repo-hardening.md)。
## 威胁模型
LogLens 专为离线审查从您拥有或管理的系统中收集的 `auth.log` 和 `secure` 风格文本日志而设计。MVP 专注于在凭据猜测、用户名枚举或突发特权命令使用期间经常出现的常见、高信号模式。
当前工具有助于回答:
- 是否有一个源 IP 在短时间内产生了重复的 SSH 失败?
- 是否有一个源 IP 在短时间内尝试了多个用户名?
- 是否有一个账户在短时间内异常频繁地运行 sudo?
它不试图替代 SIEM、跨主机关联、丰富 IP 信息或自行判定发现是否具有恶意。
## 检测能力
LogLens 目前检测:
- 同一 IP 在 10 分钟内重复的 SSH 密码失败尝试
- 同一 IP 在 15 分钟内尝试多个用户名
- 同一用户在 5 分钟内的突发 sudo 活动
LogLens 目前解析并报告这些额外的身份验证模式:
- `Failed publickey` SSH 失败,默认计入 SSH 暴力破解检测
- `pam_unix(...:auth): authentication failure`
- `pam_unix(...:session): session opened`
LogLens 还跟踪不支持或格式错误行的解析器覆盖率遥测数据,包括:
- `total_lines`
- `parsed_lines`
- `unparsed_lines`
- `parse_success_rate`
- `top_unknown_patterns`
LogLens 目前不检测:
- 横向移动
- MFA 滥用
- SSH 密钥滥用
- 超出已解析样本模式之外的特定 PAM 失败
- 跨文件或跨主机关联
## 构建
```
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
```
## 运行
```
./build/loglens --mode syslog --year 2026 ./assets/sample_auth.log ./out
./build/loglens --mode journalctl-short-full ./assets/sample_journalctl_short_full.log ./out-journal
./build/loglens --config ./assets/sample_config.json ./assets/sample_auth.log ./out-config
```
CLI 会写入:
- `report.md`
- `report.json`
到您提供的输出目录中。如果省略输出目录,文件将写入当前工作目录。
配置文件 schema 故意设计得小而严格:
```
{
"input_mode": "syslog_legacy",
"timestamp": {
"assume_year": 2026
},
"brute_force": { "threshold": 5, "window_minutes": 10 },
"multi_user_probing": { "threshold": 3, "window_minutes": 15 },
"sudo_burst": { "threshold": 3, "window_minutes": 5 },
"auth_signal_mappings": {
"ssh_failed_password": {
"counts_as_attempt_evidence": true,
"counts_as_terminal_auth_failure": true
},
"ssh_invalid_user": {
"counts_as_attempt_evidence": true,
"counts_as_terminal_auth_failure": true
},
"ssh_failed_publickey": {
"counts_as_attempt_evidence": true,
"counts_as_terminal_auth_failure": true
},
"pam_auth_failure": {
"counts_as_attempt_evidence": true,
"counts_as_terminal_auth_failure": false
}
}
}
```
此映射允许 LogLens 在应用暴力破解或多用户规则之前,将解析的事件标准化为检测信号。默认情况下,`pam_auth_failure` 被视为低置信度的尝试证据,除非配置明确提升其级别,否则不计入终端身份验证失败。
时间戳处理现在是显式的:
- `--mode syslog` 或 `input_mode: syslog_legacy` 需要 `--year` 或 `timestamp.assume_year`
- `--mode journalctl-short-full` 或 `input_mode: journalctl_short_full` 解析嵌入的年份和时区,并忽略 `assume_year`
## 示例输入
```
Mar 10 08:11:22 example-host sshd[1234]: Failed password for invalid user admin from 203.0.113.10 port 51022 ssh2
Mar 10 08:12:10 example-host sshd[1235]: Accepted password for alice from 203.0.113.20 port 51111 ssh2
Mar 10 08:15:00 example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart ssh
Mar 10 08:27:10 example-host sshd[1243]: Failed publickey for invalid user svc-backup from 203.0.113.40 port 51240 ssh2
Mar 10 08:28:33 example-host pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=203.0.113.41 user=alice
Mar 10 08:29:50 example-host pam_unix(sudo:session): session opened for user root by alice(uid=0)
Mar 10 08:30:12 example-host sshd[1244]: Connection closed by authenticating user alice 203.0.113.50 port 51290 [preauth]
Mar 10 08:31:18 example-host sshd[1245]: Timeout, client not responding from 203.0.113.51 port 51291
```
`journalctl --output short-full` 风格示例:
```
Tue 2026-03-10 08:11:22 UTC example-host sshd[2234]: Failed password for invalid user admin from 203.0.113.10 port 51022 ssh2
Tue 2026-03-10 08:13:10 UTC example-host sshd[2236]: Failed password for test from 203.0.113.10 port 51040 ssh
Tue 2026-03-10 08:18:05 UTC example-host sshd[2238]: Failed publickey for invalid user deploy from 203.0.113.10 port 51060 ssh2
Tue 2026-03-10 08:31:18 UTC example-host sshd[2245]: Connection closed by authenticating user alice 203.0.113.51 port 51291 [preauth]
```
## 示例输出
`report.md` 摘录:
```
# LogLens 报告
## 摘要
- Input mode: syslog_legacy
- Assume year: 2026
- Timezone present: false
- Total lines: 16
- Parsed lines: 14
- Unparsed lines: 2
- Parse success rate: 87.50%
- Parsed events: 14
- Findings: 3
- Parser warnings: 2
```
`report.json` 摘录:
```
{
"tool": "LogLens",
"input_mode": "syslog_legacy",
"assume_year": 2026,
"timezone_present": false,
"parser_quality": {
"total_lines": 16,
"parsed_lines": 14,
"unparsed_lines": 2,
"parse_success_rate": 0.8750
},
"parsed_event_count": 14,
"finding_count": 3
}
```
## 已知限制
- `syslog_legacy` 模式需要显式年份;LogLens 不再隐式猜测年份。
- `journalctl_short_full` 解析目前支持 `UTC`、`GMT`、`Z` 以及数字时区偏移量(如 `+0000` 或 `+00:00`),不支持任意的时区缩写。
- 解析器支持来自 `auth.log` 或 `secure` 的一小组常见 `sshd`、`sudo` 和 `pam_unix` 模式,而非所有发行版的特定变体。
- 不支持的行仅作为解析器遥测数据和警告显示;它们本身不会生成检测器发现。
- 默认情况下,`pam_unix` 身份验证失败仍为低置信度;仅当 `auth_signal_mappings` 明确提升它们时,它们才会影响检测器。
- 检测器阈值和身份验证信号映射仅能通过上述固定的 `config.json` schema 进行配置;不支持部分覆盖和替代配置格式。
- 发现结果有意设计为基于规则且保守;它们不是归因或事件判定。
## 未来路线图
- 更多身份验证模式和 PAM 覆盖范围
- 更好的主机级摘要
- 可选的 CSV 导出
- 更大的脱敏测试语料库
标签:Auth.log, Bash脚本, C++20, CodeQL, DevSecOps, GitHub Actions, Homebrew安装, Journalctl, JSON报告, Markdown报告, PE 加载器, Syslog, 上游代理, 仓库加固, 作品集项目, 公共安全, 可疑登录, 安全评估工具, 自动笔记, 解析器, 防御性安全