> For the complete documentation index, see [llms.txt](https://wbglil.gitbook.io/cobalt-strike/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wbglil.gitbook.io/cobalt-strike/cobalt-strike-yuan-li-jie-shao/cs-mu-biao-shang-xian-guo-cheng.md).

# CS Beacon通信分析

### 前言

前面几篇基本也把staging payload(分阶段)和stageless payload(无阶段)说过了，其实所谓的分阶段就是所谓的分离这个应该很多人都用过，远程加载cs或msf shellcode就是这个意思，只不过很多人可能远程加载执行是stager（分阶段payload里的第一阶段），而stager并非最终目标它也只是用来加载执行stage的，stage才是最终目标。关于加载执行过程什么的基本上也说完了，剩下的就该说说cs和Beacon之间的通信了

### 正文

关于Beacon的通信其实应该是分成3.x和4.x两个部分来写，我这里就先以4.x为例，等日后有时间了补上3.x的

如果你用过CrossC2这类工具你应该知道这类工具在使用时一定需要.cobaltstrike.beacon\_keys文件，这是因为cobaltstrike在与Beacon通信时是使用的RSA非对称加密，而.cobaltstrike.beacon\_keys文件里存储了一个序列化对象这个对象中包含着一个密钥对里面存储着RSA公私钥

![beacon\BeaconSetup.java](/files/-MIwbegtoJ3N4xV0GJmT)

为了方便操作最好使用以下c2配置，并且在生成Beacon时请使用http

```
set sleeptime "10000";

set jitter    "0";

set maxdns    "255";

set sample_name "Cobalt Strike Beacon (Default)";

http-get {
	set uri "/pixel";

	client {
		metadata {
			base64;
			header "Cookie";
		}
	}

	server {
		header "Content-Type" "application/octet-stream";
		output {
			base64;
			print;
		}
	}
}


http-post {
	set uri "/submit.php";

	client {
		header "Content-Type" "application/octet-stream";

		# transmit our session identifier as /submit.php?id=[identifier]
		id {
			parameter "id";
		}

		# post our output with no real changes
		output {
			base64;
			print;
		}
	}

	# The server's response to our HTTP POST
	server {
		header "Content-Type" "text/html";

		# this will just print an empty string, meh...
		output {
			base64;
			print;
		}
	}
}

```

配置完成后生成一个Beacon（注：请使用无阶段），开启Wireshark然后运行Beacon查看流量

![运行后目标机上线](/files/-MIx9nn1LUrvHVAuCqJt)

![通信流量](/files/-MIx91EjBpOpPmGS9LX1)

这就是Beacon回连时提交的元数据

![c2配置文件选择base64就是为了方便复制和更直观的看到](/files/-MIx9TJ5g6bu9hjeuQ6Y)

我们把这个拿去解密一下

![](/files/-MIxAW9HCHHX_COq4Ye7)

虽然可以看到部分信息，但是想要更准确的解析我们就需要去看cs的代码逆出通信格式

### 元数据

HTTP Beacon每次回连发送元数据请求任务时使用的是GET方法，Cobalt Strike关于Beacon GET处理的核心代码在BeaconHTTP里，如图所示

![代码局部截图](/files/-MJvS-o2jx8Lj8wCazKF)

元数据的格式解析就在process\_beacon\_metadata函数里，因为代码过长我就展示一下部分代码

![代码局部截图](/files/-MJvTHJMK13BRoKu2HCu)

![调用BeaconEntry传入解密后的元数据](/files/-MJvTUMOiM1ETKzO4SKJ)

BeaconEntry里面正式开始对元数据进行解析

![代码局部截图](/files/-MJvTqMEchLWOBTWfCdN)

基本元数据的处理过程就是这样，具体详细的过程请自行逆向查看这里就不在细写了

我这里根据逆向出来的结构写了个简单的脚本按照相同的格式进行解析（注：本页所有脚本代码会同一放到本页最后）

![](/files/-MJvUKmHiGvATHlIXzJ7)

我们主要关注的是AES key和HMAC key因为这两个和Beacon通信密切相关

这里我需要补充一点就是这个AES key和HMAC key具体请看process\_beacon\_metadata函数和registerKey函数

![process\_beacon\_metadata](/files/-MK-omtRLwYYeFwSx_hr)

![registerKey](/files/-MK-pAGnA8NN99Fkvtki)

很明显能看出来Beacon并不是直接发送AES key和HMAC key而且发送一个十六个字节的字符串然后cs计算这个字符串的哈希值（32位），这个哈希值的前16位作为AES key后16位作为HMAC key基本上需要补充的就这么多（补充这个主要因为下面我说了，*而AES密钥则是Beacon随机生成的然后通过RSA交换AES密钥*，这句话所以为了避免误解我这里提前解释一下）

### Beacon接收任务

Beacon的元数据传输过程中虽然使用的是RSA算法，但是Beacon任务的传输使用的却是AES算法加密的，而AES密钥则是Beacon随机生成的然后通过RSA交换AES密钥。（这也算是一种常用的密钥交换方法，通过RSA非对称加密算法传输AES对称加密算法的密钥最后使用AES算法加密通信）

关于发送任务的代码还是在BeaconHTTP里，处理完元数据就开始判断Beacon任务列队里是否有任务

![](/files/-MK-GPTAPN8oPh8qTHdd)

encrypt函数的作用就是用来加密任务数据的具体代码如图它的参数就两个Beacon id和任务数据。Beacon id用于获取Beacon会话对应AES密钥，然后使用AES加密任务数据

![](/files/-MK-HBw9ID17nK5xQ0Ij)

这里我同样写了一个脚本用来解密和解析任务数据格式

![执行shell whoami时发送的任务数据](/files/-MK-KAQemTsGC0hm3mEB)

*关于这个任务Data其实它也是有格式的，不同任务格式也不同，这个具体要看是任务数据生成过程，不过这个部分属于第三方客户端实现部分，因为在实现第三方客户端时除了要解密数据还要对任务数据的格式进行解析然后执行操作并返回结果*

### Beacon数据回传

Beacon执行完任务，会在休眠时间结束后通过POST回传任务结果，在整个，任务的交换过程中用的全是AES算法

POST核心处理代码同样在BeaconHTTP里，具体如图所示

![](/files/-MK-LbHlY3nc7x7ROdEg)

![](/files/-MK-MuNctghD1dgh_MOH)

**decrypt函数部分截图**

![](/files/-MK-QM-FE9zVyvRHlW0N)

最后调用process\_beacon\_callback\_decrypted函数根据不同的任务输出类型进行不同的处理，比如30(shell命令)类型则就直接输出在Beacon控制台里

![](/files/-MK-Q0yJ9Nan6he7TTGL)

脚本解析shell whoami任务返回结果如下

![](/files/-MK-OyFkOBoFOK2DrtVu)

### 其他

相关解密代码：<https://github.com/WBGlIl/CS_Decrypt>
