ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Sliver 客户端 update 命令组深入解析:版本检查、自动更新与 minisign 签名验证

Sliver 客户端 update 命令组深入解析:版本检查、自动更新与 minisign 签名验证 Sliver 客户端 update 命令组深入解析版本检查、自动更新与 minisign 签名验证【免费下载链接】sliverAdversary Emulation Framework项目地址: https://gitcode.com/gh_mirrors/sl/sliverupdate命令组是 Sliver 客户端控制台sliver-client中负责「检查新版本并下载更新」的核心模块位于 client/command/update由两个文件构成commands.go命令注册与参数定义与update.go版本检查、资产匹配、下载与签名验证的完整实现。本文基于当前仓库源码完整梳理update与version两个命令的全部参数、版本检查的语义化版本比较逻辑、按目标平台匹配发布资产的机制以及下载链路上的重试、代理、TLS 与 minisign 签名校验等供应链安全细节帮助你彻底理解并在实际环境中安全地使用 Sliver 的更新机制。update 命令组职责与注册方式从源码结构看update是一个典型的 Cobra 命令组Commands()函数返回两个子命令并交给命令分发层统一注册入口位于 server.go 中update.Commands的调用。两个命令都属于GenericHelpGroup即客户端控制台中的通用命令分组不依赖会话或 Beacon。命令UseShort 描述入口处理函数updateupdateCheck for updates检查更新UpdateCmdversionversionDisplay version information显示版本信息VerboseVersionsCmd命令字符串常量定义在 constants.go 中UpdateStr update、VersionStr version两者通过help.GetHelpFor生成各自的 Long 帮助文本。update 命令完整参数与使用方式update命令在 commands.go 中绑定了 6 个参数覆盖了「是否包含预发布、是否走代理、保存目录、TLS 校验、强制下载、超时」等更新场景的所有关键维度参数简写类型默认值说明--prereleases-Pboolfalse是否包含预发布不稳定版本--proxy-pstring空指定代理 URL例如http://localhost:8080--save-sstring空下载文件保存到指定目录默认下载目录--insecure-Iboolfalse跳过 TLS 证书校验--forceboolfalse跳过版本比较直接下载最新发布--timeout-tint6460gRPC 超时秒数默认值来自 flags.go 的DefaultTimeout此外命令还注册了两处 shell 补全--proxy使用LocalProxyCompleter()提供本地代理补全--save注册了本地文件路径补全RegisterLocalFilePathFlagCompletion方便在控制台交互式输入。一个典型的更新命令形如update --prereleases --proxy http://127.0.0.1:8080 --save /tmp/sliver-updates使用 --insecure 时的双重确认UpdateCmd的实现update.go对--insecure做了非常严格的保护当检测到该参数时会打印警告 “Youre trying to update over an insecure connection, this is a really bad idea!”并连续弹出两次forms.Confirm确认框Recklessly update? 与 Seriously?只有两次都确认才会继续。从这一代码路径可以看出跳过 TLS 校验被认为是一个极其危险的操作正常使用中不应开启。版本信息展示update 的前置动作与 version 命令客户端与服务器版本的同时汇报UpdateCmd的第一步就是调用VerboseVersionsCmdupdate.go它通过 gRPC 向服务器发起GetVersion请求随后同时打印客户端与服务器两侧的版本信息客户端version.FullVersion()含编译时间与 Git Commit、编译时架构runtime.GOOS/GOARCH、编译时间version.Compiled()、编译所用 Go 版本version.GoVersion服务器vMajor.Minor.Patch、Commit、OS/Arch、编译时间由CompiledAt时间戳还原。也就是说即使只运行update也会先看到一次完整的版本对比输出。构建信息的注入与读取版本字符串并非硬编码而是编译期注入 运行时探测的双通道机制sliver-version.goinit()中若未通过-ldflags -X注入GithubReleasesURL则回退到默认的 GitHub Releases API 地址applyBuildInfo()通过 Go 的debug.ReadBuildInfo()读取模块构建信息自动填充vcs.revisionGit Commit、vcs.time编译时间、vcs.modified工作区是否 Dirty若构建信息缺失Version回退为develGoVersion回退为runtime.Version()。FullVersion()sliver-version.go会拼接版本、编译时间与 Git Commit形成类似v1.6.0 - Compiled 2024-xx-xx xx:xx:xx 0000 UTC - abcdef1的完整字符串。更新检查机制GitHub Releases API 与 semver 比较数据来源与跳过开关版本检查的底层实现在 updates.goGithubReleasesURL默认指向https://api.github.com/repos/BishopFox/sliver/releases可通过构建时-ldflags -X覆盖设置环境变量SLIVER_NO_UPDATE_CHECK非空会跳过检查fetchReleases中直接返回空结果同时若GithubReleasesURL为空也会跳过Release与Asset结构体对应 GitHub Releases API 的 JSON 字段tag_name、prerelease、assets[].browser_download_url、assets[].size等响应体非 200 或 JSON 解析失败都会导致检查失败并返回错误。CheckForUpdates 与 LatestRelease 的区别这是理解update行为的关键两条路径对应--force是否开启update.goCheckForUpdatesupdates.go默认路径。将当前版本Version归一化为规范 semver自动补v前缀、调用semver.Canonical遍历发布列表跳过预发布除非--prereleases、跳过 tag 无法解析的发布一旦发现semver.Compare(releaseVersion, current) 0即返回该发布。只返回比当前版本新的第一个发布没有新版本时返回nil。LatestReleaseupdates.go--force路径。不比较当前版本直接在所有按需排除预发布的发布中挑出语义化版本最高的一个。两者共同点都通过golang.org/x/mod/semver做版本比较且预发布版本只有在--prereleases为真时才被纳入考虑。因此update --force的输出语义是 Latest release available普通update则是 New version available无可用更新时分别提示 No releases found. 与 No new releases.。上次检查时间的落盘无论检查成功与否UpdateCmd结尾都会把当前 Unix 时间戳写入Sliver 应用目录/last_update_check文件update.go文件名常量LastUpdateCheckFileName last_update_check定义于 constants.go。该文件用于记录最近一次更新检查的时间写入失败仅打印警告、不影响主流程。发布资产匹配按运行平台挑选 server/client 二进制更新下载的核心是先弄清楚「当前平台应该下载哪个文件」。update.go通过三组函数完成这一映射update.goassetSuffixes(goos, goarch)按当前runtime.GOOS/GOARCH生成候选后缀列表优先级从精确到宽松_goos-goarch.zip、_goos-goarch_goos.zip、_goos特例macOSgoos darwin额外支持_macos-goarch.zip、_macos-goarch、_macos.zip、_macos等历史命名serverAssetForGOOS/clientAssetForGOOS分别以sliver-server/sliver-client为文件名前缀在发布的assets列表中寻找「前缀匹配 后缀命中」的资产找不到时updateAvailable会打印警告 “No server/client asset available for / ”并在下载确认环节直接阻止无资产的下载。找到资产后控制台会先展示资产大小通过util.ByteCountBinary格式化为人类可读的二进制字节数再弹出forms.Confirm(Download update?)确认下载。下载流程临时文件、重试退避与进度条保存路径的决策逻辑updateSavePathupdate.go决定更新包落盘位置显式传入--save校验该路径存在且为目录否则报错未指定时优先使用当前用户~/Downloads若存在且为目录否则回退到用户主目录获取用户信息失败时最终回退到系统临时目录。三次重试与指数退避下载封装为downloadWithRetries/downloadBytesWithRetriesupdate.go最多尝试downloadAttempts 3次起始退避750ms、每次翻倍750ms → 1.5s → 3s。只有「可重试错误」才触发重试update.goio.ErrUnexpectedEOF连接中途断开网络层错误且为Timeout()或Temporary()HTTP 状态码为 429Too Many Requests、500、502、503、504 等服务器侧可恢复错误。原子落盘与字节数校验downloadOnceupdate.go使用os.CreateTemp在目标目录创建*.tmp-*临时文件下载完成后调用tmpFile.Sync()刷盘再经replaceFile先删除旧目标文件再os.Rename原子替换落为正式文件任一步失败都会清理临时文件。下载期间若已知期望字节数资产Size或Content-Length则用cheggaaa/pb渲染带字节计数的进度条并在终端是 TTY 时切换为终端模式完成后强制校验实际下载字节数 期望字节数不一致即报错downloaded %d bytes, expected %d签名文件.minisig走downloadBytesOnce内部用io.LimitedReader限制读取上限防止超大响应。供应链安全minisign 签名验证与可信注释校验构建期注入的公开密钥Sliver 的更新包采用 minisign 签名机制。update.go中声明了包级变量SliverPublicKeyupdate.go该变量在编译期通过-ldflags -X注入构建脚本会填充真实的 minisign 公钥。loadSliverPublicKey在运行时解析该字符串若未注入则直接报错 minisign public key not set at build time。双重校验签名 可信注释中的文件名downloadAssetWithSignatureupdate.go的完整校验链为从资产列表中找到对应的.minisig签名文件优先使用发布中显式声明的签名资产否则拼接BrowserDownloadURL .minisig分别下载二进制资产与签名verifyMinisignSignatureupdate.go用minisign.NewReader流式读取资产文件不整体载入内存随后调用reader.Verify(publicKey, sigData)验证签名verifyTrustedCommentupdate.go解析签名的 Trusted Comment提取其中file:name字段trustedCommentFile通过strings.CutPrefix解析并强制要求它与期望下载的文件名一致——这可以防止「签名有效但签的是另一个文件」的替换攻击全部通过后才打印 “Signature verified for” 并落盘任何一步失败都会清理已下载的临时文件与残留目标文件cleanupAssetFiles。minisign 的流式读取与校验实现位于 util/minisign/minisign.goNewReader于 L75、Verify于 L131。这一设计意味着即便更新服务器或镜像被中间人劫持只要无法获得 Sliver 官方私钥伪造或替换的更新包都会在签名校验阶段被拒绝。流程串联一次完整的 update 生命周期将上述机制串起来一次update命令的完整执行路径为VerboseVersionsCmd通过 gRPC 汇报客户端/服务器版本含编译时间、Go 版本、架构解析--insecure双重确认、--proxyurl.Parse校验、--timeout构造http.Client自定义Dial超时、TLSHandshakeTimeout、Proxy、TLSClientConfig按--force选择LatestRelease或CheckForUpdates内部走 GitHub Releases API semver 比较SLIVER_NO_UPDATE_CHECK可全局跳过有可用发布时按当前GOOS/GOARCH匹配sliver-server/sliver-client资产并展示大小经用户确认后进入下载下载阶段临时文件 进度条 最多 3 次指数退避重试 字节数校验随后用注入的 minisign 公钥验证签名与 Trusted Comment 的file:字段全部通过后原子替换落盘将当前时间戳写入last_update_check文件流程结束。整个模块把「版本对比、资产选择、安全下载」三层逻辑清晰地分离在 commands.go 与 update.go 中配合 updates.go 的发布查询、sliver-version.go 的构建信息注入构成了一个从检查到落地都具备版本语义与签名保障的完整更新链路——这也是在对抗模拟环境中长期运维 Sliver 客户端与服务器版本时最值得依赖的内置能力。【免费下载链接】sliverAdversary Emulation Framework项目地址: https://gitcode.com/gh_mirrors/sl/sliver创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表