0


sliver源码分析-初始化以及脚手架

引言

  • 项目概述:对开源的C2框架sliver进行源码分析,意图学习其原理。本篇分析sliver的入口以及脚手架,和基本的配置文件
  • 目标与读者:网络安全兴趣爱好者

准备工作

  • 源码路径BishopFox/sliver: Adversary Emulation Framework (github.com)
git clone https://github.com/BishopFox/sliver.git
  • go语言环境 Download and install - The Go Programming Language
  • vscode Download Visual Studio Code - Mac, Linux, Windows

入口点

由于sliver是CS架构的系统,而且主要功能在服务端所以分析目标是sliver-server
这里查看到入口点的内容只有运行cli.Execute()
server/main.go

import("github.com/bishopfox/sliver/server/cli")funcmain(){
    cli.Execute()}

server/cli/cli.go

// Execute - Execute root commandfuncExecute(){if err := rootCmd.Execute(); err !=nil{
        fmt.Println(err)
        os.Exit(1)}}

这里的cli.Execute()运行的就是rootCmd.Execute(),所以要重点关注rootCmd

跳转到github.com/bishopfox/sliver/server/cli,发现其使用的脚手架框架是github.com/spf13/cobra

如果对cobra不太熟悉,可以看看这个UP做的视频
https://www.bilibili.com/video/BV1ka4y177iK
Cobra 是由 Go 团队成员 spf13 为 Hugo 项目创建的,并已被许多流行的 Go 项目所采用,如 Kubernetes、Helm、Docker (distribution)、Etcd 等。
简而言之就是可以方便的编写带有参数的命令行程序。

rootCmd

这里摆上server/cli/cli.go的部分源码

var rootCmd =&cobra.Command{
    Use:"sliver-server",
    Short:"",
    Long:``,
    Run:func(cmd *cobra.Command, args []string){// Root command starts the server normally

        appDir := assets.GetRootAppDir()//makedir $HOME/.sliver
        logFile :=initConsoleLogging(appDir)defer logFile.Close()deferfunc(){if r :=recover(); r !=nil{
                log.Printf("panic:\n%s", debug.Stack())
                fmt.Println("stacktrace from panic: \n"+string(debug.Stack()))
                os.Exit(99)}}()

        assets.Setup(false,true)
        certs.SetupCAs()
        certs.SetupWGKeys()
        cryptography.AgeServerKeyPair()
        cryptography.MinisignServerPrivateKey()
        c2.SetupDefaultC2Profiles()

        serverConfig := configs.GetServerConfig()
        listenerJobs, err := db.ListenerJobs()if err !=nil{
            fmt.Println(err)}

        err =StartPersistentJobs(listenerJobs)if err !=nil{
            fmt.Println(err)}if serverConfig.DaemonMode {
            daemon.Start(daemon.BlankHost, daemon.BlankPort, serverConfig.DaemonConfig.Tailscale)}else{
            os.Args = os.Args[:1]// Hide cli from grumble console
            console.Start()}},}

由于这个是rootCmd,所以其中Use: “sliver-server"表示这个命令本身。cobra在-h等参数中会告诉这个命令是什么命令,这里就是指的是"sliver-server”。

└─$ sliver-server -h
Usage://Use:   "sliver-server" 指的就这下面的例子,用于提示这个命令是什么
  sliver-server [flags]  
  sliver-server [command]

Available Commands:
  builder     Start the process as an external builder
  completion  Generate the autocompletion script for the specified shell
  daemon      Force start server in daemon mode
  export-ca   Export certificate authority
  help        Help about any command
  import-ca   Import certificate authority
  operator    Generate operator configuration files
  unpack      Unpack assets and exit
  version     Print version and exit

Flags:
  -h, --helphelpfor sliver-server

Use "sliver-server [command] --help"formore information about a command.
Run: func(cmd *cobra.Command, args []string) 

是这个命令(sliver-server)需要运行的内容
首先执行

appDir := assets.GetRootAppDir()
// GetRootAppDir - Get the Sliver app dir, default is: ~/.sliver/funcGetRootAppDir()string{
    value := os.Getenv(envVarName)var dir stringiflen(value)==0{
        user,_:= user.Current()
        dir = filepath.Join(user.HomeDir,".sliver")}else{
        dir = value
    }if_, err := os.Stat(dir); os.IsNotExist(err){
        err = os.MkdirAll(dir,0700)if err !=nil{
            setupLog.Fatalf("Cannot write to sliver root dir %s", err)}}return dir
}

可以从上面的注释看到这个就是在当前用户的home目录下创建

.sliver

目录

然后再执行

logFile := initConsoleLogging(appDir)
// Initialize loggingfuncinitConsoleLogging(appDir string)*os.File {
    log.SetFlags(log.LstdFlags | log.Lshortfile)
    logFile, err := os.OpenFile(filepath.Join(appDir,"logs", logFileName), os.O_RDWR|os.O_CREATE|os.O_APPEND,0o600)if err !=nil{
        log.Fatalf("Error opening file: %v", err)}
    log.SetOutput(logFile)return logFile
}

其中

logFileName = "console.log" 所以该函数就是创建

