freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

sliver源码分析 | 植入物生成逻辑
2024-09-03 18:52:09

引言

  • 项目概述:对开源的C2框架sliver进行源码分析,意图学习其原理。本篇分析sliver生成植入物如windows可执行文件exe和windows平台下的shellcode。

  • 目标与读者:网络安全兴趣爱好者、红队选手

准备工作

git clone https://github.com/BishopFox/sliver.git

vscode debug配置

如果需要对sliver-server进行调试可按照下面的设置
.vscode/launch.json中写入

{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "Debug Server",
        "type": "go",
        "request": "attach",
        "mode": "remote",
        "remotePath": "${workspaceFolder}",
        "port": 8844,
        "host": "127.0.0.1",
        "trace": "log"
      }
    ]
}

在项目根目录运行dlv进行调试

dlv debug \
    --build-flags="-tags osusergo,netgo,go_sqlite,server -ldflags='-X github.com/bishopfox/sliver/client/version.Version=1.1.2 -X github.com/bishopfox/sliver/client/version.CompiledAt=Never -X github.com/bishopfox/sliver/client/version.GithubReleasesURL=github.com -X github.com/bishopfox/sliver/client/version.GitCommit=aabbcc -X github.com/bishopfox/sliver/client/version.GitDirty=Dirty'" \
    --headless \
    --listen=:8844 \
    --api-version=2 \
    --log \
    github.com/bishopfox/sliver/server

定位generate

sliver终端构造https类型植入物exe的精简命令如下

generate beacon --http HOST:PORT --save beacon.exe

通过在vscode中搜索generate关键词,找到
client/command/generate/generate.go

func GenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
	name, config := parseCompileFlags(cmd, con)
	if config == nil {
		return
	}
	save, _ := cmd.Flags().GetString("save")
	if save == "" {
		save, _ = os.Getwd()
	}
	if external, _ := cmd.Flags().GetBool("external-builder"); !external {
		compile(config, save, con)
	} else {
		_, err := externalBuild(name, config, save, con)
		if err != nil {
			if err == ErrNoExternalBuilder {
				con.PrintErrorf("There are no external builders currently connected to the server\n")
				con.PrintErrorf("See 'builders' command for more information\n")
			} else if err == ErrNoValidBuilders {
				con.PrintErrorf("There are external builders connected to the server, but none can build the target you specified\n")
				con.PrintErrorf("Invalid target %s\n", fmt.Sprintf("%s:%s/%s", config.Format, config.GOOS, config.GOARCH))
				con.PrintErrorf("See 'builders' command for more information\n")
			} else {
				con.PrintErrorf("%s\n", err)
			}
			return
		}
	}
}

可以看到如果不用external-builder默认执行的是compile(config, save, con)

分析compile

func compile(config *clientpb.ImplantConfig, save string, con *console.SliverClient) (*commonpb.File, error) {
	if config.IsBeacon {
		interval := time.Duration(config.BeaconInterval)
		con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval)
	} else {
		con.PrintInfof("Generating new %s/%s implant binary\n", config.GOOS, config.GOARCH)
	}
	if config.ObfuscateSymbols {
		con.PrintInfof("%sSymbol obfuscation is enabled%s\n", console.Bold, console.Normal)
	} else if !config.Debug {
		con.PrintErrorf("Symbol obfuscation is %sdisabled%s\n", console.Bold, console.Normal)
	}

	start := time.Now()
	ctrl := make(chan bool)
	con.SpinUntil("Compiling, please wait ...", ctrl)
	//con.r(θωθ)p(θωθ)c.Generate()重点在这个方法
	generated, err := con.r(θωθ)p(θωθ)c.Generate(context.Background(), &clientpb.GenerateReq{
		Config: config,
	})
	ctrl <- true
	<-ctrl
	if err != nil {
		con.PrintErrorf("%s\n", err)
		return nil, err
	}

	elapsed := time.Since(start)
	con.PrintInfof("Build completed in %s\n", elapsed.Round(time.Second))
	if len(generated.File.Data) == 0 {
		con.PrintErrorf("Build failed, no file data\n")
		return nil, errors.New("no file data")
	}

	fileData := generated.File.Data
	if config.IsShellcode {
		if !config.SGNEnabled {
			con.PrintErrorf("Shikata ga nai encoder is %sdisabled%s\n", console.Bold, console.Normal)
		} else {
			con.PrintInfof("Encoding shellcode with shikata ga nai ... ")
			resp, err := con.r(θωθ)p(θωθ)c.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
				Encoder:      clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
				Architecture: config.GOARCH,
				Iterations:   1,
				BadChars:     []byte{},
				Data:         fileData,
			})
			if err != nil {
				con.PrintErrorf("%s\n", err)
			} else {
				con.Printf("success!\n")
				fileData = resp.GetData()
			}
		}
	}

	saveTo, err := saveLocation(save, generated.File.Name, con)
	if err != nil {
		return nil, err
	}

	err = os.WriteFile(saveTo, fileData, 0o700)
	if err != nil {
		con.PrintErrorf("Failed to write to: %s\n", saveTo)
		return nil, err
	}
	con.PrintInfof("Implant saved to %s\n", saveTo)
	return generated.File, err
}

可以看到整个方法进行了beacon判断、是否启用DEBUG、然后发送r(θωθ)p(θωθ)c请求,调用con.r(θωθ)p(θωθ)c.Generate()进行构造。构造完毕后根据构造结果是否是shellcode,进行SGNEnabled判断,从而决定是否使用Shikata ga nai encoder进行编码,最后将结果写入到--save指定的文件中,最后该函数返回文件名和错误信息。

那么分析重点就在下面的r(θωθ)p(θωθ)c调用中

generated, err := con.r(θωθ)p(θωθ)c.Generate(context.Background(), &clientpb.GenerateReq{
	Config: config,
})

分析r(θωθ)p(θωθ)c

这里直接使用vscode的CTRL+左键只能找到他的定义,不能找到实现。
定位到定义的位置是
protobuf/被干掉的词/services_gr(θωθ)p(θωθ)c.pb.go

package 被干掉的词

import (
	context "context"
	clientpb "github.com/bishopfox/sliver/protobuf/clientpb"
	commonpb "github.com/bishopfox/sliver/protobuf/commonpb"
	sliverpb "github.com/bishopfox/sliver/protobuf/sliverpb"
	gr(θωθ)p(θωθ)c "google.golang.org/gr(θωθ)p(θωθ)c"
	codes "google.golang.org/gr(θωθ)p(θωθ)c/codes"
	status "google.golang.org/gr(θωθ)p(θ
# 安全分析 # 源码 # C2 # 源码分析 # C2框架
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录