- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
builders是 Sliver 客户端控制台中的一个命令组,用于列出当前已注册到 Sliver 服务器上的所有外部构建机(external builders)。外部构建机允许 Sliver 服务器将植入体(implant)的编译任务卸载到外部机器上执行,从而减轻服务器自身负载并实现多平台、多架构的并行构建。阅读本文后,你将掌握builders命令的注册机制、RPC 数据链路、输出字段含义,以及服务器端如何通过内存注册表维护这些构建机的生命周期。
模块定位:client/command/builders 包
在 Sliver 客户端源码中,builders命令组实现在 client/command/builders 目录下,由两个 Go 文件构成,职责划分非常清晰:
- builders.go:向服务器 RPC 发起请求获取外部构建机元数据,并将结果格式化后渲染到控制台;
- commands.go:负责将
builders命令注册到 Cobra 命令树中,绑定标志(flags)与帮助文本。
从包结构上可以推断,Sliver 客户端采用了"命令注册与命令执行分离"的模块化设计:每个命令组目录下通常都有commands.go(定义命令、标志和帮助)与若干业务文件(承载具体执行逻辑),builders包正是这一模式的典型范例。
命令注册:Cobra 命令树中的 builders
commands.go 中的Commands函数返回一个*cobra.Command切片,定义了builders命令的完整形态:
func Commands(con *console.SliverClient) []*cobra.Command { buildersCmd := &cobra.Command{ Use: consts.BuildersStr, Short: "List external builders", Long: help.GetHelpFor([]string{consts.BuildersStr}), Run: func(cmd *cobra.Command, args []string) { BuildersCmd(cmd, con, args) }, GroupID: consts.PayloadsHelpGroup, } flags.Bind("builders", false, buildersCmd, func(f *pflag.FlagSet) { f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds") }) return []*cobra.Command{buildersCmd} }几个值得注意的实现细节:
- 命令名来源:
Use字段直接引用了常量consts.BuildersStr,其值为"builders"(定义于 client/constants/constants.go)。整个客户端命令体系通过client/constants统一管理命令名字符串,避免硬编码散落各处。 - 命令分组:
GroupID: consts.PayloadsHelpGroup将该命令归入"Payloads"帮助分组,与generate、profiles等命令并列,便于用户在help输出中按主题定位。 - 唯一标志:该命令只暴露一个
--timeout(别名-t)标志,用于指定 gRPC 调用的超时秒数,默认值来自flags.DefaultTimeout(由 client/command/flags 统一管理)。由于builders是只读的元数据查询命令,因此不需要任何过滤或分页参数。
命令的长帮助文本定义在 client/command/help/long-help.go,明确说明了其用途:"Lists external builders currently registered with the server",并指出外部构建机允许 Sliver 服务器将植入体构建任务卸载到外部机器上执行。
执行逻辑:一次 RPC 调用完成元数据拉取与展示
当用户在 Sliver 控制台中输入builders时,最终执行的是 builders.go 中的BuildersCmd函数:
func BuildersCmd(cmd *cobra.Command, con *console.SliverClient, args []string) { builders, err := con.Rpc.Builders(context.Background(), &commonpb.Empty{}) if err != nil { con.PrintErrorf("%s", err) return } if len(builders.Builders) == 0 { con.PrintInfof("No external builders connected to server\n") } else { PrintBuilders(builders.Builders, con) } }整个执行链路清晰简洁:
- 通过客户端持有的 gRPC 连接
con.Rpc调用Builders方法,请求参数是空的commonpb.Empty——该命令不需要任何过滤条件; - 若 RPC 返回错误,直接以错误样式打印(
PrintErrorf); - 若返回的构建机列表为空,打印提示信息 "No external builders connected to server";
- 否则调用
PrintBuilders渲染表格输出。
对应的服务器端 RPC 实现在 server/rpc/rpc-generate.go:
func (rpc *Server) Builders(ctx context.Context, _ *commonpb.Empty) (*clientpb.Builders, error) { return &clientpb.Builders{Builders: core.AllBuilders()}, nil }可以看到,服务端只是从核心内存注册表中取出当前全部构建机并返回,没有任何磁盘或数据库操作——这印证了外部构建机的元数据是纯内存态、实时维护的。
表格渲染:五列信息揭示构建机全貌
PrintBuilders(builders.go)使用go-pretty/v6表格库渲染输出,表头包含五个字段:
| 列名 | 含义 | 数据来源 |
|---|---|---|
Name | 构建机注册名称(全局唯一) | builder.Name |
Operator | 注册该构建机的操作员身份 | builder.OperatorName |
Templates | 支持的植入体模板列表(逗号分隔) | builder.Templates |
Platform | 构建机自身的操作系统/架构 | builder.GOOS / builder.GOARCH |
Compiler Targets | 可编译的目标平台列表(每个占一行) | builder.Targets |
其中两个字段的格式化逻辑值得展开:
- Compiler Targets:每个目标被格式化为
fmt.Sprintf("%s:%s/%s", target.Format, target.GOOS, target.GOARCH),即"输出格式:操作系统/架构"的组合,例如EXECUTABLE:windows/amd64或SHARED_LIB:linux/arm64。多个目标通过换行符\n连接,在表格中纵向排列。 - Platform:直接使用构建机自身的
GOOS/GOARCH拼接展示。
表格样式通过settings.GetTableStyle(con)获取,会跟随用户在控制台中配置的终端主题,保证输出风格与其他命令一致。
数据结构:protobuf 层的 Builder 定义
客户端展示的所有字段都来自 protobuf 消息Builder,其定义位于 protobuf/clientpb/client.proto:
message Builders { repeated Builder Builders = 1; } message Builder { string Name = 1; string OperatorName = 2; string GOOS = 3; // The builder's OS string GOARCH = 4; // The builder's Arch repeated string Templates = 5; repeated CompilerTarget Targets = 6; repeated CrossCompiler CrossCompilers = 7; }该消息引用了两个子类型(同样定义在 client.proto):
message CompilerTarget { string GOOS = 1; // The server's OS string GOARCH = 2; // The server's Arch OutputFormat Format = 3; } message CrossCompiler { string TargetGOOS = 1; // The server's OS string TargetGOARCH = 2; // The server's Arch string CCPath = 3; string CXXPath = 4; }注意CrossCompiler字段(交叉编译器路径)并未在客户端表格中展示,但从源码结构看,它在builder向服务器注册自身能力时会被携带,属于构建机能力描述的一部分。此外,同一 proto 文件还定义了ExternalGenerateReq(client.proto),携带ImplantConfig、BuilderName、Name三个字段,用于将植入体构建请求定向转发给指定名称的外部构建机——这就是builders查询结果与外部构建功能之间的衔接点。
服务器端实现:内存注册表与连接生命周期
外部构建机的注册与注销由 server/core/builders.go 中的核心注册表统一管理:
var ( // ClientID -> *clientpb.Builder builders = &sync.Map{} ErrDuplicateExternalBuilderName = errors.New("builder name must be unique, this name is already in use") )该模块提供了四个线程安全的基本操作(基于sync.Map):
AddBuilder:以构建机名称为 key 执行LoadOrStore,若名称已被占用则返回ErrDuplicateExternalBuilderName;GetBuilder:按名称查询单个构建机;AllBuilders:遍历返回全部构建机切片(buildersRPC 的数据源);RemoveBuilder:按名称删除。
构建机注册的完整流程在 server/rpc/rpc-generate.go 的BuilderRegister流式 RPC 中实现,关键步骤包括:
- 从 gRPC 上下文(mTLS 证书)中提取操作员身份写入
OperatorName——这解释了控制台表格中Operator列的来源; - 校验
Name非空,缺失则返回InvalidArgument错误; - 调用
core.AddBuilder注册,名称冲突时返回ErrDuplicateExternalBuilderName(对应的 gRPC 错误映射见 server/rpc/errors.go); - 注册成功后订阅事件代理
core.EventBroker,仅向该构建机转发ExternalBuildEvent类型的构建任务事件(rpc-generate.go); - 通过
defer确保流关闭(stream.Context().Done())时自动注销构建机并退订事件。
这种"注册即订阅、断连即注销"的设计意味着:构建机列表是实时的,任何构建机掉线后都会立刻从服务器注册表中移除,builders命令查询到的永远是在线构建机集合。
外部构建事件:从查询到任务的闭环
builders命令解决的是"发现可用构建机"问题,而完整的外部构建闭环还依赖事件机制。构建任务被创建时,服务器会为每个构建记录"构建机/操作员"绑定关系,这由 server/core/externalbuilds.go 中的ExternalBuildAssignment结构体跟踪(TrackExternalBuildAssignment/GetExternalBuildAssignment/RemoveExternalBuildAssignment),对应单元测试见 server/core/externalbuilds_test.go。
构建事件的处理逻辑位于 server/rpc/rpc-generate.go 与 server/builder/builder.go:
- 服务器通过
ExternalBuildEvent事件将构建请求定向推送给目标构建机(按targetBuilderName匹配,见 rpc-generate.go); - 外部构建机会回传
ExternalBuildProgressEvent、ExternalBuildFailedEvent、ExternalBuildCompletedEvent等事件(见 builder.go 中的事件分发逻辑); - 构建完成或失败后,服务器会清理对应的外部构建分配(
RemoveExternalBuildAssignment)。
由此形成完整的调用链:外部构建机注册(BuilderRegister)→ 服务器内存注册表(core/builders.go)→ 客户端查询(builders 命令)→ 定向构建任务(ExternalGenerateReq + ExternalBuildEvent)→ 构建结果回传。builders命令正是这条链路中唯一面向用户的"构建机目录"视图。
实战速查
| 场景 | 操作 |
|---|---|
| 查看所有在线外部构建机 | 在 Sliver 控制台输入builders |
| 指定 gRPC 调用超时 | builders --timeout 30(或-t 30) |
| 在植入体生成时指定构建机 | generate命令配合--builder <名称>(对应 proto 中的BuilderName字段) |
| 查看命令帮助 | help builders(长帮助定义见 long-help.go) |
使用前提:builders命令的输出结果取决于服务器当前在线的外部构建机数量,若没有任何外部构建机接入,命令会提示 "No external builders connected to server"。外部构建机本身需要通过 Sliver 的 builder 二进制连接服务器完成注册,注册后其元数据(名称、操作员、模板、平台、编译目标)才会出现在本命令的表格中。
延伸阅读
如需深入了解外部构建机制的完整实现,建议按以下路径继续阅读仓库源码:
- 客户端命令执行与表格渲染:client/command/builders/builders.go、client/command/builders/commands.go
- protobuf 数据结构定义:protobuf/clientpb/client.proto
- 服务器端注册表:server/core/builders.go
- 外部构建分配跟踪与测试:server/core/externalbuilds.go、server/core/externalbuilds_test.go
- 注册与构建事件 RPC:server/rpc/rpc-generate.go、server/builder/builder.go
- 命令常量与帮助文本:client/constants/constants.go、client/command/help/long-help.go
- 网络安全
【免费下载链接】sliver
Adversary Emulation Framework
相关推荐
Hyperledger Fabric 外部构建器(External Builders and Launchers)原理与实战指南
Hyperledger Fabric 外部构建器(External Builders and Launchers)原理与实战指南 本指南围绕 Hyperledg
区块链密码学Authelia authelia-scripts suites external 命令详解:外部测试套件的管理与执行
Authelia authelia scripts suites external 命令详解:外部测试套件的管理与执行 导读 authelia scripts
后端认证鉴权单点登录身份认证应用安全Yi-1.5-6B-Chat模型深度解析:从架构到性能的完整评测指南
Yi 1.5 6B Chat模型深度解析:从架构到性能的完整评测指南 Yi 1.5 6B Chat 是一款基于Llama架构优化的中文对话大语言模型,专为中文用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考