0xDanielSec/duel-framework
GitHub: 0xDanielSec/duel-framework
一个基于 LLM 博弈的对抗性安全研究框架,通过离线模拟攻击与检测提升 KQL 规则质量。
Stars: 0 | Forks: 0
# DUEL — 双重无监督规避循环




## 什么是 DUEL?
DUEL 是一个自包含的对抗性安全研究框架。两个本地运行的 LLM 代理将在可配置轮数内相互对抗。**攻击者**(`llama3.1:8b`)获得 MITRE ATT&CK 技术定义,并负责生成看起来像真实 Azure AD / Microsoft 365 攻击活动的合成遥测数据——凭证滥用、密码喷洒、OAuth 令牌窃取——同时主动推理上一轮防御者检测到了什么,并变异其方法以规避。**防御者**(`mistral:7b`)读取相同的遥测数据,研究之前哪些规则漏过了,并重写规则以填补漏洞。
在每一轮代理回合之间,DUEL 内置的检测引擎会在模拟真实 Microsoft Sentinel 模式(`SigninLogs`、`SecurityEvent`、`AuditLogs`)的 pandas DataFrame 上执行防御者的 KQL 规则。每一行都会被标记为唯一 ID,以便引擎精确报告哪些日志被捕获、哪些被规避。
评分器跟踪游戏状态——每条被规避日志给攻击者加分,每条检测成功给防御者加分,并将结果反馈到下一轮的提示中,使双方代理都能真正记住战斗历史。
所有轮次完成后,DUEL 生成三个输出工件:每轮的结构化 JSON 战斗日志、列出捕获至少一条攻击日志的每条 KQL 规则的最终报告,以及一份战后分析(`battle_analysis.md`),详细分解攻击者如何变异、每条防御者规则在字段层面为何失败、哪些检测信号被永久忽略,以及实际部署的 Sentinel 应添加哪些具体 KQL 规则。整个过程离线运行——不调用任何 Anthropic API、OpenAI 或其他付费服务。
## 架构
```
┌─────────────────────────────────────────────────────────────────────┐
│ DUEL ADVERSARIAL LOOP │
│ │
│ ┌──────────────────────────────────┐ │
│ │ TECHNIQUE LIBRARY │ │
│ │ techniques/T1078.004.json │ IOCs · Evasion variants │
│ │ techniques/T1110.003.json │ Sentinel tables · KQL hints │
│ └─────────────────┬────────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ ATTACKER AGENT │ llama3.1:8b via Ollama │
│ │ agents/attacker.py │ │
│ │ │ Round 1: generate initial TTPs │
│ │ ┌───────────────┐ │ Round N: mutate based on what │
│ │ │ Mutation logic│ │ was detected last round │
│ │ └───────────────┘ │ │
│ └──────────┬──────────┘ │
│ │ Synthetic log entries (JSON) │
│ │ [{table, _duel_id, IPAddress, UserAgent, …}] │
│ ┌──────────▼──────────┐ │
│ │ DEFENDER AGENT │ mistral:7b via Ollama │
│ │ agents/defender.py │ │
│ │ │ Round 1: write initial KQL rule │
│ │ ┌───────────────┐ │ Round N: harden based on what │
│ │ │Hardening logic│ │ evaded last round │
│ │ └───────────────┘ │ │
│ └──────────┬──────────┘ │
│ │ KQL detection rule (string) │
│ ┌──────────▼──────────┐ │
│ │ DETECTION ENGINE │ engine/detection.py │
│ │ │ │
│ │ SigninLogs ◄──┤ KQL → pandas pipeline executor │
│ │ SecurityEvent ◄──┤ Mirrors real Sentinel schemas │
│ │ AuditLogs ◄──┤ Returns: set of detected _duel_id │
│ └──────────┬──────────┘ │
│ │ detected_ids: set[str] │
│ ┌──────────▼──────────┐ │
│ │ SCORER │ engine/scoring.py │
│ │ │ │
│ │ Attacker +1/evaded │ Writes round_NN_battle_log.json │
│ │ Defender +1/caught │ Feeds results → next round prompt │
│ └──────────┬──────────┘ │
│ │ (repeat for N rounds) │
│ ┌──────────▼──────────────────────────────┐ │
│ │ OUTPUT ARTIFACTS │ │
│ │ │ │
│ │ output/round_NN_battle_log.json │ │
│ │ output/full_battle_log.json │ │
│ │ output/final_report.md │ │
│ │ output/battle_analysis.md ◄── new │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
## 快速开始
### 1. 安装 Ollama
从 [ollama.ai](https://ollama.ai) 下载并安装,然后启动守护进程:
```
ollama serve
```
### 2. 拉取所需模型
```
ollama pull llama3.1:8b # Attacker
ollama pull mistral:7b # Defender
```
### 3. 克隆并安装依赖
```
git clone https://github.com/yourhandle/duel-framework
cd duel-framework
pip install -r requirements.txt
```
### 4. 运行你的第一场对决
```
# Default: T1078.004, 5 rounds, 10 logs per round
python main.py
# Password spraying, 8 rounds, verbose output
python main.py --technique T1110.003 --rounds 8 --verbose
# Crank up attack volume
python main.py --technique T1078.004 --rounds 10 --logs 20
```
输出将位于 `output/`。战后分析始终位于 `output/battle_analysis.md`。
### CLI 参考
| 标志 | 默认值 | 描述 |
|------|---------|------|
| `--technique` | `T1078.004` | 模拟的 MITRE 技术 ID |
| `--rounds` | `5` | 对抗轮数 |
| `--attacker-model` | `llama3.1:8b` | 攻击者使用的 Ollama 模型 |
| `--defender-model` | `mistral:7b` | 防御者使用的 Ollama 模型 |
| `--logs` | `10` | 每轮生成的攻击日志数 |
| `--verbose` | off | 每轮打印遥测和 KQL |
## 工作原理
### 攻击者代理(`agents/attacker.py`)
攻击者接收完整的 MITRE 技术定义(IOC、规避变体、目标 Sentinel 表),并生成一批合成日志条目作为 JSON 数组。每条条目都是一个完整的日志记录,包含所有模式字段——真实的 UPN、地理定位、用户代理、结果代码等。
从第二轮开始,攻击者会看到上一轮的 KQL 规则及其捕获的日志,并被明确提示分析哪些字段值触发了检测,并在保留底层攻击模式的同时变异这些值。这就是产生**反应式变异**行为的地方——IP 范围轮换、用户代理切换、认证方式变化——所有这些都直接响应防御者在上轮针对的内容。
```
Round 1: python-requests/2.28.0 → 185.220.101.5 → ResultType 50126
Round 2: curl/7.68.0 → 91.108.4.200 → ResultType 50158 [reactive]
Round 3: Go-http-client/1.1 → 45.142.212.100 → ResultType 0 [reactive]
```
### 防御者代理(`agents/defender.py`)
防御者接收当前轮的攻击日志、上一轮的 KQL 规则以及漏过的日志。它被限制只能查询实际包含数据的表(从攻击日志动态注入),并且明确禁止使用 `join` 或 `union` 运算符,以免对单表遥测产生空结果。
防御者的温度设置比攻击者更低(0.4 对比 0.85),以生成一致、可解析的 KQL,而不是可能破坏执行器的创造性变体。即便如此,模型仍然会学习:到第三、四轮时,它通常会放弃基于 IP 的规则,转而开始针对结构性信号,如 `ConditionalAccessStatus` 和 `AuthenticationRequirement`。
### 检测引擎(`engine/detection.py`)
引擎是一个自定义的 KQL 到 pandas 解释器——不是 Azure Data Explorer 或任何云服务的包装器。它将 KQL 管道翻译为一系列 pandas 操作,并在根据攻击者日志构建的 DataFrame(应用完整的 Sentinel 模式并对缺失字段使用默认值)上逐阶段执行。
**支持的运算符:**
| 类别 | 运算符 |
|------|--------|
| 过滤 | `where` 支持 `==`、`!=`、`>`、`<`、`>=`、`<=`、`contains`、`!contains`、`has`、`has_any`、`startswith`、`endswith`、`in`、`!in`、`in~`、`matches regex`、`isempty`、`isnotempty`、`isnull`、`isnotnull` |
| 逻辑 | `and`、`or`、`not`(可任意嵌套带括号) |
| 聚合 | `summarize count() by`、`summarize dcount() by` |
| 投影 | `project`、`project-away` |
| 转换 | `extend`、`top N by`、`order by`、`sort by`、`limit`、`take`、`distinct`、`count` |
防御性地防范两种故障模式:如果防御者的 KQL 以没有数据的表开头,引擎会重定向到有数据的表;`join` 和 `union` 阶段会被移除,原因相同。
### 计分引擎(`engine/scoring.py`)
每条日志条目都携带唯一的 `_duel_id`。KQL 执行后,引擎返回被检测到的 ID 集合。评分器计算检测/规避率,为双方代理计分,将每轮日志持久化为 JSON,并将漏过和检测到的样本排队用于下一轮的提示。所有轮次结束后,运行战后分析器。
### 战后分析器
分析器(`engine/scoring.py` 中的 `_BattleAnalyst`)从轮次记录中通过纯数据分析推导叙事洞察——不调用任何额外模型。它将每条日志的每个字段分类为**稳定**(每轮值相同,最高置信度 IOC)或**旋转**(至少变化一次,变异向量)。它解析每条 KQL 规则的正则表达式以提取字段引用和简单条件,然后将其与漏过日志的值交叉引用,生成每轮失败诊断。它识别**检测缺口**——在所有轮次中 100% 出现在漏过日志中的字段,但从未被任何规则提及——并映射到具体的 KQL 修复代码片段,按置信度排序。
## 示例输出
以下是在一次 5 轮 T1110.003(密码喷洒)对决中 `output/battle_analysis.md` 的真实摘录。
### 攻击者变异表
```
| Field | Value(s) | Rounds Present |
|---------------------|------------------------------------|----------------|
| AuthenticationReq. | `Password` | all 5 |
| ClientAppUsed | `Microsoft Authentication Broker` | all 5 |
| ConditionalAccess | `Permitted` | all 5 |
| CountryOrRegion | `US` | all 5 |
```
```
Round 1 → Round 2:
- IPAddress: dropped `192.168.1.100`; added `192.168.1.103` [reactive mutation]
- ResultType: dropped `50126` [reactive mutation]
- AppDisplayName: dropped `Teams`; added `Microsoft Bookings`
Round 2 → Round 3:
- IPAddress: dropped `192.168.1.103`; added `192.168.1.112` [reactive mutation]
- AppDisplayName: dropped `Excel for the web`; added `SharePoint`
```
### 检测缺口分析
```
| Field | Stable Value(s) | % of Evaded Logs | Rounds Never Targeted |
|---------------------|-----------------|------------------|-----------------------|
| CountryOrRegion | `US` | 100% | all 5 |
| City | `Redmond` | 100% | all 5 |
```
### 生成的高置信度修复规则
```
SigninLogs
| where ConditionalAccessStatus == "notApplied"
| where ResultType == 0
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, CountryOrRegion
```
## 支持的技术
| ID | 名称 | 主表 | 状态 |
|----|------|------|------|
| [T1078.004](https://attack.mitre.org/techniques/T1078/004/) | 有效账户:云账户 | `SigninLogs` | 包含 |
| [T1110.003](https://attack.mitre.org/techniques/T1110/003/) | 暴力破解:密码喷洒 | `SigninLogs` | 包含 |
### 添加新技巧
创建 `techniques/.json` 并运行即可——
无需代码更改。
攻击者和防御者代理在运行时读取技巧定义——IOC 为攻击者的初始遥测播种规避变体指导其变异策略,检测提示指导防御者的第一轮规则。
## 路线图
### 近期计划
- [ ] **T1566.002** — 钓鱼:鱼叉式钓鱼链接(`OfficeActivity`、`EmailEvents`)
- [ ] **T1098.001** — 账户操纵:附加云凭证(`AuditLogs`)
- [ ] **T1136.003** — 创建账户:云账户(`AuditLogs`)
- [ ] **T1087.004** — 账户发现:云账户(`SigninLogs`、`AuditLogs`)
### 检测引擎
- [ ] 完整的 `join` 运算符支持用于跨表关联规则
- [ ] `let` 语句和变量绑定
- [ ] `arg_max` / `arg_min` 聚合
- [ ] 时间序列运算符(`make-series`、`series_decompose_anomalies`)
### 框架
- [ ] **Web UI** — 实时轮次可视化、并列 KQL 差异查看器、
实时得分计数器
- [ ] **MITRE ATT&CK 覆盖热图** — 跟踪哪些技术/战术单元已被对决及其平均规避率
- [ ] **多技巧战役** — 在单个对决中串联技巧(初始访问 → 持久化 → 渗出)
- [ ] **模型锦标赛模式** — 将多个 Ollama 模型进行对抗,按平均检测率排名
- [ ] **Sentinel 导出** — 一键导出存活的 KQL 规则作为 ARM 模板分析规则,随时可部署
- [ ] **人工介入模式** — 每轮后暂停,由人工分析师审查并覆盖防御者规则后再继续
## 项目结构
```
duel-framework/
├── main.py Adversarial loop orchestrator, CLI entry point
├── CLAUDE.md Permanent project briefing for Claude Code
├── requirements.txt
│
├── agents/
│ ├── attacker.py LLM agent: generates + mutates attack telemetry
│ └── defender.py LLM agent: generates + hardens KQL rules
│
├── engine/
│ ├── detection.py KQL-to-pandas executor, Sentinel schema factories
│ └── scoring.py Round scoring, battle logs, post-battle analyst
│
├── techniques/
│ ├── T1078.004.json Valid Accounts: Cloud Accounts
│ └── T1110.003.json Brute Force: Password Spraying
│
└── output/ Created at runtime
├── round_NN_battle_log.json
├── full_battle_log.json
├── final_report.md
├── battle_analysis.md
└── duel.log
```
## 道德使用
DUEL 生成**完全合成的遥测数据**,针对**内存中的 pandas DataFrame**。它不连接任何 Azure 租户、Microsoft 365 环境或实时 Sentinel 工作区。不涉及真实凭据、日志或系统。
该框架旨在用于安全研究、攻防演练和检测工程教育。
## 许可证
MIT 许可证——请参见 [LICENSE](LICENSE)。
*DUEL 是一个独立研究项目。它与 Microsoft、Anthropic 或 MITRE 公司无关。MITRE ATT&CK® 是 The MITRE Corporation 的注册商标。*
标签:AI风险缓解, Azure AD, Cloudflare, KQL检测规则, LLM评估, Microsoft 365, MITRE ATT&CK, Ollama, Python, 安全博弈论, 对抗安全, 攻击模拟, 数据帧, 无后门, 无监督逃逸循环, 日志仿真, 本地推理, 机器学习博弈, 检测引擎, 红队攻防, 自包含框架, 蓝队检测, 逆向工具, 防御博弈, 驱动签名利用