- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
Armory 是 Sliver 客户端控制台内置的包管理器,用于"Automatically download and install extensions/aliases"(自动下载并安装扩展与别名)。它以armory命令组的形式实现,覆盖索引拉取、签名校验、包缓存、依赖解析、安装/更新/搜索以及多 Armory 配置管理等完整工作流。读完本文,你将掌握armory全部子命令的用法、armories.json配置结构、Minisign 签名验证机制,以及背后的缓存与并发设计。
Armory 是什么:Sliver 的扩展分发中心
在 Sliver 中,Alias(别名)与Extension(扩展)是两类可复用能力:Alias 通常指将外部工具(如 mimikatz、Rubeus 等)包装成 Sliver 命令的 manifest 包;Extension 则是包含多个自定义命令的扩展包。Armory 解决的问题是"从哪下载、如何校验、怎样安装"——它从配置的 Armory 仓库拉取签名索引,索引中列出可用的 aliases、extensions 与 bundles(包组合),再按需下载、验证并安装到本地。
该功能位于 client/command/armory/README.md,其核心职责由以下文件承担:
| 文件 | 职责 |
|---|---|
| armory.go | 维护 Armory 缓存生命周期,拉取包元数据、验证签名、展示包清单 |
| commands.go | 声明 Cobra 命令层级,绑定共享 flag 与补全逻辑 |
| install.go | 解析依赖并从缓存元数据安装 alias/extension,覆盖安装时提示用户 |
| manage.go | 查看、添加、验证、持久化 Armory 配置的管理逻辑 |
| parsers.go | 拉取 Armory 索引与包的解析器及 HTTP 工具,含 Minisign 验证 |
| search.go | 基于正则表达式的包搜索命令 |
| update.go | 计算可用更新、呈现选项并编排更新安装 |
命令族总览:一个命令,十三个动作
所有子命令在 commands.go 中通过 Cobra 注册,父命令armory的 Short 描述为 "Automatically download and install extensions/aliases",归属GenericHelpGroup。下表是完整命令矩阵:
| 命令 | 作用 | 必填参数 |
|---|---|---|
armory | 读取索引并列出所有可用包与 bundle | 无 |
armory install [name] | 安装一个 alias 或 extension | 0~1 个包名(缺省进入交互选择) |
armory update | 更新已安装的 aliases 与 extensions | 无 |
armory search <regex> | 按正则表达式搜索包名 | 恰好 1 个正则 |
armory info [name] | 查看已配置 Armory 列表或某 Armory/包详情 | 0~1 个名称 |
armory add <name> | 添加一个新 Armory | 名称,且--url/--pubkey必填 |
armory rm <name> | 移除一个 Armory | 名称 |
armory save | 将当前 Armory 配置持久化到磁盘 | 无 |
armory enable <name> | 启用某个 Armory | 名称 |
armory disable <name> | 禁用某个 Armory | 名称 |
armory modify <name> | 修改某个 Armory 的配置 | 名称 |
armory refresh | 强制刷新所有 Armory 索引 | 无 |
armory reset | 删除armories.json并重置配置 | 无 |
父命令共享的连接级 Flag
armory及其子命令通过flags.Bind("connection", ...)绑定了四个影响 HTTP 拉取行为的全局 flag(commands.go):
| Flag | 简写 | 默认值 | 说明 |
|---|---|---|---|
--insecure | -I | false | 跳过 TLS 证书校验 |
--proxy | -p | 空 | 指定代理 URL,如http://localhost:8080,支持本地代理补全 |
--ignore-cache | -c | false | 忽略元数据缓存,强制刷新 |
--timeout | -t | 15m | 下载超时时间(Go duration 格式) |
超时解析逻辑位于 armory.go 的parseArmoryHTTPConfig:--timeout会被time.ParseDuration解析,解析失败则回退到默认的defaultTimeout = 15 * time.Minute;--proxy会被解析为*url.URL注入 HTTP Transport。
核心命令实战
armory:浏览可安装的包
不带子命令直接执行armory时,会依次触发索引拉取、包签名拉取,并打印两张表格(armory.go):
- Packages 表:列包括 Armory、Command Name、Version、Type(Alias/Extension)、Help、URL(终端宽度足够时显示)。已安装的包名会被渲染为绿色。
- Bundles 表:列包括 Armory Name、Name、Contains(所含包名,每 5 个换行)。
执行流程的关键一步是签名验证:先并发拉取所有启用 Armory 的索引(fetchIndexes),再为每个索引中的包拉取.minisig签名(fetchPackageSignatures),只有签名合法、manifest 解析成功的包才会进入展示列表,任何失败都会打印错误行而不中断整体流程。
armory install:安装与依赖解析
安装是最核心的命令,支持三种用法:
armory install # 无参数,进入交互式多选表单 armory install <name> # 安装指定包或 bundle armory install all # 安装全部可用包(需确认)专属 flag(commands.go):
| Flag | 简写 | 默认值 | 说明 |
|---|---|---|---|
--force | -f | false | 强制安装,覆盖已存在的同名包 |
--armory | -a | 空 | 指定从哪个 Armory 安装(缺省搜索全部) |
安装逻辑(install.go)值得注意的细节:
- 覆盖确认:不带
--force时promptToOverwrite = true,若目标已安装则弹出覆盖确认;带--force则静默覆盖。 - 依赖解析:扩展的每个
ExtCommand可声明DependsOn,resolveExtensionPackageDependencies 会递归解析依赖,深度上限maxDepDepth = 10,并内置自依赖与循环依赖防护(跳过已解析、已 pending 的包)。 - 同名冲突处理:当多个 Armory 提供同名命令时,
getPackageForCommand会让用户从带完整描述(类型、版本、Armory、RepoURL)的列表中挑选,并提供 "Do not install this package" 取消选项。 - bundle 安装:若名字匹配 bundle,则逐个解析其中每个包的安装清单(去重、跳过已安装项)后批量安装。
- 安装后加载:alias 安装完成后会立即调用
alias.LoadAlias加载到植入端菜单;extension 则通过extensions.InstallFromDir完成。
底层安装(installAliasPackage / installExtensionPackage)是"下载 → 验签 → 落盘"三步:根据 RepoURL 主机名选择解析器下载 tar.gz 与签名,用包自身的public_key做 Minisign 验证(minisign.Verify),失败即中止;通过后写入临时文件(sliver-armory-*)再交给 alias/extension 安装器。
armory search:正则搜索包
armory search接收恰好一个正则表达式参数(search.go):先强制刷新包缓存,然后regexp.Compile编译用户输入(非法正则直接报错),分别对缓存的 alias 命令名与 extension 的每个ExtCommand.CommandName做MatchString,命中结果复用PrintArmoryPackages输出表格。
armory search '^mimi' # 匹配以 mimi 开头的包 armory search '(get|set)' # 匹配包含 get 或 set 的包armory update:版本比对与批量升级
更新流程(update.go):刷新缓存 → 对比已安装包与仓库最新版本 → 展示 "Available Updates" 表格(Package Name / Package Type / Installed Version / Available Version)→ 交互式多选 → 逐项安装新版本。
版本比对逻辑值得关注:由于支持多 Armory 且没有官方版本号规范,checkForAliasUpdates 与 checkForExtensionUpdates 均采用版本字符串比较(latestAlias.Version > localManifest.Version),要求包作者在发布时递增版本标识。扩展还额外做了 manifest 匹配(PackageName相同,或存在同名ExtCommand)以及同名多版本去重。与install相同,--armory/-a可将更新范围限定在单个 Armory。
armory info:查看配置与包详情
不带参数时列出所有已配置 Armory(Armory Name / Authorization Required / Enabled / URL)。(manage.go)带参数时(如armory info sliver-armory)先强制刷新缓存,再输出三类详情(viewDetailedInformation):
- 匹配的Armory:Name、Public Key、Enabled、是否需要授权(含当前 Authorization 值)、Authorization Command、URL;
- 匹配的包:Name、Command Name、Armory Name、类型(alias/extension)、Version、Author、Repo URL、Help,扩展还会列出所含命令、依赖与各命令 Help;
- 匹配的扩展命令:列出包含该命令名的扩展包完整信息。
Armory 配置管理:armories.json的增删改查
配置文件结构
所有 Armory 配置持久化在客户端根目录下的armories.json(常量ArmoryConfigFileName = "armories.json",见 client/assets/armories.go),每个条目对应结构体ArmoryConfig(armories.go):
[ { "public_key": "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3", "repo_url": "https://api.github.com/repos/BishopFox/sliver-armory/releases", "authorization": "", "authorization_cmd": "", "name": "Default", "enabled": true } ]字段说明:
| 字段 | 说明 |
|---|---|
public_key | 用于验证该 Armory 索引签名的 Minisign 公钥(同时也是内存缓存的键) |
repo_url | 索引的仓库 URL,https/http以外的 scheme 会被拒绝 |
authorization | 静态授权凭据,请求时作为AuthorizationHeader 发送 |
authorization_cmd | 本地命令,每次刷新时执行并用其输出作为授权凭据 |
name | Armory 名称,需唯一 |
enabled | 是否启用,禁用的 Armory 不会被拉取 |
默认 Armory 的特殊处理:常量DefaultArmoryName = "Default"(armories.go)。GetArmoriesConfig 在读取文件时会把 Default 强制排到列表末尾;getCurrentArmoryConfiguration 则维护defaultArmoryRemoved标志,避免用户主动删除 Default 后又被重新加回。authorization_cmd的凭据由RefreshArmoryAuthorization在每次拉取前刷新(执行本地命令捕获 stdout,失败则置空并记日志)。
管理命令一览
armory add my-armory -u https://example.com/index -k <PUBKEY> # 添加并验证 armory add my-armory -u https://example.com/index -k <PUBKEY> -a "Bearer xxx" # 带授权 armory add my-armory -u ... -k ... -x "/path/to/token.sh" # 用本地命令动态授权 armory rm my-armory # 移除并清缓存 armory modify my-armory -n new-name -u https://new.url -k <NEWPK> # 修改 armory enable my-armory # 启用 armory disable my-armory # 禁用 armory save # 手动持久化 armory refresh # 清空缓存强制刷新 armory reset # 删除配置文件并重置各命令的关键行为(均位于 manage.go):
add(AddArmoryCmd):--url/--pubkey为必填(MarkFlagRequired)。添加前先调用verifyArmory实际拉取一次索引并验证签名,验证失败则拒绝添加——确保只有签名可验证的 Armory 才会进入配置。默认Enabled: true;--no-save/-e只做临时添加不落盘。其他 flag:--auth/-a、--authcmd/-x。rm(RemoveArmoryCmd):同步清除该 Armory 的索引缓存、包缓存与currentArmories条目,删除 Default 时置defaultArmoryRemoved = true,随后保存新配置。modify(ModifyArmoryCmd):支持--name/-n、--pubkey/-k、--url/-u、--auth/-a、--authcmd/-x、--no-save/-e。修改 pubkey 时校验唯一性(公钥是缓存键);修改后会删除旧缓存、重新验证新配置,验证失败时弹出交互确认,可选择回滚到旧配置。enable/disable(ChangeArmoryEnabledState):禁用时清除该 Armory 的全部缓存,随后强制刷新其余 Armory。refresh(RefreshArmories):设置IgnoreCache = true、clearAllCaches()清空三个内存缓存并重置初始化标志,全量重新拉取。reset(ResetArmoryConfig):直接删除armories.json文件并触发一次强制刷新,回到仅含 Default Armory 的初始状态。
底层原理:缓存、签名与解析器
三级内存缓存与 2 分钟有效期
armory.go 用三个sync.Map构成缓存体系:
| 缓存 | 键 | 存储内容 |
|---|---|---|
indexCache | Armory 公钥 | indexCacheEntry:索引、仓库 URL、拉取时间、错误 |
pkgCache | 包 ID(SHA-256 哈希) | pkgCacheEntry:签名、alias/extension manifest、错误 |
currentArmories | Armory 公钥 | 当前生效的ArmoryConfig |
缓存有效期cacheTime = 2 * time.Minute(armory.go):fetchIndex与fetchPackageSignature都会先检查缓存,命中且未过期则直接复用;过期则删除旧条目重新拉取。--ignore-cache可强制绕过。索引与包签名拉取均通过容量为 10 的 channel 做并发限流,避免对 Armory 服务器造成压力(fetchIndexes)。
包 ID 的生成是理解缓存一致性的关键:calculatePackageHash 对RepoURL + PublicKey + ArmoryName + CommandName做 SHA-256。由于多 Armory 场景下命令名不再唯一,该 ID 用于跨缓存唯一定位包;索引解析时还会调用makePackageCacheConsistent,把已从索引中删除的包从缓存中清除。
Minisign 签名验证链路
所有索引与包都必须经过 Minisign 验证(基于 util/minisign):
- 索引验证:
DefaultArmoryIndexParser(parsers.go)拉取 Armory URL 的 JSON,其中包含 Base64 编码的armory_index与minisig;解码后用配置的公钥执行minisign.Verify,失败返回"index has invalid signature"。签名中的TrustedComment字段实际承载 Base64 编码的 manifest 数据。 - 包验证:
DefaultArmoryPkgParser(parsers.go)拉取包 JSON(minisig+tar_gz_url),解析签名后用包级公钥验证 tar.gz。安装时installAliasPackage/installExtensionPackage会再次对下载的 tar.gz 做minisign.Verify,双重校验。 - 签名内容:
fetchPackageSignature(armory.go)解码签名TrustedComment后,按IsAlias分支解析为AliasManifest或ExtensionManifest。
三类解析器的选择策略
解析器按 RepoURL 主机名注册(parsers.go):
| 主机名 | 索引解析器 | 包解析器 |
|---|---|---|
api.github.com | GithubAPIArmoryIndexParser | GithubAPIArmoryPackageParser |
github.com | 默认解析器 | GithubArmoryPackageParser |
| 其他(自托管) | DefaultArmoryIndexParser | DefaultArmoryPkgParser |
GitHub API 解析器(GithubAPIArmoryIndexParser)从 release 列表中取最新 release,下载名为armory.json与armory.minisig的资产;包解析器则下载<command_name>.minisig与<command_name>.tar.gz资产。注意 GitHub API 未认证限额为 60 次/小时,超出会返回 403,客户端会提示"you hit the github api rate limit (60 req/hr), try later"。GithubArmoryPackageParser则绕开 API,通过拦截/releases/latest的 302 重定向 Location 头解析最新 tag,再从releases/download/<tag>/<name>.tar.gz直链下载。自托管 Armory 只需按{armory_index, minisig}与{minisig, tar_gz_url}的 JSON 结构提供接口即可。
常见问题与排查思路
- "you hit the github api rate limit":GitHub API 未认证 60 次/小时,稍后重试,或为 Armory 配置
authorization凭据提升限额。 - "index has invalid signature" / "signature verification failed":
public_key与索引/包签名不匹配,检查armories.json中的公钥是否完整、与仓库发布者一致。 - "Package is already installed":目标包已存在,使用
armory install <name> --force覆盖,或先执行armory update。 - "The package cache is out of date":bundle 安装时缓存与索引不一致,执行
armory refresh后重试。 - 想临时体验某个 Armory:用
armory add <name> --no-save添加,验证通过即可使用,不会污染配置文件。
结语
Armory 是 Sliver 生态中连接社区工具与本地控制台的关键枢纽:它以 Minisign 签名保证供应链可信,用 2 分钟缓存与 10 路并发限流平衡效率与负载,通过依赖解析、同名冲突消解、多 Armory 配置与动态授权命令,把"装包"这一简单动作背后的完整工程细节收敛成一条armory install命令。理解其缓存键设计(SHA-256 包 ID)、解析器按主机名分发的架构,以及armories.json的字段语义,能帮助你在自建 Armory、排查验签失败或定制包分发时做到心中有数。
- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
相关推荐
Oh My Fish 插件包实战:如何搜索、安装与管理 shell 扩展包
Oh My Fish 插件包实战:如何搜索、安装与管理 shell 扩展包 Oh My Fish 是一个专为 Fish Shell 打造的 shell 扩展包管
CLI包管理器Appium CLI 扩展管理命令完全指南:driver 与 plugin 的安装、更新与维护
Appium CLI 扩展管理命令完全指南:driver 与 plugin 的安装、更新与维护 本指南系统讲解 Appium CLI 中 appium driv
任务调度大数据后端前端OMO Native Bun 安装与自更新管理器的 QA 实录:从 Bun 全局安装缺陷到包管理器感知的更新命令
OMO Native Bun 安装与自更新管理器的 QA 实录:从 Bun 全局安装缺陷到包管理器感知的更新命令 本篇文章基于 oh my openagent
人工智能AI Agent代码智能体多智能体MCP ClientsAgent 编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考