142 lines
8.1 KiB
Markdown
142 lines
8.1 KiB
Markdown
# 2026-08-01 通用加密 oracle 与公开模板解析器组合成 SQL 管理员接管
|
||
|
||
## 场景分类
|
||
|
||
Web / API / 渗透测试 / .NET CMS / 权限组合 / SQL 注入 / 管理员接管
|
||
|
||
## 目标概述
|
||
|
||
对一个开源 .NET CMS 做高危优先源码审计时,闭合“受限管理员通用加密功能 + 无认证密文模板消费者 + 危险模板标签”组合链。单独看似低影响的字符串加密权限,可为任意恶意模板生成系统有效密文;公开搜索动作把“可解密”误当“可信”,最终以 CMS 数据库账号执行原始 SQL 并重置合成管理员口令。
|
||
|
||
## 完整执行链路
|
||
|
||
1. 先把既有数据泄露归档设为 baseline,根因指纹不再计入“挖新的”停止门。
|
||
2. 从所有 `Encrypt/Decrypt/Sign/Verify` 入口建立生产者—消费者矩阵,记录权限、用途绑定、调用者可控字段和密文格式。
|
||
3. 定位一个只要求普通后台角色与独立“字符串加密”应用权限的动作;动作允许任意明文输入。
|
||
4. 反向搜索同一解密函数的消费者,发现公开搜索动作解密调用者模板,且控制器/动作没有授权元数据。
|
||
5. 沿公开动作跟踪到完整模板解析器,而非搜索专用允许列表;确认数据库标签可读取嵌套查询文本并沿用默认 CMS 数据库连接。
|
||
6. 跟到数据库抽象的最终 sink,确认原始字符串直接进入 `ExecuteReaderAsync(queryString)`,不限制为 `SELECT`。
|
||
7. 第一层夹具直接引用官方发布程序集,反射精确路由、角色与权限;无权限返回 401,有单一权限时加密成功,公开消费者解密后把固定 `SELECT` 送到数据库管理器替身。
|
||
8. 单独用官方数据库管理器、ORM 与 PostgreSQL provider 在隔离数据库执行 `UPDATE ... RETURNING`;独立查询确认状态持久化。
|
||
9. 最终在同一 Linux 进程串联官方加密动作、公开搜索动作、完整模板解析器和真实 PostgreSQL,修改合成管理员表。
|
||
10. 使用官方管理员仓储的口令验证方法做业务层正负对照:指定新口令成功、旧口令失败;到此立即停止进一步 SQL/RCE 扩展。
|
||
11. 数据库容器使用无宿主端口、独立网络、`tmpfs` 与自动删除;测试后确认容器不存在。
|
||
12. 按本地标准把“任意 SQL + 管理员密码接管”定为高危,生成正式报告、攻击路径图、结构化总账和不可变证据哈希。
|
||
|
||
## 踩坑记录
|
||
|
||
| 问题 | 原因 | 解决方案 | 耗时 |
|
||
|---|---|---|---|
|
||
| 先尝试从 CBC 密文直接伪造模板 | 块翻转虽可控,但会破坏前一明文块;非标准 padding 对最后一字节产生 33 个成功候选,不是经典单候选 oracle | 将密码学分支作为独立闭合项,不用它支撑主结论;回到应用层通用加密 oracle | 中 |
|
||
| SQL 写入夹具在 macOS 打开 SQLite 前失败 | 官方 SQLite provider 依赖缺失的 native `SQLite.Interop` | 保留“SQL 前失败”的环境证据,切换正式支持的 PostgreSQL provider 与 Linux 容器 | 低 |
|
||
| 模板属性中的 HTML `"` 未转成 SQL 双引号 | 模板属性解析没有按预期完成实体解码,数据库在 `&` 处拒绝语句 | 改用嵌套查询文本元素;先前失败保留为语法负控,不重复同法 | 低 |
|
||
| Linux 证明项目缺 ICU | 最小 Debian 镜像未安装 globalization native 依赖 | 证明仅使用 ASCII canary,以 `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1` 运行,不扩展镜像或下载额外包 | 低 |
|
||
| “能执行 UPDATE”仍可能被认为影响抽象 | 只证明数据库原语,不一定闭合实际业务接管 | 修改官方管理员表后调用官方口令验证器,建立新口令成功/旧口令失败的独立业务对照 | 低 |
|
||
|
||
## 工具链发现
|
||
|
||
- 对采用“不透明密文参数”的应用,必须同时审计密文生产者和消费者;加密不提供来源认证,通用加密接口会摧毁消费者隐含的信任边界。
|
||
- 控制器级角色限制不能替代细粒度权限影响分析。一个看似低风险的独立应用权限若能生成其他公开 sink 接受的 capability,就属于权限提升原语。
|
||
- 模板语言的公开解析面必须采用标签允许列表;只过滤搜索输入/XSS,不会约束数据库、文件、插件或代码类标签。
|
||
- `ExecuteReaderAsync` 并不等于只读。支持 `UPDATE/INSERT/DELETE ... RETURNING` 的数据库可通过同一 reader API 完成写入并返回行。
|
||
- 跨 OS native provider 失败后,用产品已携带的另一数据库 provider 和相同数据库抽象做隔离动态证明,证据强度高于重新实现 sink。
|
||
- 管理员接管要由业务验证器闭合;数据库列改变、HTTP 200 或响应回显单独都不足以证明新凭据可用。
|
||
|
||
## 关键代码/命令
|
||
|
||
生产者—消费者检查模板:
|
||
|
||
```text
|
||
producer: role + exact permission + arbitrary plaintext -> ciphertext
|
||
consumer: unauthenticated ciphertext -> decrypt -> full parser
|
||
parser: dangerous database tag -> raw query string
|
||
sink: configured CMS connection -> ExecuteReaderAsync(raw SQL)
|
||
impact: synthetic administrator UPDATE -> official validator new=true / old=false
|
||
```
|
||
|
||
隔离数据库执行模式:
|
||
|
||
```bash
|
||
docker run -d --rm --name {pg_canary} \
|
||
--network none --tmpfs /var/lib/postgresql/data \
|
||
-e POSTGRES_PASSWORD={synthetic_password} \
|
||
-e POSTGRES_DB={synthetic_database} {existing_postgres_image}
|
||
|
||
docker run --rm --network container:{pg_canary} \
|
||
-e DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 \
|
||
-v "{task_root}:/proof:ro" -w /proof {existing_linux_image} \
|
||
/proof/{verified_dotnet_runtime}/dotnet /proof/{proof_dll}
|
||
|
||
docker stop {pg_canary}
|
||
```
|
||
|
||
高价值断言:
|
||
|
||
```text
|
||
DENIED_WITHOUT_PERMISSION=True
|
||
PERMISSION_CHECK={single_encrypt_permission}
|
||
PUBLIC_CONSUMER_AUTHORIZE_METADATA_COUNT=0
|
||
RAW_SQL_RETURNED_CANARY=True
|
||
PERSISTED_ADMIN_ROW_CHANGED=True
|
||
CHOSEN_PASSWORD_ACCEPTED=True
|
||
OLD_PASSWORD_REJECTED=True
|
||
PROOF=PASS
|
||
```
|
||
|
||
## 对本包的改进建议
|
||
|
||
- 在 API Security 与 SRC Hunter 中增加固定检查:“通用 Encrypt/Sign/JWT 生成器是否能为另一个公开 Verify/Decrypt/Parse 消费者生成 capability”。
|
||
- 模板引擎审计清单增加“按解析上下文列危险标签允许列表”,优先检查 SQL、文件、插件、include、代码执行与任意连接字符串覆盖。
|
||
- 数据库 sink 证明模板应优先使用 `UPDATE ... RETURNING` 加独立读回;若可触达账号表,再加官方认证方法正负对照。
|
||
- 把“宿主 native provider 失败 → 产品另一正式 provider + 隔离 Linux/DB 容器”加入 .NET 动态证据降级路径。
|
||
|
||
## 可复用的模式/脚本片段
|
||
|
||
```text
|
||
低权限加密/签名生产者
|
||
→ 同格式公开解密/验签消费者
|
||
→ 消费者把密码学有效性误作授权
|
||
→ 完整解释器/模板引擎
|
||
→ SQL/文件/插件高危标签
|
||
→ 实际业务状态改变
|
||
```
|
||
|
||
评级闭环:
|
||
|
||
```text
|
||
原始 SQL 可达
|
||
+ 无权限负控
|
||
+ 独立持久化读回
|
||
+ 官方管理员验证器新旧口令差分
|
||
= 管理员接管 confirmed
|
||
```
|
||
|
||
## 进化动作
|
||
|
||
- [x] 更新了路由矩阵(新增通用加密/签名 oracle 与公开危险消费者组合路由)
|
||
- [ ] 更新了 tool-index(未安装新项目工具)
|
||
- [ ] 更新了 bootstrap-manifest(无缺失能力)
|
||
- [ ] 更新了子 skill 文档
|
||
- [x] 新增了 pitfalls 记录
|
||
- [x] 更新了 field-journal 三类索引
|
||
|
||
## 环境信息
|
||
|
||
- OS:macOS ARM64 宿主 + 隔离 Linux ARM64 容器
|
||
- 工具版本:.NET SDK 10.x;官方发布程序集目标 .NET 8;证明 runtime .NET 10.x;PostgreSQL 16
|
||
- 目标平台/版本:`{target_product}` 7.x 开源发行物
|
||
|
||
## 脱敏检查
|
||
|
||
- [x] 无真实产品名、域名、公网 IP、客户部署、commit 或发行物哈希
|
||
- [x] 无真实 token、Cookie、账号、口令、数据库连接串或业务记录
|
||
- [x] 所有命令使用 `{placeholder}`;状态改变仅描述合成 canary
|
||
- [x] 未保留管理员原值、密文、SecurityKey 或可直接回放的载荷
|
||
|
||
## 索引同步
|
||
|
||
本文件已加入 Web/API 场景、高频 Web/API 授权模式和 .NET CMS 模板解析实体倒排;统计日期同步为 2026-08-01。
|
||
|
||
---
|
||
<!-- [社区贡献] 完成后询问用户是否 PR 到主仓库。 -->
|