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"
)func main() {cli.Execute()
}

server/cli/cli.go

// Execute - Execute root command
func Execute() {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 normallyappDir := assets.GetRootAppDir() //makedir $HOME/.sliverlogFile := initConsoleLogging(appDir)defer logFile.Close()defer func() {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 consoleconsole.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 buildercompletion  Generate the autocompletion script for the specified shelldaemon      Force start server in daemon modeexport-ca   Export certificate authorityhelp        Help about any commandimport-ca   Import certificate authorityoperator    Generate operator configuration filesunpack      Unpack assets and exitversion     Print version and exitFlags:-h, --help   help for sliver-serverUse "sliver-server [command] --help" for more 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/
func GetRootAppDir() string {value := os.Getenv(envVarName)var dir stringif len(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 logging
func initConsoleLogging(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()defer func() {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()
func GetServerConfig() *ServerConfig {configPath := GetServerConfigPath()config := getDefaultServerConfig().....
//后面的内容就是读取configPath的路径的json格式的配置文件解析到config进行使用和保存
}
// GetServerConfigPath - File path to config.json
func GetServerConfigPath() string {appDir := assets.GetRootAppDir()serverConfigPath := filepath.Join(appDir, "configs", serverConfigFileName)serverConfigLog.Debugf("Loading config from %s", serverConfigPath)return serverConfigPath
}

GetServerConfigPath函数就是读取~/.sliver/config/server.json

func getDefaultServerConfig() *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 consoleconsole.Start()
}

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

database.json

至于数据库

package dbimport ("gorm.io/gorm"
)
// Client - Database Client
var Client = newDBClient()
// Session - Database session
func Session() *gorm.DB {return Client.Session(&gorm.Session{FullSaveAssociations: true,})
}

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

看看生成这个Client的newDBClient()

// newDBClient - Initialize the db client
func newDBClient() *gorm.DB {dbConfig := configs.GetDatabaseConfig()var dbClient *gorm.DBswitch 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 value
func GetDatabaseConfig() *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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/397987.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++][opencv]基于opencv实现photoshop算法图像旋转

【测试环境】 vs2019 opencv4.8.0 【效果演示】 【核心实现代码】 //图像旋转: src为原图像, dst为新图像, angle为旋转角度, isClip表示是采取缩小图片的方式 int imageRotate4(InputArray src, OutputArray dst, double angle, bool isClip) {Mat input src.…

【c++】类和对象 (中) (类的默认成员函数)

类的默认成员函数 在C中,如果你定义了一个类但没有显式地提供特定的成员函数(比如构造函数、析构函数、拷贝构造函数、拷贝赋值运算符等),编译器会为这些函数生成默认的实现。这些默认生成的成员函数称为类的默认成员函数。那么既…

C#学习笔记15:上位机助手_usercontrol窗体内嵌的应用

今日完善一下之前的上位机助手,做一个组合窗体内嵌的多功能助手软件应用, 与之前的上位机软件相比: 更注重控件能够随着窗体缩放而缩放变换,串口助手部分能自动后台检测串口设备,解决市面上大部分串口助手的打开初始化会卡顿的问题 ( 多线程后…

Linux服务管理-Nginx配置

静态解析主要解析html、css动态解析需要解析php 动态资源通过轮询分配到后端的Apache服务器处理 apache是同步阻塞,nginx是异步非阻塞

论文阅读笔记:Efficient Teacher: Semi-Supervised Object Detection for YOLOv5

Efficient Teacher: Semi-Supervised Object Detection for YOLOv5 1 背景1.1 动机1.2 问题 2 创新点3 方法4 模块4.1 伪标签分配4.2 Epoch Adapter 5 效果5.1 与SOTA方法对比5.2 消融实验 论文:https://arxiv.org/pdf/2302.07577v3.pdf 代码:https://g…

Python 常用内置函数

目录 1、enumerate函数 1.1、for循环中使用 1.2、enumerate指定索引的起始值 1.3、enumerate在线程中的作用 2、Map 函数 2.1、map()函数可以传多个迭代器对象 3、lambda表达式(匿名函数) 示例 4、sort函数和sorted函数 4.1、sort()函数 4.2、…

map和set的使用

关联式容器 在学习关联式容器之前&#xff0c;我们学习过的容器有vector、list、deque…这些容器称为序列式容器&#xff0c;单纯的存储数据存储的数据没有关联性。 即将学习的map 和set属于关联式容器&#xff0c;其里面存储的是<key, value>结构的键值对&#xff0c;…

制造知识普及(九)--企业内部物料编码(IPN)与制造商物料编码(MPN)

在日常的物料管理业务逻辑中&#xff0c;一物一码是物料管理的基本的业务规则&#xff0c;不管物料从产品开发还是仓库管理&#xff0c;甚至成本核算&#xff0c;都要遵循这个原则&#xff0c;才能保证产品数据的准确性&#xff0c;才具备唯一追溯的可行性。大部分企业都是这种…

某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]

文章目录 某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏…

C#数据类型转换

代码&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace Test05 {class Program{static void Main(string[] args){double db 2008;//声明一个double类型变量db&#xff0c;并初始化为2008object obj db;//对db…

JAVA实现判断小程序用户是否关注公众号

本文主要描述了判断小程序用户是否关注公众号的逻辑实现及部分代码 首先阐述一下大致流程&#xff1a; 1、在将小程序和公众号绑定至同一个微信开发平台下&#xff1b; 2、后端拉取公众号已关注用户列表&#xff0c;并获取其中每一个用户的unionID&#xff0c; 建立已关注用户…

OCR调研

OCR调研 一、介绍 OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;是一种将图像中的文字转换为计算机可处理格式的技术。OCR技术经历了从传统OCR到基于深度学习的OCR的转变。深度学习OCR技术通过模拟人脑神经元结构处理文本和图像数据&am…

MATLAB - 强化学习(Reinforcement Learning)

系列文章目录 前言 一、什么是强化学习&#xff1f; 强化学习是一种以目标为导向的计算方法&#xff0c;计算机通过与未知的动态环境交互来学习执行任务。这种学习方法能让计算机在没有人工干预和明确编程的情况下&#xff0c;做出一系列决策&#xff0c;使任务的累积奖励最大化…

cmake 编译教程

参考链接&#xff1a;cmake使用详细教程&#xff08;日常使用这一篇就足够了&#xff09;_cmake教程-CSDN博客 一、只有一个源文件的程序编译 首先在当前目录下创建两个文件 hello.cpp CMakeLists.txt &#xff08;注意CMakeLists大小写&#xff0c;不要写错了&#xff09; …

推荐一个优秀的 .NET MAUI 组件库

目录 前言 组件介绍 组件展示 布局 按钮 复选框 进度条 导航栏 组件地址 最后 前言 .NET MAUI 的发布&#xff0c;项目中可以使用这个新的跨平台 UI 框架来轻松搭建的移动和桌面应用。 为了帮助大家更快地构建美观且功能丰富的应用&#xff0c;本文将推荐一款优秀…

AcCode核心思路

文章目录 在线OJ项目核心思路1. 项目介绍2.预备知识理解多进程编程为啥采用多进程而不使用多线程?标准输入&标准输出&标准错误 3.项目实现题目API实现相关实体类定义新增/修改题目获取题目列表 编译运行编译运行流程 4.统一功能处理 在线OJ项目核心思路 1. 项目介绍 …

有序转化数组(LeetCode)

题目 给你一个已经 排好序 的整数数组 和整数 、 、 。对于数组中的每一个元素 &#xff0c;计算函数值 &#xff0c;请 按升序返回数组 。 解题 在时间复杂度为解决问题 def sortTransformedArray(nums, a, b, c):def f(x):return a * x * x b * x cn len(nums)result…

4个从阿里毕业的P7打工人,当起了包子铺的老板

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247483727&idx1&sndb05d8c1115a4539716eddd9fde4e5c9&chksmc0e47813f793f105017fb8551c9b996dc7782987e19efb166ab665f44ca6d900210e6c4c0281&scene21#wechat_redirect 《网安面试指南》h…

学生公寓电费信息管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;公寓管理员管理&#xff0c;学生管理&#xff0c;楼层信息管理&#xff0c;用电情况管理&#xff0c;缴费清单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;用电情况…

【数据结构】六、图:4.图的遍历(深度优先算法DFS、广度优先算法BFS)

三、基本操作 文章目录 三、基本操作1.图的遍历1.1 深度优先遍历DFS1.1.1 DFS算法1.1.2 DFS算法的性能分析1.1.3 深度优先的生成树和生成森林 1.2 广度优先遍历BFS1.2.1 BFS算法1.2.2 BFS算法性能分析1.2.3 广度优先的生成树和生成森林 1.3 图的遍历与图的连通性 1.图的遍历 图…