golang sliver二次开发自定义命令(格式乱后面再调)

准备工作
sliver客户端和服务端之间命令的通信采用的grpc, 服务端和和植入程序通信使用的protobuf,所以在开发之前需要了解 grpc和protobuf, 相关文档:
https://jergoo.gitbooks.io/go-grpc-practice-guide/content/chapter2/hello-grpc.html
https://jergoo.gitbooks.io/go-grpc-practice-guide/content/chapter1/protobuf.html
安装grpc protobuf相关工具:
https://jergoo.gitbooks.io/go-grpc-practice-guide/content/chapter1/install.html

定义自定义rpc服务

首先定义proto文件中的服务和相关数据类型:
在文件 sliver/protobuf/rpcpb/services.proto 增加PortScan方法:
rpc PortScan(sliverpb.PortScanReq) returns(sliverpb.PortScanResp);

然后在 sliver/protobuf/sliverpb/sliver.proto 增加 PortScan的请求参数和响应:

// 端口扫描请求参数
message PortScanReq {
  string Targets = 1;
  string Ports = 2;
  commonpb.Request Request = 9;
}

// 端口扫描返回数据
message PortScanResp {
  repeated string result = 1;
  commonpb.Response Response = 9;
}

编译proto文件
在 sliver/Makefile 已经有写好的makefile, 直接执行make pb则可以自动重新编译.proto文件

如图所示,已经成功生成对应的go代码 sliver/protobuf/rpcpb/services_grpc.pb.go

在server端编写rpc服务go代码
新建文件 sliver/server/rpc/rpc-portscan.go, 写入以下代码:

package rpc

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

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


这时候服务端定义就完成了
添加客户端命令
注意: 客户端和服务端命令是公用的,只需在客户端中定义相应命令即可
在文件 sliver/client/constants/constants.go 增加我们的命令port_scan
然后创建文件夹 sliver/client/command/portscan 新建portscan.go文件,加入以下代码:


package portscan

import (
	"context"
	"fmt"
	"github.com/bishopfox/sliver/client/console"
	"github.com/bishopfox/sliver/protobuf/sliverpb"
	"github.com/desertbit/grumble"
)

func PortScanCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
	targets := ctx.Args.String("targets")
	ports := ctx.Args.String("ports")
	_, _ = con.Println(fmt.Sprintf("正在扫描 %s, 端口: %s", targets, ports))
	resp, err := con.Rpc.PortScan(context.Background(), &sliverpb.PortScanReq{
		Targets: targets,
		Ports:   ports,
		Request: con.ActiveTarget.Request(ctx),
	})
	if err != nil {
		_, _ = con.PrintErrorf("%s\n", err)
		return
	}
	_, _ = con.Println("端口扫描完成, 结果: ")
	for _, line := range resp.Result {
		_, _ = con.Println(line)
	}
}

然后在 sliver/client/command/commands.go 定义portscan命令


// 自定义端口扫描命令
	con.App.AddCommand(&grumble.Command{
		Name:     consts.PortScanStr,
		Help:     "自定义端口扫描命令",
		LongHelp: help.GetHelpFor([]string{consts.PortScanStr}),
		Flags: func(f *grumble.Flags) {
			f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
		},
		Args: func(a *grumble.Args) {
			a.String("targets", "待扫描的目标, 例:192.168.1.1,8.8.8.8")
			a.String("ports", "待扫描的端口,例: 80,443,22", grumble.Default("80,443,22"))
		},
		Run: func(ctx *grumble.Context) error {
			_, _ = con.Println()
			portscan.PortScanCmd(ctx, con)
			_, _ = con.Println()
			return nil
		},
		HelpGroup: consts.SliverHelpGroup,
	})

这时候客户端和服务端交互相关代码已经全部编写完毕了,执行make 重新编译客户端和服务端


这时候可以看到portscan命令已经成功加入进去了,但是还没有在植入程序实现具体的端口扫描功能,所以返回 rpc error: code = Unknown desc = unknown message type

在植入程序中实现portscan功能
修改 sliver/protobuf/sliverpb/constants.go 增加消息类型常量,根据植入程序收到的消息类型返回MsgPortScan

创建目录 sliver/implant/sliver/portscan/ 新建port_scan.go文件,代码如下

package portscan

import (
	"fmt"
	"github.com/panjf2000/ants/v2"
	"net"
	"strings"
	"sync"
	"time"
)

type Task struct {
	Ip   string
	Port string
}

func isOpen(ip, port string) bool {
	_, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, port), 4*time.Second)
	if err != nil {
		return false
	}
	return true
}

func ScanPort(targets, ports string) []string {
	scanTargets := strings.Split(targets, ",")
	scanPorts := strings.Split(ports, ",")
	var ret []string
	var lock sync.Mutex
	wg := new(sync.WaitGroup)
	defer ants.Release()
	p, _ := ants.NewPoolWithFunc(20, func(param interface{}) {
		defer wg.Done()
		task := param.(Task)
		if isOpen(task.Ip, task.Port) {
			lock.Lock()
			ret = append(ret, fmt.Sprintf("%s:%s", task.Ip, task.Port))
			lock.Unlock()
		}
	})

	defer p.Release()
	for _, target := range scanTargets {
		for _, port := range scanPorts {
			p.Invoke(Task{
				Ip:   target,
				Port: port,
			})
			wg.Add(1)
		}
	}
	wg.Wait()
	return ret

}

然后在 sliver/implant/sliver/handlers/rpc-handlers.go 添加如下代码


// 端口扫描
func portscanHandler(data []byte, resp RPCResponse) {
	sc := &sliverpb.PortScanReq{}
	err := proto.Unmarshal(data, sc)
	if err != nil {
		// {{if .Config.Debug}}
		log.Printf("error decoding message: %v", err)
		// {{end}}
		return
	}
	res := &sliverpb.PortScanResp{}
	res.Result = portscan.ScanPort(sc.Targets, sc.Ports)
	data, err = proto.Marshal(res)

	resp(data, err)
}

如图所示,调用了porscan具体的功能,并将结果通过protobuf序列化并返回给服务端

然后需要将功能注册到对应的操作系统,例如我的功能只能在macos下运行,则需要在对应的文件下注册功能
sliver/implant/sliver/handlers/handlers_操作系统类型.go

posted @ 2024-08-07 11:45  干炸小黄鱼  阅读(23)  评论(0编辑  收藏  举报