BearlyStable/Simple-GPO-Explorer

GitHub: BearlyStable/Simple-GPO-Explorer

一款基于 Web 的 GPO 备份归档分析工具,主要用于解析 SYSVOL 导出文件并自动恢复组策略偏好设置中的加密凭据。

Stars: 0 | Forks: 0

# Simple GPO Explorer 一个基于 Web 的组策略对象 (GPO) 备份归档分析器。 上传 SYSVOL 样式的 `.zip` 导出文件(包含 `GPT.INI` 的 `{GUID}` 目录),然后即可浏览、搜索并检查其中包含的每一个 GPO —— 安全模板、注册表策略、客户端扩展以及任何可恢复的组策略偏好设置凭据 —— 所有操作都在由 SQLite 支持的本地暗色模式界面中完成。 ## 功能 - **上传与解析** GPO 备份 `.zip` 归档(支持拖放或文件选择器)—— 预期为 SYSVOL 样式的 `{GUID}` 目录布局,每个目录需包含 `GPT.INI`;目录会被递归发现,因此直接压缩整个 `Policies` 文件夹的 zip 包也可直接使用 - 对归档中发现的每个 GPO 进行 **深度工件解析**: - `GPT.INI` —— GPO 版本(拆分为计算机/用户版本号) - `Group Policy\GPE.INI` —— 已配置的客户端扩展,根据精选的知名扩展 GUID 列表进行解析(注册表、安全、文件夹重定向、本地用户和组等) - `SecEdit\GptTmpl.inf`(计算机和用户)—— UTF-16LE 安全模板,解析为有序的节/键 - `Registry.pol`(计算机和用户)—— 二进制注册表策略格式,完全解码(`REG_SZ`、`REG_EXPAND_SZ`、`REG_DWORD`、`REG_QWORD`、`REG_MULTI_SZ`、`REG_BINARY`) - **组策略偏好设置凭据恢复** —— 每一个 `Preferences\*.xml` 文件(`Groups.xml`、`Drives.xml`、`ScheduledTasks.xml`、`Services.xml` 等)都会被扫描以查找 `cpassword` 属性,并使用微软公布的 AES 密钥(MS14-025 / KB2962486)进行解密 - 任何单个工件上的解析失败都会被记录为特定 GPO 的警告,而不会中断整个上传过程 - **归档集** —— 每次上传都会作为其独立的归档集存储在 SQLite 中;可从下拉菜单中切换以前上传的归档,或彻底删除某个归档 - **GPO 表格** 带有实时状态栏(显示的 GPO 数量、包含凭据发现的 GPO 数量、已解密的凭据总数),并包含名称、GPT 版本、扩展数量、计算机/用户策略存在状态、凭据发现以及备注等列 - **搜索栏** 支持自由文本加上 `key:value` 运算符(请参阅 [搜索运算符](#search-operators));多个 token 以 AND 组合,任何运算符都可以使用 `-` 进行否定 - 每一个 GPO 的 **GPO 详细视图** 解析工件: - GPT.INI 摘要、扩展列表、SecEdit 节、解码后的 Registry.pol 条目 - **凭据发现** 部分会高亮显示任何已解密的 `cpassword` 值,并附带源文件和账户名 - **文件浏览器** —— GPO 内部的每个文件都会被列出并可供查看:文本和 XML 会内联呈现(XML 经过格式化美化,大文件会被截断),二进制文件会通过扩展名/内容嗅探进行识别,且绝不会转储其原始字节 - 该 GPO 的任何解析错误都会被单独展示出来 - **显示名称映射** —— 上传一个包含 `{GUID}` 单元格和显示名称列的 markdown 表格文件(例如从 GPMC/RSOP 导出),以便为匿名的 GPO 添加标签;列的顺序和表头并不重要,只要每行有一个单元格呈 GUID 形式即可 - **备注** —— 每个 GPO 提供一个自由文本备注字段,并持久化存储在数据库中 - **标签** —— 每个 GPO 可附加任意标签,支持持久化存储并可通过 `tag:` 运算符进行搜索 - **暗色模式 UI**,无外部 CDN 依赖 —— 所有内容(样式、脚本)均在本地提供 ## 要求 - Python 3.11 或更高版本 - Pip / venv ## 安装 ``` # 1. Clone the repository git clone https://github.com/BearlyStable/Simple-GPO-Explorer.git cd Simple-GPO-Explorer # 2. 创建并激活虚拟环境 python -m venv .venv # Windows .venv\Scripts\activate # macOS / Linux source .venv/bin/activate # 3. 安装依赖 pip install -r src/requirements.txt ``` 在 macOS/Linux 上,你可以使用自带的 `Makefile` 来代替上述步骤: ``` make setup # creates src/.venv and installs dependencies make run # runs the app (implies setup) ``` ## 运行应用程序 ``` cd src python app.py ``` 服务器在 debug 模式下于 **http://localhost:4000** 启动。 用于生产环境部署(与 Docker 镜像运行的内容相匹配): ``` pip install gunicorn cd src gunicorn --bind 0.0.0.0:5000 --workers 1 --threads 4 --timeout 120 app:app ``` 实用的环境变量: | 变量 | 默认值 | 用途 | |---|---|---| | `SIMPLE_GPO_EXPLORER_SECRET_KEY` | `dev-secret-key-change-me` | Flask session/flash 签名密钥 | | `SIMPLE_GPO_EXPLORER_DB` | `/simple_gpo_explorer.sqlite3` | SQLite 数据库路径 | | `SIMPLE_GPO_EXPLORER_UPLOAD_DIR` | `/uploads` | 存储上传归档的目录 | ## Docker ### 拉取已发布的镜像 GitHub Actions 工作流(`.github/workflows/docker-publish.yml`)构建镜像并将其发布到 GitHub Container Registry: - 每次推送到 `main` 分支都会发布 `ghcr.io/bearlystable/simple-gpo-explorer:latest` - 每个发布的 GitHub Release 都会发布一个带版本标签的镜像,例如 `ghcr.io/bearlystable/simple-gpo-explorer:1.0.0`(以及 `1.0`) ``` docker pull ghcr.io/bearlystable/simple-gpo-explorer:latest ``` ### 在本地构建并运行 ``` cd docker docker compose up -d --build ``` 随后即可通过 **http://localhost:5000** 访问该应用程序。 ### 配置 将 `docker/.env.example` 复制到 `docker/.env` 以覆盖默认值(`docker compose` 会自动加载它): ``` cp docker/.env.example docker/.env ``` | 变量 | 默认值 | 用途 | |---|---|---| | `SIMPLE_GPO_EXPLORER_SECRET_KEY` | `dev-secret-key-change-me` | Flask session/flash 签名密钥 | | `SIMPLE_GPO_EXPLORER_PORT` | `5000` | 发布 Web UI 的主机端口 | ### 持久化数据 SQLite 数据库和每个上传的 `.zip` 归档都保存在容器内的 `/app/instance` 目录下,并由名为 `simple_gpo_explorer_data` 的命名卷支持。停止、移除或重建容器都**不会**影响此卷: ``` docker compose down # data preserved docker compose down -v # -v also deletes simple_gpo_explorer_data — be sure first ``` ### 将镜像迁移到离线机器 ``` make release # builds the image and exports it to dist/simple-gpo-explorer-.tar.gz ``` 目标机器只需要 tarball 以及 `docker/` 目录(不需要源码树、registry 或互联网访问): ``` docker load -i simple-gpo-explorer-.tar.gz docker compose -f docker/docker-compose.yml up -d ``` ### 备份与恢复 将命名卷备份为 tarball: ``` docker run --rm -v simple_gpo_explorer_data:/data -v "$PWD":/backup alpine \ tar czf /backup/simple-gpo-explorer-backup.tar.gz -C /data . ``` 通过将 tarball 解压回卷中来还原它,然后运行 `docker compose up -d`。 有关完整的操作步骤,请参阅 [docker/README.md](docker/README.md)。 ## 用法 1. 在浏览器中打开 **http://localhost:4000**(在 Docker 下为 **:5000**)。 2. 点击右上角的 **Upload GPO Archive**。 3. 拖放(或浏览找到)一个 `.zip` 导出文件 —— 即 SYSVOL 样式的 `{GUID}` 目录布局,每个目录需包含 `GPT.INI`(例如压缩了域控制器的 `SYSVOL\\Policies` 文件夹的 zip 包)。 4. 归档中的每个 GPO 都会被解析并存储为一个新的 **archive set**;使用顶部栏的下拉菜单可在不同归档集之间切换。 5. 使用 **search bar** 按名称、GUID、版本、策略范围、凭据发现、备注或标签进行筛选。 6. 点击任意行以打开 **GPO detail view**,其中包含每个已解析的工件、文件浏览器、备注和标签。 7. 可选择点击 **Display Names** 上传 markdown GUID → 名称映射表,为该归档集中的 GPO 添加标签。 ### 归档布局示例 ``` {31B2F340-016D-11D2-945F-00C04FB984F9}/ ├── GPT.INI ├── Group Policy/ │ └── GPE.INI ├── MACHINE/ │ ├── Microsoft/Windows NT/SecEdit/GptTmpl.inf │ ├── Registry.pol │ └── Preferences/Groups/Groups.xml └── USER/ ├── Registry.pol └── Preferences/Drives/Drives.xml ``` 同一个 zip 中的多个 `{GUID}` 目录都会被作为同一个归档集的一部分发现并解析。 ## 项目结构 ``` Simple-GPO-Explorer/ ├── LICENSE ├── Makefile # setup / run / docker-* / release targets ├── .dockerignore # Applies to the docker build context (repo root) ├── src/ │ ├── app.py # Flask application — routes, upload handling, REST API │ ├── requirements.txt # Python dependencies │ ├── gpo_analyzer/ # Parsing engine (no Flask dependency) │ │ ├── analyzer.py # Orchestrates parsing of a single GPO directory │ │ ├── extractor.py # Zip upload/extraction, zip-slip protection, GPO discovery │ │ ├── gpt_ini.py # GPT.INI parser │ │ ├── gpe_ini.py # GPE.INI / client-side extension parser │ │ ├── secedit.py # SecEdit\GptTmpl.inf parser │ │ ├── registry_pol.py # Binary Registry.pol parser │ │ ├── preferences.py # Group Policy Preferences cpassword scanner/decryptor │ │ ├── file_inspector.py # Binary/text detection for the in-browser file viewer │ │ ├── displayname_md.py # Markdown GUID → display-name table parser │ │ ├── pathutils.py # Case-insensitive path resolution │ │ └── db.py # SQLite schema, migrations, archive/GPO persistence │ ├── templates/ │ │ ├── base.html # Shared layout, upload/display-name modals │ │ ├── index.html # Archive set / GPO table page │ │ └── detail.html # GPO detail page │ ├── static/ │ │ ├── style.css # All custom styles (dark theme, badges, layout) │ │ └── app.js # All application logic (API calls, search, rendering) │ └── instance/ # Created at runtime — SQLite DB and stored upload archives └── docker/ ├── Dockerfile # Production image (gunicorn, python:3.12-slim) ├── docker-compose.yml # Compose file with a named volume for persistence ├── .env.example # Template for docker/.env overrides └── README.md # Extended Docker usage, backup/restore, offline transfer ``` ## API 端点 | 方法 | 路径 | 描述 | |--------|------|-------------| | `GET` | `/` | 主 Web UI(归档集 / GPO 表格) | | `GET` | `/gpo//` | GPO 详情页 | | `GET` | `/api/archive-sets` | 列出所有归档集 | | `POST` | `/api/archive-sets` | 上传并解析 GPO 备份 `.zip`(multipart 字段:`gpo_zip`) | | `GET` | `/api/archive-sets/` | 获取一个归档集的元数据 | | `DELETE` | `/api/archive-sets/` | 删除一个归档集、其包含的 GPO 及其存储的归档文件 | | `GET` | `/api/archive-sets//gpos` | 列出归档集中 GPO 的摘要信息 | | `GET` | `/api/archive-sets//gpos/` | 获取一个 GPO 的完整解析详情 | | `PATCH` | `/api/archive-sets//gpos//comment` | 设置或清除 GPO 的备注文本 | | `PATCH` | `/api/archive-sets//gpos//tags` | 替换 GPO 的标签列表(`{"tags": [...]}`) | | `GET` | `/api/archive-sets//gpos//files/` | 查看 GPO 中单个文件的内容(支持二进制安全;直接从存储的 zip 中重新读取) | | `POST` | `/api/archive-sets//display-names` | 上传 markdown GUID → 显示名称映射表(multipart 字段:`display_names_md`) | ## 搜索运算符 搜索栏接受纯文本(匹配显示名称、GUID、备注和标签)以及结构化的 `key:value` 运算符。多个 token 会以 **AND** 组合。在任何 token 前加上 `-` 可对其进行否定。`*` 字符作为通配符使用。 | 运算符 | 描述 | 示例 | |----------|-------------|---------| | `displayname:` | 显示名称 | `displayname:*policy*` | | `guid:` | GPO GUID | `guid:31B2F340*` | | `version:` | 精确的 GPT.INI 版本号 | `version:3` | | `machine:yes/no` | 包含计算机端策略 | `machine:yes` | | `user:yes/no` | 包含用户端策略 | `user:no` | | `creds:yes/no` | 包含已解密的 GPP 凭据 | `creds:yes` | | `notes:yes/no` | 包含备注 | `-notes:yes` | | `comment:` | 备注文本 | `comment:*legacy*` | | `tag:value` | 带有特定标签的 GPO | `tag:reviewed`, `-tag:stale` | **示例:** ``` # GPOs with recoverable credentials creds:yes # Named, machine-only policies without a review comment displayname:*policy* machine:yes user:no -notes:yes # Everything tagged "legacy" tag:legacy ``` ## 许可证 Simple GPO Explorer 采用 [GNU GPLv3](LICENSE) 许可。 ### 第三方软件 本项目构建于以下开源软件之上,并在设置/构建时通过 `pip` 安装(本仓库并未以源码形式重新分发其中的任何一项): | 项目 | 许可证 | 作用 | |---|---|---| | [Flask](https://github.com/pallets/flask) | BSD-3-Clause | Web 框架 | | [Werkzeug](https://github.com/pallets/werkzeug) | BSD-3-Clause | WSGI 工具包(Flask 依赖) | | [gunicorn](https://github.com/benoitc/gunicorn) | MIT | 生产级 WSGI 服务器(Docker 镜像) | | [PyCryptodome](https://github.com/Legrandin/pycryptodome) | BSD-2-Clause | 对组策略偏好设置 `cpassword` 值进行 AES 解密 | 以上各项均采用宽松的开源许可证,因此在 GPLv3 下分发本项目不存在 copyleft 兼容性问题。
标签:凭据提取, 数据可视化, 组策略, 请求拦截, 调试辅助, 逆向工具