dotgibson/htpx
GitHub: dotgibson/htpx
一个 ATT&CK 标签标注的红蓝队配对语料库与终端浏览工具,让攻击手法与检测方法可并排查阅、按需填充并一键复制。
Stars: 0 | Forks: 0
# ⚔️ htpx
**每一次攻击,连同其检测。** 一个带有 ATT&CK 标签、红队↔蓝队配对的
语料库 —— 在浏览攻击时查看其对应的检测方法,填充 `{{slots}}`,并剪贴。
`fzf` · `mitre-attack` · `purple-team`
[](https://dotgibson.github.io/dotfiles-web/) 
**companion** — 结构化的、带 ATT&CK 标签的、红队↔蓝队配对的渗透测试参考
将攻击性语料库重构为机器可读的条目,以便相同的内容可以**被搜索、打上 ATT&CK 标签、进行目标替换,并与其
蓝队检测相配对** —— 这正是独立终端 companion 应有的形态。
对于其所涵盖的配对红队↔蓝队**攻击/检测切片,条目就是
事实来源**:当它们与 `hacktheplanet` / `PURPLE-TEAM.md` 存在交集时,扁平文件的代码块是从条目中*生成*的(位于 `companion:gen` 标记内),且
CI 会拒绝任何偏移。扁平文件中那些*不属于*干净的配对
攻击的内容 —— 技术文章、dorks、多步骤链 —— 仍保持手写并
作为权威来源。完整的模型请参阅下文的_事实来源_。
## 这里有什么
```
companion/
├── htpx # fzf browser: search → preview attack + its detection → fill slots → clip
├── gen-views.sh # render entry-backed blocks into the flat views (+ --check drift gate)
└── entries/
├── red/*.md # attacks (frontmatter + command template)
└── blue/*.md # detections (frontmatter + SPL), paired back to red
```
此目录是**主机无关的**(主机无关是因为它存放在自己的代码库 `dotgibson/htpx` 中,并像 `core/` 一样被 vendored 回来):`gen-views.sh` 的扁平视图目标默认指向
此代码库的 `PURPLE-TEAM.md` + `offensive/hacktheplanet`(相对于代码库根目录),但
可以通过
`$COMPANION_TARGETS` 进行覆盖(如果目标不存在则会被跳过,因此即使在没有扁平视图的独立 checkout 下,状态依然是绿色的),并且 `htpx` 会通过它找到的第一个
`clip`/`pbcopy`/`wl-copy`/`xclip`/`xsel` 进行复制(否则输出到 stdout),而不是
要求使用 Core 的 `clip` 助手。
## 条目 schema(Markdown + YAML frontmatter)
顶部是类型化的元数据(可被 grep、`yq` 查询);正文是
原始的复制粘贴内容(可在 `bat`/`glow` 中渲染,可被 `rg` 搜索)。每个条目一个文件。
```
id: stable kebab key
title: human label
section: matches a hacktheplanet fold name
phase: engagement phase
attack: { tactic: TA0006, techniques: [T1558.003] } # MITRE ATT&CK
platform: [windows, linux, network]
source: citation
pair: # or null
```
命令模板将语料库的 `` 占位符标准化为
`{{slots}}`(`{{rhost}}`、`{{lhost}}`、`{{user}}`、`{{password}}`、`{{domain}}`、
`{{hostname}}`、`{{nthash}}`、`{{port}}`、`{{share}}`)。
## 使用方法
```
export RHOST=10.10.10.5 DOMAIN=corp.local USER_T=svc_sql PASS='…'
htpx # pick an attack; preview shows it + its blue detection;
# the command is slot-filled and copied via `clip`
```
`htpx` 在 bootstrap 后即可在 shell 中使用:`companion/` 符号链接到 `~/companion`,
并且 `offensive.zsh` 定义了一个 `htpx` 函数。从 checkout 处你也可以直接运行
`./htpx`。它需要 `fzf`;如果存在 `bat`(预览)和 `clip`(Core 剪贴板)则会
使用它们,否则回退到 `cat`/stdout。没有 `yq` 依赖 ——
`htpx` 仅使用 `awk` 读取它所需的 frontmatter 中的标量顶级字段(`title:`、`pair:`)(嵌套的 `attack:` 块是供人类/grepper 使用的)。
## 差异化优势
`pair:` 字段使得 **purple pivot** 几乎零成本:选择一个攻击即可
在其旁边预览其检测方法(参见 Kerberoast ↔ `4769`,DCSync ↔ `4662`)。
没有主流工具会将攻击与它们触发的遥测数据配对提供。
## 语料库
71 个配对概念 + 1 个未配对的侦察条目(SMB enum),涵盖 Credential
Access、Privilege Escalation、Lateral Movement、Persistence、Execution、Defense
Evasion、Collection、Exfiltration 和 Discovery —— 包括本地 AD、多云切片
(Entra/M365、AWS、GCP)、Kubernetes、Okta、Google Workspace、CI/CD(GitHub Actions、
GitLab、Jenkins)、Harbor 容器注册表、HashiCorp Vault、Terraform Cloud、
Snowflake 数据云、Cloudflare 边缘网络、npm + PyPI 包注册表,
以及 Slack:
| Attack (red) | Detection (blue) | ATT&CK |
| --------------------------------- | ----------------------------------------------------- | --------- |
| Kerberoast SPNs | `4769` RC4 TGS | T1558.003 |
| AS-REP roast | `4771` pre-auth `0x18` | T1558.004 |
| Password spray (kerbrute) | `4625` one source, many accounts | T1110.003 |
| DCSync | `4662` replication | T1003.006 |
| Pass-the-hash lateral | `4624` type-3 fan-out | T1550.002 |
| NTLM relay | `4624` workstation mismatch | T1557.001 |
| Coerce DC (PetitPotam/printerbug) | `5145` named-pipe access | T1187 |
| AD CS ESC1 (certipy) | `4886` SAN mismatch | T1649 |
| Remote LSASS dump (lsassy) | `4656` dump-shaped handle | T1003.001 |
| RDP session hijack (tscon) | `4688` tscon `/dest:rdp-tcp#` | T1563.002 |
| Shadow Credentials (certipy) | `5136` msDS-KeyCredentialLink write | T1556 |
| RBCD (impacket) | `5136` msDS-AllowedToActOnBehalfOfOtherIdentity write | T1098 |
| Unconstrained delegation → DC TGT | `4624` DC machine-acct → non-DC _(soft)_ | T1558 |
| DPAPI domain backup key | `5145` protected_storage pipe | T1555 |
| SeImpersonate → SYSTEM (Potato) | `4688` service-acct → SYSTEM shell _(moderate)_ | T1134.001 |
| Device-code phishing (Entra) | Entra sign-in `deviceCode` flow _(KQL, cloud)_ | T1528 |
| Golden Ticket (forged TGT) | `4769` TGS with no preceding `4768` | T1558.001 |
| GPP cpassword (SYSVOL) | `5145` SYSVOL `Groups.xml` read | T1552.006 |
| NTDS.dit dump (ntdsutil/VSS) | `4688` ntdsutil/vssadmin + `8222` | T1003.003 |
| WMI exec (impacket-wmiexec) | `4688` `WmiPrvSE.exe` child shell | T1047 |
| Scheduled-task persistence | `4698` task created (suspicious action) | T1053.005 |
| WMI subscription persistence | Sysmon `19`/`20`/`21` consumer/binding | T1546.003 |
| Silver Ticket (forged TGS) | `4624` Kerberos logon, no `4769` _(soft)_ | T1558.002 |
| DCShadow (rogue DC) | `4742` `GC/` SPN write + `5137`/`4662` | T1207 |
| Illicit consent grant (Entra) | Entra audit "Consent to application" _(KQL, cloud)_ | T1528 |
| SP credential backdoor (Entra) | Entra audit "Add SP credentials" _(KQL, cloud)_ | T1098.001 |
| Privileged pod → node escape (K8s) | audit: privileged/hostPID/hostPath pod create | T1610/T1611 |
| Pod exec / attach (K8s) | audit: `pods/exec` subresource create | T1609 |
| Cluster-admin binding (K8s) | audit: roleRef `cluster-admin` binding | T1098 |
| MFA reset → takeover (Okta) | System Log `user.mfa.factor.reset_all` | T1556.006 |
| API token persistence (Okta) | System Log `system.api_token.create` | T1098 |
| Rogue IdP backdoor (Okta) | System Log `system.idp.lifecycle.create` | T1556 |
| IAM access-key backdoor (AWS) | CloudTrail `CreateAccessKey` actor≠target _(cloud)_ | T1098.001 |
| Console takeover (AWS) | CloudTrail Create/UpdateLoginProfile _(cloud)_ | T1098 |
| SA key creation (GCP) | Cloud Audit `CreateServiceAccountKey` _(cloud)_ | T1098.001 |
| Rogue self-hosted runner (GitHub) | audit `self_hosted_runner.created` _(cloud)_ | T1543 |
| Branch-protection tamper (GitHub) | audit `protected_branch.destroy` / `protected_branch.policy_override` _(cloud)_ | T1562.001 |
| Deploy-key/PAT backdoor (GitHub) | audit `repo.create_deploy_key` / `personal_access_token.access_granted` _(cloud)_ | T1098 |
| Backdoored image over trusted tag (Harbor) | audit `operation=push` artifact _(registry)_ | T1525 |
| Robot-account backdoor (Harbor) | audit `operation=create` `resource_type=robot` _(registry)_ | T1098 |
| Artifact deletion (Harbor) | audit `operation=delete` artifact/repository _(registry)_ | T1070 |
| Rogue runner association (GitLab) | audit `set_runner_associated_projects` _(cloud)_ | T1543 |
| Protected-branch tamper (GitLab) | audit `protected_branch_removed` / `protected_branch_created` _(cloud)_ | T1562.001 |
| Access/deploy-token backdoor (GitLab) | audit `project_access_token_created` / `personal_access_token_created` / `deploy_token_created` _(cloud)_ | T1098 |
| Bulk KV secret read (Vault) | audit `read` breadth over `secret/` paths _(secrets)_ | T1555 |
| Rogue AppRole backdoor (Vault) | audit create/update on `auth/approle/role/` _(secrets)_ | T1098 |
| Audit-device disable (Vault) | audit `delete` on `sys/audit/` path _(secrets)_ | T1562.001 |
| Rogue agent pool (Terraform) | audit `agent_pool` `create` _(IaC)_ | T1543 |
| Org/team token backdoor (Terraform) | audit `authentication_token` `create` _(IaC)_ | T1098 |
| Variable injection (Terraform) | audit `variable` `create`/`update` _(IaC)_ | T1072 |
| Script Console RCE (Jenkins) | audit `/script`/`/scriptText` request _(CI)_ | T1059 |
| User API token backdoor (Jenkins) | audit `generateNewToken` request _(CI)_ | T1098 |
| Job/pipeline backdoor (Jenkins) | audit `/createItem`/`/job//configSubmit` request _(CI)_ | T1072 |
| Data exfil via COPY INTO (Snowflake) | `QUERY_HISTORY` `QUERY_TYPE=UNLOAD` _(data)_ | T1567.002 |
| Backdoor user + ACCOUNTADMIN (Snowflake) | `QUERY_HISTORY` `CREATE_USER`/priv `GRANT` _(data)_ | T1136.003 |
| Network-policy tamper (Snowflake) | `QUERY_HISTORY` `NETWORK POLICY` change _(data)_ | T1562.007 |
| Illicit OAuth grant (Workspace) | token audit `authorize` _(cloud)_ | T1528 |
| Super-admin grant (Workspace) | admin audit `GRANT_DELEGATED_ADMIN_PRIVILEGES` _(cloud)_ | T1098.003 |
| External mail forwarding (Workspace) | `email_forwarding_out_of_domain` _(cloud)_ | T1114.003 |
| API token backdoor (Cloudflare) | audit `resource.type=api_token` `create` _(edge)_ | T1098 |
| WAF/firewall rule disable (Cloudflare) | audit `firewall_rule`/`ruleset` `delete`/`update` _(edge)_ | T1562.001 |
| Malicious Worker deploy (Cloudflare) | audit `resource.type=worker`/`workers_script` `create`/`update` _(edge)_ | T1648 |
| Malicious package publish (npm) | audit `package.publish` off-CI actor _(registry)_ | T1195.002 |
| Rogue maintainer add (npm) | audit `package.owner_add` / `team.user_add` _(registry)_ | T1098 |
| Publish-2FA disable (npm) | audit `package.edit` `mfa=none` _(registry)_ | T1562.001 |
| Malicious release upload (PyPI) | journal `new release` not via trusted publisher _(registry)_ | T1195.002 |
| Rogue collaborator add (PyPI) | journal `add Owner` / `add Maintainer` _(registry)_ | T1098 |
| Rogue trusted publisher (PyPI) | journal add `trusted publisher` _(registry)_ | T1098 |
| Malicious app install (Slack) | audit `app_installed` broad scopes _(SaaS)_ | T1098 |
| External shared channel (Slack) | audit `shared_channel_invite_sent` _(SaaS)_ | T1567 |
| 2FA enforcement disable (Slack) | audit `pref.two_factor_auth_changed` off _(SaaS)_ | T1562.001 |
既然有了偏移检测门,语料库的扩展就变得机械化:编写红队+蓝队条目
配对,标记匹配的扁平块,然后运行 `gen-views.sh`。对于**本地**配对,
蓝队检测会生成到 `PURPLE-TEAM.md` 中(云配对仅属于 companion ——
见下文)。当命令可映射到插槽时,红队部分会生成到
`hacktheplanet` 中(即使是多步骤也是如此 —— 见 RBCD);
只有带有内联注释或分散在现有折叠部分的命令才会保持手写。
无论哪种方式,条目都驱动着 `htpx` 和配对
预览。**全新**的技术(Shadow Credentials、RBCD)首先被编写为
条目,然后通过桥接流入*两个*扁平视图。
**云配对仅属于 companion。** Device-code-phishing 配对是本地 AD 之外的第一个
实例:其检测是 Entra 登录日志(KQL),这不应放在 `PURPLE-TEAM.md` 的 Windows 安全日志 SPL 框架中,因此它不会生成到
任何扁平视图中 —— 它只存在于条目中,在那里 `htpx` 仍然提供
完整的 purple pivot。这清楚地证明了条目是本地扁平引用的超集(并且是独立/云端拆分后的自然接缝)。
## 事实来源(已决定 —— 混合模式)
“条目是否将成为权威?”这一问题已经**解决**,但并不是
最初的二元模式。`hacktheplanet` 有 489 行,其中大部分是_技术文章_
—— dorks、枚举排序、条件建议、警告 —— 这些都不符合
条目 schema;从死板的条目生成整个文件要么会丢失这些
文章,要么会使 schema 臃肿成自由格式的 markdown。因此:
- **对于配对的红队↔蓝队攻击/检测切片,条目是权威的。**
那部分才是真正符合 `{id, title, attack, command}` 结构,并且
能从 ATT&CK 标签、插槽填充和 purple pivot 中受益的部分。
- **扁平文件在其他所有方面保持权威** —— schema 无法承载的
文章。
- **在存在交集的地方,条目通过生成优先。** 扁平文件使用 `companion:gen ID` … `companion:end ID` 标记选择加入一个块 —— markdown 中的 HTML 注释(`PURPLE-TEAM.md`),
即 shell 风格的 `hacktheplanet` 中的 `#` 注释。
`gen-views.sh` 会从条目重新生成被标记的块,并且
`gen-views.sh --check`(在 CI 中运行,`.github/workflows/companion.yml`)会在发生偏移时
失败。标记之外的内容永远不会被触碰。
这在交集处消除了偏移,_既不需要_进行 60 个条目的迁移,_也无需_
放弃丰富的文章。工作流程:编辑条目 → `gen-views.sh` → 提交两者。
**两端已连接。** 渲染形态取决于条目的颜色:
- **蓝队**(`PURPLE-TEAM.md`) —— `**title**` + 文章 + 围栏 `spl` 检测
块。它的 SPL 没有目标插槽,因此没有占位符转换。
- **红队**(`hacktheplanet`) —— 仅包含该文件简洁的、
命令优先的内部风格中的原始命令行,条目的 `{{slots}}` 会反向映射到它的
`` 词汇表(`{{rhost}}`→``,`{{nthash}}`→``,
…;见 `gen-views.sh` 中的 `SLOT_TO_ANGLE`)。仅标记命令连续且
干净映射的攻击(Kerberoast、AS-REP、DCSync);对于行分散在折叠部分或带有
内联注释的攻击(SMB enum、pass-the-hash)
保持手写 —— 条目仅拥有它能干净拥有的部分。
## 待定决策(在从 MVP 毕业之前)
1. **ATT&CK 标注是 100% 手动的** —— 目前没有任何来源包含技术 ID。
用_相同的_技术 ID 标注两种颜色会将 `pair:` 变成一个
可推导的关联(而不仅仅是一个手动维护的链接)。
2. **独立 vs 代码库内 —— 已解决。** 它现在存放在自己的代码库
(`dotgibson/htpx`)中,并通过 `git subtree` 被 vendored 回
`dotfiles-Kali` 的 `offensive/companion/` 中(来源记录在 Kali 的 `companion.lock` 中,
通过 `scripts/sync-companion.sh` 重新同步)。Kali 消费它;此代码库是
事实来源。
标签:AMSI绕过, Cutter, 威胁检测, 紫队, 防御加固