sliver源码分析 | 植入物生成逻辑
本文由
创作,已纳入「FreeBuf原创奖励计划」,未授权禁止转载
引言
项目概述:对开源的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(θ
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
文章目录