CS-Abuhelal/log-anomaly-detector
GitHub: CS-Abuhelal/log-anomaly-detector
一款基于透明统计学方法的轻量级日志异常检测工具,用于离线分析 Windows 和 Linux 系统日志中的可疑安全行为。
Stars: 0 | Forks: 0
# 日志异常检测器
一个适合初学者的 Python 工具,用于扫描 Windows 安全事件日志
和 Linux `auth.log` 文件以查找可疑模式,它使用简单的
统计方法(仅使用 `pandas` 和 `numpy` - 没有繁重的机器学习库)而不是
黑盒模型。每个发现都会获得一个 **0-100 的风险评分**,以便您
可以快速分拣出最重要的问题。
## 它能检测什么
| 检测项 | 查找目标 |
|---|---|
| **登录失败激增(暴力破解)** | 在一个较短的滑动时间窗口内,来自同一源 IP 的大量失败登录尝试 - 无论是猛攻单个账户还是“喷射”多个账户 |
| **非正常时段登录** | 在网络中统计上极其罕见的时段内发生的成功登录,通过对通常有活动的时段使用 z-score 进行计算 |
| **新建用户账户** | 呈现每一个新建账户,如果其是在非正常时段创建的,则会增加额外风险 |
| **权限提升** | 被添加到特权组(Administrators、sudo、wheel、Domain Admins 等)的账户 |
| **异常进程执行** | 已知攻击者工具/技术(Mimikatz、编码的 PowerShell、PsExec、反弹 shell 等)的监控列表,以及统计上罕见的单次执行进程 |
## 安装
要求 Python 3.8+。
```
git clone https://github.com/CS-Abuhelal/log-anomaly-detector.git
cd log-anomaly-detector
pip install -r requirements.txt
```
唯一的依赖项是 `pandas` 和 `numpy` - 这是刻意为之,
它*不是*一个机器学习工具。下面所有的检测逻辑都是纯粹的
计数、滑动时间窗口和 z-score,这使得它快速、
透明且易于推理(您始终可以解释*为什么*
某些内容会被标记)。
## 快速开始
`sample_logs/` 中包含了十个示例日志文件,以便您可以立即
试用该工具:
```
python analyzer.py sample_logs/mixed_windows.csv sample_logs/mixed_linux.log
```
您可以在一次运行中传入任意混合的 Windows CSV 导出文件和 Linux auth.log 文件 -
它们会被解析为一个统一的组合时间线并进行
共同分析。要将报告保存到文件:
```
python analyzer.py sample_logs/mixed_windows.csv sample_logs/mixed_linux.log --output report.txt
```
### 示例输出
```
======================================================================
LOG ANOMALY DETECTOR - SUMMARY REPORT
======================================================================
Files analyzed : sample_logs/mixed_windows.csv, sample_logs/mixed_linux.log
Events parsed : 65
Total findings : 6
Findings by severity:
CRITICAL : 3
HIGH : 2
MEDIUM : 1
======================================================================
--- CRITICAL ----------------------------------------------------------
[Risk 97/100 - CRITICAL] Suspicious Process Execution: 'mimikatz.exe' run by
backup_svc2 matches a known attack pattern: Known credential-dumping tool.
[Risk 90/100 - CRITICAL] Privilege Escalation: Account 'backup_svc2' was added
to a highly privileged group (Group: Administrators).
[Risk 90/100 - CRITICAL] Suspicious Process Execution: '/bin/nc' run by diego
matches a known attack pattern: Netcat used to spawn a reverse shell.
--- HIGH --------------------------------------------------------------
[Risk 74/100 - HIGH] Unusual Login Hour: diego logged in at 04:00, an hour
when logins are statistically rare on this network (z-score -2.24).
[Risk 70/100 - HIGH] New Account Created: New account 'backup_svc2' was
created by svc_admin during an unusual hour.
--- MEDIUM ------------------------------------------------------------
[Risk 63/100 - MEDIUM] Brute Force: 203.0.113.40 made 6 failed login
attempts within 5 minutes (targeting 6 distinct account(s)).
```
## 输入日志格式
### Windows (`.csv`)
支持并会自动检测两种 Windows CSV 格式:
**1. 事件查看器的 GUI 导出**(“Save All Events As...” / “Save
Filtered Log File As...”) - 只需导出您的安全日志并让该工具
直接指向该文件即可,无需手动重新格式化。此格式
有一个众所周知的怪癖:它的标题只命名了 5 列
(`Keywords, Date and Time, Source, Event ID, Task Category`),但每
行实际上有 6 个字段 - 事件描述没有列名。
天真地读取它(例如在 Excel/pandas 中使用默认设置打开)
会悄悄地使每一列都向右错位一位。此工具会检测到该标题
并正确读取它,然后直接从 Windows 始终
写入描述中的结构化 `Field Name: value` 文本中提取所需的
账户/IP/进程详细信息。
**2. 一个简化的、有文档说明的 schema** - 如果您正在手动构建 CSV,
使用 `Get-WinEvent`,或用于测试,这会非常有用:
```
TimeCreated,EventID,Account,SourceIP,TargetAccount,ProcessName,CommandLine,Message
```
两种格式都能理解的事件 ID:
| Event ID | 含义 | 映射为 |
|---|---|---|
| 4624 | 账户成功登录 | `logon_success` |
| 4625 | 账户登录失败 | `logon_failed` |
| 4720 | 创建了用户账户 | `account_created` |
| 4732 | 将成员添加到启用安全性的组中 | `privilege_change` |
| 4688 | 创建了新进程 | `process_execution` |
其他所有内容都会被解析但会被忽略 - 只有这五种事件类型会提供给
检测器。
### Linux(任何非 `.csv` 格式)
标准 syslog 风格的 `/var/log/auth.log` 行,例如:
```
Jun 18 03:14:12 host sshd[1234]: Failed password for invalid user admin from 203.0.113.5 port 51234 ssh2
Jun 18 03:14:15 host sshd[1234]: Accepted password for ahmed from 192.168.1.50 port 51240 ssh2
Jun 18 09:00:01 host useradd[2345]: new user: name=backdoor, UID=1001
Jun 18 09:00:05 host usermod[2345]: add 'backdoor' to group 'sudo'
Jun 18 09:05:00 host sudo: ahmed : TTY=pts/0 ; PWD=/home/ahmed ; USER=root ; COMMAND=/usr/bin/whoami
```
两种格式都会被规范化为一个内部表格(参见
`loganomaly/parsers.py`),因此无论数据来自何处,每个检测器
都以相同的方式工作。
## 示例日志文件
| 文件 | 演示内容 |
|---|---|
| `windows_normal.csv` / `linux_auth_normal.log` | 干净的基线 - 仅包含工作时间内的登录。根据设计,产生 **零** 发现。 |
| `windows_bruteforce.csv` / `linux_auth_bruteforce.log` | 来自一个 IP 的失败登录激增,速度快到足以越过暴力破解阈值 |
| `windows_unusual_hours.csv` | 扎实的白天基线加上两次在统计上显得突出的非工作时间登录 |
| `windows_new_account.csv` | 在凌晨 2:30 创建的新账户 |
| `windows_privilege_escalation.csv` | 添加到 Administrators 组的账户 |
| `windows_suspicious_process.csv` | 一个正常的、经常运行的进程(被忽略)旁边是一个编码的 PowerShell 命令和一个罕见的单次运行工具(均被标记) |
| `mixed_windows.csv` + `mixed_linux.log` | 一次同时涉及所有五个检测类别的综合事件场景 - 即上面的示例 |
随时使用以下命令重新生成其中任何一个:
```
python sample_logs/generate_samples.py
```
这些文件中的每个账户名、IP 地址和命令行都是
合成的 - 不涉及任何真实的主机、用户或凭据。
外部 IP 使用 `203.0.113.0/24` 范围,[RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)
专门为文档/示例保留了该范围,并且它在
真实的互联网上是不可路由的。
## 真实世界测试
除了合成示例外,此工具还针对真实的 Windows
11 机器的安全事件日志运行过,该日志是使用事件查看器的“Save All
Events As...”(GUI 导出格式 - 请参见上面的[输入日志格式](#input-log-formats)
)导出的:
```
Events parsed : 1512
Total findings : 0
```
这里干净的结果不仅仅是“没有东西可以打印” - 每个
检测器实际上都对真实数据运行了检查,并且有
具体的依据来否定发现:
- **异常登录时间**:成功的登录分布在 24 小时中的
21 个小时里(这台机器全天候运行计划任务和后台登录),因此
对于 z-score 检查来说,没有任何统计上罕见的小时可以标记 - 这
与典型的朝九晚五工作站的结果有着本质上的不同,检测器
正确地反映了这一点。
- **暴力破解**:整个日志中只出现了 2 次失败登录,
远未达到默认的“5 分钟内失败 5 次”阈值。
- **新建账户**:零次 `4720` 事件 - 在捕获期间没有创建
任何新账户。
- **权限提升**:零次 `4732` 事件 - 没有
组成员身份的更改。
- **可疑进程执行**:26 个进程创建事件,全部
是普通的 Windows 启动/系统进程(`smss.exe`、`csrss.exe`、
`lsass.exe`、`services.exe` 等),它们既不在攻击者
监控列表中,在统计上也不罕见。
这次运行还在 Event Viewer CSV 读取器中发现了一个真实的解析错误:
一个 `New Process Name` 字段为空的进程创建事件,
导致*下一行*的文本渗入其中,原因是正则表达式使用了 `\s*`
(匹配换行符)而不是字段冒号后面的
`[ \t]*`。此问题已修复,并在
`tests/test_parsers.py` 中通过回归测试进行了锁定。
## 调整检测阈值
```
python analyzer.py mylog.csv \
--window-minutes 10 \
--count-threshold 8 \
--hour-z-threshold -2.0
```
| 标志 | 默认值 | 含义 |
|---|---|---|
| `--window-minutes` | 5 | 用于暴力破解突发检测的滑动窗口大小 |
| `--count-threshold` | 5 | 窗口内被视为突发的失败登录次数 |
| `--hour-z-threshold` | -1.5 | 登录时间被视为统计上罕见的 z-score 阈值(负值越大 = 越严格) |
| `--output` | *(无)* | 同时将报告保存到此文件 |
## 各个检测器的工作原理(供好奇者参考)
- **暴力破解** (`detect_brute_force`):对于每个源 IP,按时间对其
失败登录进行排序,并使用 `numpy.searchsorted` 来为每次
尝试找出,该 IP 在前 N 分钟内发生了多少次
其他尝试。如果该计数超过阈值,则为
突发。如果攻击者尝试了 3 个或更多不同的账户
名(密码喷射,而不仅仅是猜测单个账户),则会增加奖励分数。
- **异常时间** (`detect_unusual_hours`):构建一个 24 格的直方图,显示
成功登录通常发生在哪个小时,但是 - 重要的是
- 仅在实际
有活动的小时上计算平均值/标准差(否则,十几个以上始终为空的夜间时段
会使数学计算严重倾斜,以至于任何登录看起来都像是
“激增”而不是异常值)。如果某个登录发生时间的小时
z-score 低于阈值,则该登录将被标记。
- **新建账户** (`detect_new_accounts`):标记每个账户
创建事件,如果它发生在统计
上罕见的小时(使用与上述相同的计算),则会增加风险。
- **权限提升** (`detect_privilege_escalation`):标记组
成员身份更改,当目标组名
与高价值模式(Administrators、sudo、wheel、Domain
Admins 等)匹配时,得分会更高。
- **异常进程** (`detect_unusual_processes`):检查每个
执行的进程/命令是否与已知攻击者
技术(Mimikatz、编码的 PowerShell、PsExec、certutil/regsvr32/
bitsadmin LOLBins、通过 netcat 的反弹 shell 等)的监控列表匹配。任何不在
监控列表上的内容,如果在统计上很罕见,即在整个
日志中只出现一次或两次,仍然会被标记。
## 运行测试
```
python tests/test_detectors.py -v
# 或者,如果你已经安装了 pytest:
python -m pytest tests/ -v
```
## 局限性
这是一个教育项目,而不是生产级的 SIEM 关联规则
集:
- 所有分析都是**离线**的,针对静态日志文件 - 没有实时跟踪或
实时警报。
- 统计基线(小时罕见性、进程罕见性)需要
合理的数据量才能有意义;微小的日志文件无法提供
可靠的 z-score。
- Windows CSV schema 是为清晰起见而选择的简化、有文档说明的格式 - 真实世界的
`Get-WinEvent` 导出将需要映射其列以
与之匹配(或者扩展 `parsers.py` 以直接读取它们)。
- 进程监控列表是说明性的,并非详尽无遗 - 它不会
捕获每个攻击者工具,特别是自定义/重命名的二进制文件。
## License
MIT
标签:AMSI绕过, Python, 威胁检测, 安全, 异常检测, 无后门, 红队行动, 超时处理, 逆向工具