~/.sliver/logs/console.log`, 并返回这个文件到变量logFile
接着执行下面的两个函数

defer logFile.Close()deferfunc(){if r :=recover(); r !=nil{
        log.Printf("panic:\n%s", debug.Stack())
        fmt.Println("stacktrace from panic: \n"+string(debug.Stack()))
        os.Exit(99)}}()

前者

defer logFile.Close()

表示在当前函数生存期最后把logFile关闭
后者是使用

recover()

函数确认是否出现panic,如果没有产生panic,r的值就是nil,如果产生了panic,就用后面的语句对panic进行处理
这里要注意的是 先defer后调用,有点类似于压栈操作

后面接着一系列初始化操作

assets.Setup(false,true)//assets init
certs.SetupCAs()//ca init
certs.SetupWGKeys()//wireguard key init
cryptography.AgeServerKeyPair()//Get teh server's ECC key pair
cryptography.MinisignServerPrivateKey()//Get the server's minisign key pair
c2.SetupDefaultC2Profiles()

第一个

assets.Setup(false, true)

,对各种资源进行初始化,例如开头的banner。

certs.SetupCAs() 

初始化了CA证书

certs.SetupWGKeys() 

初始化了wireguard key

cryptography.AgeServerKeyPair() 

初始化了ECC秘钥对

cryptography.MinisignServerPrivateKey()

初始化minisign秘钥对

c2.SetupDefaultC2Profiles()

初始化默认的C2Profiles

配置文件

server.json

首先便是服务端的配置文件

serverConfig := configs.GetServerConfig()
funcGetServerConfig()*ServerConfig {
    configPath :=GetServerConfigPath()
    config :=getDefaultServerConfig().....//后面的内容就是读取configPath的路径的json格式的配置文件解析到config进行使用和保存}
// GetServerConfigPath - File path to config.jsonfuncGetServerConfigPath()string{
    appDir := assets.GetRootAppDir()
    serverConfigPath := filepath.Join(appDir,"configs", serverConfigFileName)
    serverConfigLog.Debugf("Loading config from %s", serverConfigPath)return serverConfigPath
}

GetServerConfigPath函数就是读取

~/.sliver/config/server.json
funcgetDefaultServerConfig()*ServerConfig {return&ServerConfig{
        DaemonMode:false,
        DaemonConfig:&DaemonConfig{
            Host:"",
            Port:31337,},
        Logs:&LogConfig{
            Level:int(logrus.InfoLevel),
            GRPCUnaryPayloads:false,
            GRPCStreamPayloads:false,},
        CC:map[string]string{},
        CXX:map[string]string{},}}

getDefaultServerConfig函数是返回一个默认的config内容

serverConfig := configs.GetServerConfig()

最后执行的结果就是获取

~/.sliver/config/server.json

的内容给到变量serverConfig
这里可以看下默认的config内容的样子

└─$ cat ~/.sliver/configs/server.json  
{"daemon_mode": false,
    "daemon":{"host":"",
        "port":31337,
        "tailscale":false},
    "logs":{"level":4,
        "grpc_unary_payloads": false,
        "grpc_stream_payloads": false,
        "tls_key_logger":false},
    "watch_tower": null,
    "go_proxy":"",
    "cc":{},
    "cxx":{}}

接着代码是

listenerJobs, err := db.ListenerJobs()if err !=nil{
    fmt.Println(err)}

err =StartPersistentJobs(listenerJobs)if err !=nil{
    fmt.Println(err)}

意思是获取数据库中保存的监听任务,也就是说,就算服务down了,重启自动就从数据库读取任务继续运行,或者说如果忘记结束job,这个job就一直跑着

然后的代码是

if serverConfig.DaemonMode {
    daemon.Start(daemon.BlankHost, daemon.BlankPort, serverConfig.DaemonConfig.Tailscale)}else{
    os.Args = os.Args[:1]// Hide cli from grumble console
    console.Start()}

查看服务配置文件是否配置守护进程,也就是配成service,如果有配置成守护进程,就监听端口可以进行多人协同。

database.json

至于数据库

package db

import("gorm.io/gorm")// Client - Database Clientvar Client =newDBClient()// Session - Database sessionfuncSession()*gorm.DB {return Client.Session(&gorm.Session{
        FullSaveAssociations:true,})}

可以看到有一个导出的Client和Session()

看看生成这个Client的newDBClient()

// newDBClient - Initialize the db clientfuncnewDBClient()*gorm.DB {
    dbConfig := configs.GetDatabaseConfig()var dbClient *gorm.DB
    switch dbConfig.Dialect {case configs.Sqlite:
        dbClient =sqliteClient(dbConfig)case configs.Postgres:
        dbClient =postgresClient(dbConfig)case configs.MySQL:
        dbClient =mySQLClient(dbConfig)default:panic(fmt.Sprintf("Unknown DB Dialect: '%s'", dbConfig.Dialect))}.....}

首先从dbConfig := configs.GetDatabaseConfig()获取配置文件
然后根据配置文件去连接数据库

// GetDatabaseConfig - Get config valuefuncGetDatabaseConfig()*DatabaseConfig {
    configPath :=GetDatabaseConfigPath()
    config :=getDefaultDatabaseConfig()......}

和前面server.json的函数相似
不过

GetDatabaseConfigPath()

读取的是`~/.sliver/config/database.json

看一下默认的内容

└─$ cat ~/.sliver/configs/database.json 
{"dialect":"sqlite3",
    "database":"",
    "username":"",
    "password":"",
    "host":"",
    "port":0,
    "params": null,
    "max_idle_conns":10,
    "max_open_conns":100,
    "log_level":"warn"}

欢迎来关注我的公众号 GEEK-DREAM

标签: go 网络安全 安全

本文转载自: https://blog.csdn.net/witwitwiter/article/details/141144321
版权归原作者 suqerbrave 所有, 如有侵权,请联系我们删除。

“sliver源码分析-初始化以及脚手架”的评论:

还没有评论