文章总结: 本文介绍作者自研的服务器离线取证工具,基于纯Python实现,支持Linux/Windows镜像分析,含31个采集器、文件浏览、哈希计算、数据查看、网站解构、疑似密码提取等功能。实测在真实Linux镜像上成功定位后门文件,并验证证据链完整性。文章还分享了开发中修复的真实缺陷,对取证工具开发具有参考价值。
综合评分: 82
文章分类: 安全工具,应急响应,安全开发
尝试自己做一个全功能的服务器离线取证工具
CC14
CC14
蝶影流觞
2026年9月22日 22:07
山东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
可能是显示的问题,有些表格在手机上看不完整,反正也没有什么营养就凑活看吧,要是想看完整的可以用电脑。。。
第一次写实用的程序,虽然大部分都是ai的功劳但是也确实发现了很多问题,要学的还有很多
1. 任务由来
笔者发现,服务器在取证的时候比较麻烦,需要仿真后连接各种东西,而且需要复杂的指令(当然ai一把梭的话当我没说),对小白十分不友好(而且线下不让用ai),遂想做一个全自动的服务器取证工具,不需要直接出答案,只需要展开整个服务器的结构,使之一目了然即可。同时,考虑到题目的多变性,这个工具也需要不断完善,以应对百变马丁般的服务器题目
第一版十分简单,就是想做一个能看检材的工具(以下是ai修的四轮)
1. 第一轮:做一个服务取证工作者用的软件,不联网也能用,主要用于服务器取证;本地 Web 界面、纯 Python 后端;取证对象覆盖 Windows Server / Linux 服务器 / 数据库;优先在线响应式的现场取证。并给了一台真实 Linux Web 服务器的 6.8 GB 整盘镜像作为样本,要求”能看到这个服务器的全部信息,要有条理、一目了然”。
2. 第二轮:补齐线索——用户组成员关系、分区/卷 UUID 与文件预览、网卡与服务器管理系统识别、接入设备、软件使用日志清点、应用清单;右键即可计算哈希值;管理后台登录入口;数据库查看/筛选/处理;文档/日志/数据库中的疑似密码提取与验证并归纳到”疑似密码”栏;网站解构工具;加密区域可自动破解或等用户输密码,且不能影响其他进程。
3. 第三轮:把上述能力全部接入本地 Web 界面与离线报告。
4. 第四轮(收尾):口令不需要加密或混淆,直接明文即可;校验完整性,保证运行后能直接分析服务器文件;再写一个可视化的一键运行程序,把镜像拖进去就分析并自动打开界面。
2. 交付物
2.1 压缩包
略
2.2 两个一键入口
| | |
| — | — |
| 文件 | 说明 |
| 一键取证.bat | 双击运行。会先做环境自检(找 Python、import sfk),失败时留在控制台显示真实报错,不会一闪而过 |
| sfk_launcher.pyw | 双击启动,不带黑窗口。需要系统已把 .pyw 关联到 Python——这台机器上没设,所以两个入口都提供了 |
AI说的这些我也是一知半解,反正在我电脑上能跑就行,之后分享给队友的时候需要修修依赖之类的东西。
3. 快速开始
双击一键取证.bat
→ 打开窗口,把镜像(E01 / dd / raw / img)拖进拖放区
→ 自动分析 → 自动启动本地界面并在浏览器里打开
这个第一版能解析的镜像十分有限,只能打开如下文件
窗口里能看到分析过程的实时输出、进度条与逐条状态;完成后可一键打开界面 / 案件目录 / 离线报告。
命令行等价形式:
python -m sfk info image.E01 # 体检镜像
python -m sfk analyze image.E01 -o D:\cases –operator 张三 # 完整分析
python -m sfk web D:\cases\case_xxx –open # 打开界面
python -m sfk verify D:\cases\case_xxx –hash # 校验证据链
4. 能力清单
4.1 采集(共注册 31 个采集器;Linux 镜像上实际执行 22 个)
| | |
| — | — |
| 平台 | 覆盖内容 |
| Linux | 主机画像、用户与账号(passwd/shadow/group/sudoers/PAM,含用户组完整成员关系——显式成员 + 按 GID 反查的主组成员)、SSH(配置 + 全部 authorized_keys 含指纹)、网络配置与网卡、接入设备(块设备/USB 含序列号/PCI + 内核日志里的接入、移除、挂载、I/O 故障事件)、认证日志、syslog、crontab、systemd、命令历史、Web 服务、Webshell 扫描、/tmp 可疑文件、软件包变更、Docker、软件日志清点、已部署应用清单、网站解构 |
| Windows | EVTX 事件日志(纯 Python 解析)、注册表 hive、计划任务、本地账号、进程、网络连接、服务与驱动、安全软件状态、执行痕迹 |
| 通用 | 疑似口令提取与验证(两个平台都跑) |
4.2 工具
• 文件浏览:在镜像里逐层浏览目录、预览文本/图片/十六进制、右键即可计算哈希(MD5/SHA1/SHA256)或下载,参考火眼的,但是也有问题,目前的UI优化的不是很好,使用体验还是比火眼差一些,具体表现在目录的分级上,之后还需要再优化。
• 哈希工具:对文件路径或任意粘贴文本计算哈希,在文件目录里面也可以直接右键计算哈希。
• 数据查看:按内容自动识别 SQLite / Redis RDB / MySQL binlog / 文本日志并选对读法,支持浏览、排序、关键字过滤、列筛选、任意只读 SQL 与分页。SQLite 用 Connection.deserialize 在内存里打开并置PRAGMA query_only。
• 网站解构:站点结构、框架识别、数据库连接、入口/上传/可写目录、风险项(后门脚本、上传目录内的可执行文件等)。这个功能还比较不稳定,不是所有的网站都能解构,需要多喂一些检材修修。
• 疑似密码:提取结果、手工验证口令(含 MD5/NTLM 二义性处理)、离线口令恢复(这个几乎是摆设。。。)、口令保管库。这个疑似密码是我觉得最伟大的功能,测试用的黄河流域服务器直接把拓鑫的密码吐出来了。
• 管理后台:识别到的面板与可直接复制的登录地址,但是第一版只做了显示网址这个功能,没法仿真,也就进不去后台,看看后续能不能实现一下这个功能,做到一键仿真。
• 设备与应用:接入设备、已部署应用、软件日志清点、服务器管理系统、网络接口。
4.3 界面与离线报告
本地 Web 界面只监听localhost,访问需要一次性随机令牌;页面完全内联,不引用任何外部 CSS/JS/字体,可在断网机器上打开。
离线报告(report/report.html)是自包含单文件,双击即可看。网站解构与疑似密码都走内嵌记录,所以离线报告与在线界面看到的内容一致;文件浏览 / 数据查看 / 哈希工具需要服务端实时读源镜像,报告里对这些入口给出了明确提示(一个离线 HTML 文件无法读取 E01 镜像)。
4.4 关联规则
SFK-COR-001…009 与SFK-SEC-001,覆盖暴力破解、攻击时间窗口、危险命令、特权账号、Webshell 文件 ↔ 访问日志中被实际请求、非工作时间登录(按目标主机本地时间判断)、网站高风险项、凭据汇总。
5. 实测成果(真实镜像)
5.1 Linux Web 服务器(20 GB E01,openEuler 24.03 LTS-SP3)(黄河流域)
1875 条记录 / 3 项发现 / 119 个证据文件,分析耗时 44.5 秒
3 项发现:
| | | |
| — | — | — |
| 级别 | 规则 | 内容 |
| critical | SFK-SEC-001 | 发现 77 条疑似口令/密钥(4 条已验证可用) |
| high | SFK-COR-007 | Webshell 检测与访问日志关联(1 个文件) |
| high | SFK-COR-009 | 网站存在高风险项(8 项,涉及 2 个站点) |
识别出的真实信息包括:发行版 openEuler 24.03 LTS-SP3、37 个账号与 64 个用户组的完整成员关系、nginx + 宝塔面板(端口 38497、后台路径 /7c09f4b5)+ Cockpit、Docker 容器、SSH 与 cron 持久化点、3 个站点解构(293 / 222 个文件、25 项风险)、116 条疑似凭据(4 条已验证可用)。
其中定位到一个真实后门:/www/wwwroot/tuoxin.com/public/backdoor.php,371 字节,内容为 $key=’2026′ 与system($_GET[‘cmd’])。网站解构把它标为高风险,SFK-COR-007 把它与访问日志里的实际请求关联起来。
5.2 Windows Server(WIN2008.E01,NTFS)(好久之前的检材了忘了是什么题)
9323 条记录 / 2 项发现
| | | |
| — | — | — |
| 级别 | 规则 | 内容 |
| high | SFK-COR-003 | 攻击时间窗口:2017-11-07T06:46:31Z 起 10 分钟内 17 条高危事件 |
| high | SFK-SEC-001 | 发现 75 条疑似口令/密钥 |
EVTX 解析器在该镜像上产出 8937 条事件,事件区 CRC 全部通过。
5.3 证据链完整性
对新生成的案件跑sfk verify –hash(重新计算每个证据文件的 SHA256 与清单比对):
证据清单条目:119
链式校验 :通过
清单头哈希 :8e27b03168b8147eda8d1eeb51bb6cd57707af97ed77391e9917bc6b153fd2c3
证据文件核对:全部通过(SHA256 与清单一致)
审计日志条目:2921
6. 关键设计与取舍(都是AI写的看一乐就行)
只用标准库,零外网。 开发环境实测 PyPI 不可达——这个约束是被强制的,不是口号。所以 EWF、ext4、NTFS、EVTX、注册表 hive、binlog、RDB 全是纯 Python 实现。
只读取证。 所有读取都经过ImageReader 只读抽象,对镜像只mmap(ACCESS_READ),不提供任何写目标的 API。
只写案件目录。 所有写入都经过util.within() 校验,越界直接抛PermissionError。
结论可回溯。 每条记录都带来源(文件路径 + 行号 / 字节偏移);每个证据文件都有 SHA256/MD5;manifest.jsonl 是链式哈希清单——任何一条被删改,其后所有条目都会校验失败。链头哈希写在报告摘要里,可以抄进正式取证报告。
同一套采集器,三种运行环境。 采集器只认逻辑路径(/etc/passwd),由core/fs.py 决定它落到哪里:本机、已挂载的镜像目录、或镜像里的 ext4/NTFS 卷。第三种情况下直接按块读取镜像,不需要先把文件系统解包到磁盘。
明细表的列同时看 extra 与 evidence。 一部分采集器把结构化细节放extra,另一部分放evidence。只看extra 会让后者的明细表一列都显示不出来——数据在案件里,界面上却只剩一句 detail,看起来像什么都没采到。
口令保管库改为明文(本轮按需求调整)。 原先用会话级随机密钥做异或+base64″混淆”。这个设计有两个坏结果:使用者会误以为它安全;而进程一重启,连自己存的口令都读不回来。现在改成格式化明文 JSON,可以直接用编辑器打开核对与修改,文件里显式标注 “storage”: “plaintext”。由此产生的责任:该文件等同于口令本身,必须按凭据同等保护。
离线口令恢复跑在独立子进程里。 并发默认 1、上限 4(刻意不占满 CPU),有墙钟时间上限、候选数上限;spawn 上下文、不写任何文件(审计由父进程写);每次任务记一条审计且不记录口令本身。只对本地哈希做离线计算,不会向任何目标地址发起登录尝试——那会改变取证目标的状态。
不静默失败。 采集器异常写入”采集覆盖”;提取/验证被资源预算或条数上限截断时,同样写明截断了多少、因为什么截断。案件卡片上会直接写出这类提示,例如:
扫描 2500 个候选文件,提取 91 条,入库 75 条……已达候选文件数上限,后面的文件没有扫描——真实环境中凭据往往集中在数据库转储、备份与配置文件里,如果需要更彻底的覆盖,请调高 any.secrets 的文件预算
7. 过程中修掉的真实缺陷(小鲸鱼犯的错误)
这是本次工作里最有价值的部分。下面每一条都是真实存在、被实际观测到、并已修复的缺陷;”如何被发现”一列说明它为什么没有一直被藏着。
| | | | | | |
| — | — | — | — | — | — |
| # | 问题 | 表现 | 根因 | 影响 | 如何被发现 |
| 1 | SQLite 视图跨线程复用 | 第二个请求里tables() 静默返回空,界面报”表不存在” | sqlite3 默认check_same_thread=True,而 Web 服务用 ThreadingHTTPServer | 看起来像数据文件损坏,极易误判 | 用 HTTP 连续多轮请求同一张表复现;新增 probe_db_http.py(8 线程并发)钉住 |
| 2 | 明细表列推导只读extra | 23 个事件类别里 16 个一列都没有;”账号”栏看不到组成员关系 | 采集器把细节放在evidence,列推导只看extra | 采到了却显示不出来,比没采到更糟 | 打印每类的列清单,发现大面积为空 |
| 3 | 同上(Windows 侧) | Windows 明细表 8 列里 6 列是空的 | EVTX 采集器把一批字段统一放进 extra 但值多为null,它们频率一样高,把列位占满 | 真正有用的event_id/log 被挤掉 | 同上 |
| 4 | 规则取字段只读extra,而 Webshell 采集器根本没写 path | SFK-COR-007 永远不可能触发,案件显示”0 项发现” | 规则期望path 字段,采集器只把它写在detail 和source 文本里 | 真后门存在却出不了结论 | 对比规则产出与案件 findings,发现 0 项但明明检出了 webshell |
| 5 | any.secrets.collect() 没有yield | 每次分析都抛TypeError: ‘NoneType’ object is not iterable | 不是生成器函数,返回None,基类yield from 失败;run() 的容错把它降级成一条”采集过程异常”告警 | 记录其实写进去了,但采集器被标记出错,容易被当成”小毛病”忽略 | 读case.json 里的 warnings;新增契约测试:定义了 collect 的采集器必须是生成器函数 |
| 6 | 19 个无基目录的 ** 模式各走一遍全盘 | 口令提取耗时 196 秒 | FileSystem.glob 对** 取base=”/”,每个模式独立全盘遍历(实测 19 个合计 50.7 秒) | 分析慢到影响使用 | 逐阶段计时定位 |
| 7 | 昂贵 KDF 无预算 | 同上,其中哈希比对 97.7 秒 | 60 个候选 × sm3crypt 单次 1.67 秒,而候选中大量是 /etc/shadow 的解析残渣 | 同上 | 量化单次 KDF 代价与候选/哈希组合数 |
| 8 | 0 字节数据库文件 | 接口直接返回HTTP 500 | 空文件让SqliteView 正确拒绝(”空的 SQLite 数据”),异常冒到兜底 500 | 取证人员会以为工具坏了 | 遍历全部候选文件跑一遍/api/db/info |
| 9 | 32 位十六进制无法区分 MD5 与 NTLM | 宝塔users.password 的哈希永远验证不上 | 判定用的是parsers.logs.classify_hash,它对裸 32 位十六进制给不出结论 | 漏报:真实的 MD5 口令匹配不上 | 手工验证接口返回”不匹配”,但 md5(“admin”) 明明相等 |
| 10 | 把哈希报成”明文口令,可直接使用” | 界面告诉分析师21232f29… 是可直接使用的明文口令 | 提取器把password 列的值一律当明文 | 误导性结论:分析师会拿十六进制串去登录 | 核对”已验证”条目的值,发现它其实是 md5(“admin”);修复后已验证数从 5 条降到 4 条(少的那条本就不该算) |
| 11 | 数据文件候选只列 Linux 路径 | Windows 镜像上候选列表是 0 个 | 路径表只写了/www/…、/var/lib/… | 换个目标操作系统就完全用不了 | 在真实 Windows 镜像上跑验收 |
| 12 | 截断原因上报错误 | 明明没到入库上限,却提示”已达入库上限,结果被截断” | 把”空值条目本来就不该入库”和”撞上 limit 被截断”混为一谈 | 让使用者误判覆盖完整性 | 检查案件卡片上的实际提示文字与真实计数 |
| 13 | .bat 把自己的提示文字当命令执行 | 运行时报’o’ is not recognized as an internal or external command | 文件用 LF 换行,而 cmd 按行读批处理,LF-only 在 ( ) 块里会错切行 | 一键入口不可用 | 实际运行.bat 看输出;修复:CRLF + 标签跳转,实测零裸 LF |
| 14 | 拖放实现会破坏整个窗口过程 | 窗口对每条消息返回垃圾值 | CallWindowProcW 的原窗口过程指针在 64 位下超出 c_int 范围,ctypes 类型推断溢出;异常被 ctypes 吞掉只打印一行 | 窗口行为诡异且极难定位 | 单元测试里跑消息循环并断言错误计数为 0 |
另外还修了:README 与实现矛盾(原写”口令只记录算法与是否锁定,不落盘明文或哈希“,而实现按需求会记录——已改正并写明使用者的责任);我自己的 JS 语法检查脚本有个 GBK 解码 bug 在吞真实错误;以及 ui.py 里两处[‘x’]})) 多一个括号(靠把内嵌 JS 抽出来交给 node –check 抓到——Python 编译通过不代表 JS 合法)。
8. 验证方式与证据
| | |
| — | — |
| 验证项 | 结果 |
| 单元测试(源树) | Ran 958 tests … OK (skipped=5),退出码 0 |
| 单元测试(解压副本) | 同一套测试通过(OK (skipped=10)) |
| 界面与接口验收(Linux) | 24 / 24 |
| 界面与接口验收(Windows) | 23 / 23 |
| 口令闭环验收 | 32 / 32 |
| 数据库端点验收(含 8 线程并发) | 19 / 19 |
| 离线报告渲染验收 | 8 / 8 |
| 压缩包校验 | 15 / 15 |
解压副本上多出的 5 个跳过依赖 .scratch/ 下的预生成夹具(全量 EVTX 回归样本、性能样本 perf.img)或环境能力(zip 命令、注册表 hive 权限),不是代码问题。
端到端证明”解压后即可用”:用解压出来的副本(不是源树)对那个 20 GB E01 完整跑了一遍——40 秒完成,1875 条记录 / 3 项发现 / 119 个证据文件,随后自动启动服务,界面验收 24/24 通过,证据链校验通过。
自己的验证工具(随包发布在verify/,8 个脚本 + 说明):
| | |
| — | — |
| 脚本 | 作用 |
| check_js.py | 把渲染出的页面里的内嵌 JS 抽出来交给 node –check。不能省:ui.py 里的 JS 嵌在 Python 字符串中 |
| accept_web2.py | 界面与接口端到端验收,自动按 Linux/Windows 分别断言 |
| accept_secrets.py | 口令闭环验收 |
| probe_db_http.py | 数据库端点验收(连续多轮 + 并发,复现跨线程缺陷) |
| check_local_sites.py | 抽界面里真实的 localSites() 在 node 里喂真实记录,断言返回值——不另抄一份逻辑 |
| dump_columns.py / final_check.py | 列推导检查 / 离线报告内容与截断提示检查 |
9. 已知限制
格式与文件系统
• 镜像格式:E01(含分卷)与 dd/raw 可用。VMDK 稀疏格式与 QCOW2 会被识别并明确拒绝(ImageError: 暂不支持的镜像格式);VHDX / VDI / VHD 目前没有实现识别(见第 10 节待办)。
• 文件系统:ext2/3/4 与 NTFS 可解析。XFS、Btrfs、LUKS、swap 能被正确识别出类型,但打不开,分析会停在”根文件系统 未打开”。
• ext4 事务日志(jbd2)不重放;Windows 注册表 .LOG1/.LOG2 不重放;NTFS $LogFile 不重放,压缩属性不解压。
• 加密卷(LUKS / BitLocker)需要先提供密钥。
• EWF 目前是只读的:不支持写入或修复损坏的 E01。
采集与判定
• IIS(Windows)站点发现未实现——网站解构只解析 Nginx/Apache 的站点配置,Windows 目标上该栏目是 0 个站点(界面上已写明,并指向 applicationHost.config 与「数据查看」里的 IIS 日志)。
• Windows 上疑似口令提取有候选文件数上限(2500 个)。实测在一台 Windows 镜像上,凭据富矿(*.sql 数据库转储等)排在上限之外,覆盖面不足;案件里会如实写明”已达候选文件数上限,后面的文件没有扫描”。
• Windows 上没有 CPU/内存硬上限(Python 无 resource 模块),离线口令恢复的实际约束只有墙钟时间、候选数与并发数。
• bcrypt 的实现尚未通过公开测试向量,界面标为”实验性”,结论仅供参考。
• MySQL binlog 与 Redis RDB 解析器只在高保真合成样本上验证过,未在真实生产文件上验证。
• 部分镜像的 Security.evtx 因权限/加密无法读取(其余日志正常)。
• 离线报告无法使用文件浏览 / 数据查看 / 哈希工具(需要服务端实时读源镜像)。
10. 待办与建议
按优先级排序。前两条是今天停手时尚未修复的发现,已实测复现。
1. (高)VHDX / VDI / VHD 被当成 raw 处理,且不报错。 造一个带vhdxfile 签名的文件跑sfk info,退出码 0、只报”介质大小 4.0 MB”,没有任何格式不支持的提示——用户会以为”检材是空的”,而不是”格式不支持”。这违反项目自己的”不静默失败”红线。修法:在 imageio.sniff() 里补 VHDX(vhdxfile)、VDI(偏移 0x40 的 7f 10 da be)、VHD(文件尾 conectix)三条签名,让open_image 给出带转换建议的明确错误。同时补一个格式嗅探的测试,断言”未知格式绝不静默按 raw 处理”。
2. (中)目标平台判定无法确定时,退化成取证机自身的操作系统。 core/runner._platform_for() 在target_os == “auto” 时直接看os.name。在自造的 LUKS 样本上(根文件系统打不开 → 平台判定为 auto),它在 Windows 取证机上跑起了 win.* 采集器并产出了 10 条记录——对 Linux 检材来说是纯噪声,且会误导。建议:无法确定目标平台时不要假定是取证机的系统,而是要么同时跑两个平台能探测通过的采集器,要么明确报告”未能判定目标平台”。
3. (中)无分区表时不提示。 空 dd 镜像跑 sfk info 会”成功”返回,但不说明未找到分区表。应显式提示,避免与第 1 条叠加造成误判。
4. (中)Windows 凭据提取的顺序与预算。 让*.sql 数据库转储、备份文件、.env 这类高产出目标优先于成堆的.config,或提高预算;现在的顺序会在到达富矿之前用完额度。
5. (低)IIS 站点发现:解析applicationHost.config 的
6. (低)bcrypt:当前实现算不过公开测试向量,应修到通过向量或明确标注不可用。
7. (低)Command.deserialize 之外的长尾格式:VMDK / VHDX / QCOW2 解析、XFS / Btrfs 读取、VSS 卷影副本。
这只是个初步尝试,虽然目前的小工具稀烂,有很多题都做不了,但希望之后能逐渐优化,真正成为好用的离线取证工具
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:蝶影流觞 CC14
CC14《尝试自己做一个全功能的服务器离线取证工具》