RustCobaltStrike4.4Beacon:SMB,TCPBeacon重写记录

admin 2026-09-23 05:45:36 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细记录了使用Rust语言重写CobaltStrike4.4的SMBBeacon与TCPBeacon的技术实现,涵盖命名管道通信、链路帧格式、上线握手、命令转发及回调回传等核心机制,并展示了完整代码模块划分与验证流程,为红队C2开发提供了可操作的参考方案。 综合评分: 85 文章分类: 红队,内网渗透,安全工具,安全开发


Rust Cobalt Strike 4.4 Beacon:SMB,TCP Beacon重写记录

原创

cc cc

freedom安全

2026年9月22日 14:56 广东

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

1. SMB Beacon 定位

SMB Beacon 不是一套独立的命令实现,而是给同一个 Rust Beacon 增加了一条 SMB 传输通道。

项目里的三个入口共用同一套 command::handle_command():

beacon-rs.exe    HTTP Beacon
tcp_beacon.exe   TCP Beacon
smb_beacon.exe   SMB Beacon

SMB 的典型使用场景是内网横向和链式转发:

CS teamserver
   |
   | HTTP
   v
HTTP Beacon(父)
   |
   | 命名管道
   v
SMB Beacon(子)
   |
   | 命名管道
   v
更下一层 SMB Beacon

2. 配置文件

config.smb.json:

{
  "pipe_name": "\\\\.\\pipe\\beacon_rs_smb",
  "smb_frame_header": "",
  "pub_key_pem": "-----BEGIN PUBLIC KEY-----..."
}

字段说明:

| 字段 | 作用 | | — | — | | pipe_name | SMB Beacon 监听的命名管道 | | smb_frame_header | 可选帧魔数,可用来做流量伪装 | | pub_key_pem | CS 的 RSA 公钥,用于构造 metadata |

配置在 build.rs 里加密成 generated_config.rs,运行时再 XOR 解密。

3. 链路结构

SMB 子 Beacon 的完整链路:

父 Beacon connect SMB
   -> CreateFileA 连接命名管道
   -> 子 Beacon 发送 metadata 握手帧
   -> 父 Beacon 解析 agent_id + RSA metadata
   -> 父 Beacon 回传 CALLBACK_PIPE_OPEN 给 CS
   -> CS 下发 CMD_TYPE_PIPE_ROUTE
   -> 父 Beacon 写链路帧给子 Beacon
   -> 子 Beacon 解密、执行命令
   -> 子 Beacon 回传加密回调包
   -> 父 Beacon 读取并 POST CALLBACK_PIPE_READ

4. 命名管道实现

管道封装在 src/npipe.rs:

PipeServer
  CreateNamedPipeW
  ConnectNamedPipe

Pipe
  CreateFileA
  SetNamedPipeHandleState
  ReadFile
  WriteFile
  PeekNamedPipe

服务端使用:

PIPE_ACCESS_DUPLEX
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE
PIPE_UNLIMITED_INSTANCES

客户端使用 CreateFileA 连接,并设置 PIPE_READMODE_MESSAGE。

5. 链路帧格式

HTTP、TCP、SMB 的 link 帧使用同一套自定义格式:

2 字节 header length(大端)
可选 frame_header / magic
4 字节 payload length(小端)
payload

示例,空 magic:

00 04
00 00 00 0C
<12 字节 payload>

这里 00 04 表示 header 长度为 4。

对应代码:

fn&nbsp;build_link_frame(payload: &[u8],&nbsp;magic: &[u8])&nbsp;->&nbsp;Vec<u8>&nbsp;{
&nbsp; &nbsp;&nbsp;let&nbsp;header_len&nbsp;=&nbsp;magic.len()&nbsp;+&nbsp;4;
&nbsp; &nbsp;&nbsp;let mut&nbsp;frame&nbsp;=&nbsp;Vec::with_capacity(2&nbsp;+&nbsp;header_len&nbsp;+&nbsp;payload.len());
&nbsp; &nbsp;&nbsp;frame.extend_from_slice(&(header_len&nbsp;as&nbsp;u16).to_be_bytes());
&nbsp; &nbsp;&nbsp;frame.extend_from_slice(magic);
&nbsp; &nbsp;&nbsp;frame.extend_from_slice(&[0u8;&nbsp;4]);
&nbsp; &nbsp;&nbsp;let&nbsp;offset&nbsp;=&nbsp;frame.len()&nbsp;-&nbsp;4;
&nbsp; &nbsp;&nbsp;frame[offset..offset&nbsp;+&nbsp;4].copy_from_slice(&(payload.len()&nbsp;as&nbsp;u32).to_le_bytes());
&nbsp; &nbsp;&nbsp;frame.extend_from_slice(payload);
&nbsp; &nbsp;&nbsp;frame
}

6. 上线握手

smb_beacon.exe 启动后:

创建命名管道
等待客户端连接
发送握手帧
进入命令处理循环

握手帧 payload:

4 字节 client_id(小端)
RSA 加密后的 metadata

父 Beacon 读取握手后构造 CALLBACK_PIPE_OPEN:

4 字节 agent_id(大端)
4 字节 hint(大端)
子 Beacon metadata

SMB hint 固定为 445。

7. 命令转发

父 Beacon 收到 CS 的 link 命令后,对应命令:

CMD_TYPE_PIPE_OPEN_EXPLICIT
CMD_TYPE_PIPE_ROUTE
CMD_TYPE_PIPE_CLOSE
CMD_TYPE_PIPE_REOPEN

下行数据流:

CS
&nbsp; -> CMD_TYPE_PIPE_ROUTE
&nbsp; -> 父 Beacon handle_route()
&nbsp; -> write_link_frame()
&nbsp; -> SMB 子 Beacon read_frame()
&nbsp; -> decrypt_packet()
&nbsp; -> command::handle_command()

下行链路帧 payload 是加密命令包:

AES-CBC 密文 + HMAC-SHA256 前 16 字节

8. 回调回传

子 Beacon 执行命令后调用 post_packet():

生成加密 callback packet
前面加 4 字节大端长度
再包一层 link frame
写回父 Beacon

父 Beacon 的 link::poll() 读取完整帧后,构造:

CALLBACK_PIPE_READ
agent_id(4 字节大端)
子 Beacon 的 4 字节长度 + 加密回调包

然后通过 HTTP POST 回传 CS。

9. 已实现命令

SMB Beacon 与 HTTP/TCP 共用命令表,因此支持:

sleep
pwd
getuid
shell
cd
setenv
getprivs
ps
filebrowse
drives
mkdir
rm
cp
mv
upload
download
inject
spawn
dllinject
jobs
jobkill
execute-assembly
inline-execute
screenshot
keylogger
hashdump
AMSI / ETW patch

11. 代码模块

| 文件 | 作用 | | — | — | | src/smb/beacon.rs | SMB Beacon 主循环、握手、命令处理 | | src/npipe.rs | 命名管道封装 | | src/link.rs | 父 Beacon 的 SMB/TCP link 管理 | | src/command.rs | 统一命令分发 | | src/packet.rs | 命令 ID、回调类型、报文封装 | | src/crypto.rs | AES、HMAC、RSA |

12. 验证

当前测试覆盖:

smb_frame_roundtrip
link_frame_parser_handles_partial_frames
link_frame_parser_skips_empty_frames
smb_link_large_frame_roundtrip

验证流程:

启动 smb_beacon.exe
HTTP Beacon 执行 link 127.0.0.1 beacon_rs_smb
子 beacon 执行 shell whoami
父 beacon 回传 PIPE_READ

13. 效果

成功上线smb beacon

1. TCP Beacon 定位

TCP Beacon 是项目里的另一条持久连接通道,适合内网不稳定 HTTP 环境、跳板场景和链式转发。

CS teamserver
&nbsp; &nbsp;|
&nbsp; &nbsp;| HTTP
&nbsp; &nbsp;v
HTTP Beacon(父)
&nbsp; &nbsp;|
&nbsp; &nbsp;| TCP
&nbsp; &nbsp;v
TCP Beacon(子)

TCP 和 HTTP、SMB 共用同一套命令表,只更换传输层。

2. 配置文件

config.tcp.json:

{
&nbsp;&nbsp;"mode":&nbsp;"bind",
&nbsp;&nbsp;"server":&nbsp;"172.20.10.3",
&nbsp;&nbsp;"port":&nbsp;4444,
&nbsp;&nbsp;"bind_host":&nbsp;"0.0.0.0",
&nbsp;&nbsp;"bind_port":&nbsp;4444,
&nbsp;&nbsp;"tcp_frame_header":&nbsp;"",
&nbsp;&nbsp;"pub_key_pem":&nbsp;"-----BEGIN PUBLIC KEY-----..."
}

字段说明:

| 字段 | 作用 | | — | — | | mode | bind 或 reverse | | server | reverse 模式连接地址 | | port | reverse 模式连接端口 | | bind_host | bind 模式监听地址 | | bind_port | bind 模式监听端口 | | tcp_frame_header | 可选链路魔数 | | pub_key_pem | CS RSA 公钥 |

3. Socket 实现

项目没有直接依赖 Rust 标准库 TCP,而是在 src/wsock.rs 里封装 Winsock:

WSASocketW
connect
bind
listen
accept
send
recv
select
setsockopt

4. bind / reverse

4.1 bind

RawListener::bind(bind_host, bind_port)
listener.accept()

适合目标能出网但不能主动连接外部的场景。

4.2 reverse

RawSocket::connect(server, port)

适合目标可主动连接 C2/中继端口的场景。

5. 链路帧格式

TCP 使用与 SMB 相同的 link 帧:

2 字节 header length(大端)
可选 frame_header / magic
4 字节 payload length(小端)
payload

示例:

00 04
00 00 00 0C
<12 字节 payload>

6. 上线握手

tcp_beacon.exe 收到连接后:

发送握手帧
进入命令处理循环

握手帧 payload:

4 字节 client_id(小端)
RSA 加密后的 metadata

父 Beacon connect 后:

读取握手帧
解析 agent_id
hint = 0x00100000 | port
回传 CALLBACK_PIPE_OPEN

7. 命令转发

父 Beacon 收到 CS 的 CMD_TYPE_TCP_CONNECT 后建立 TCP 链路。

后续命令通过 CMD_TYPE_PIPE_ROUTE 转发:

CS
&nbsp; -> CMD_TYPE_PIPE_ROUTE
&nbsp; -> handle_route()
&nbsp; -> write_link_frame()
&nbsp; -> TCP 子 Beacon read_frame()
&nbsp; -> decrypt_tcp_packet()
&nbsp; -> command::handle_command()

8. 回调回传

TCP 子 Beacon 的回调流程:

生成加密 callback packet
前面加 4 字节大端长度
再包一层 link frame
写回父 Beacon

父 Beacon:

link::poll()
&nbsp; -> 非阻塞读取 socket
&nbsp; -> read_buf 缓冲
&nbsp; -> 解析完整链路帧
&nbsp; -> POST CALLBACK_PIPE_READ

9. 非阻塞轮询

TCP 没有数据时必须快速返回,不能阻塞 HTTP 父 Beacon 主循环。

实现方式:

select(read_fd, 1ms)
&nbsp; -> 不可读:返回超时
&nbsp; -> 可读:recv() 读入 read_buf
&nbsp; -> 解析完整帧

对应代码:

pub&nbsp;fn&nbsp;wait_readable(&mut&nbsp;self,&nbsp;timeout:&nbsp;Duration)&nbsp;->&nbsp;Result<bool,&nbsp;String>&nbsp;{
&nbsp; &nbsp;&nbsp;let&nbsp;select:&nbsp;SelectFn&nbsp;=&nbsp;dyn_fn("select")?;
&nbsp; &nbsp;&nbsp;let mut&nbsp;readfds&nbsp;=&nbsp;FdSet::new();
&nbsp; &nbsp;&nbsp;readfds.insert(self.socket);
&nbsp; &nbsp;&nbsp;let&nbsp;timeval&nbsp;=&nbsp;Timeval&nbsp;{ ... };
&nbsp; &nbsp;&nbsp;let&nbsp;status&nbsp;=&nbsp;unsafe&nbsp;{&nbsp;select(0, &mut&nbsp;readfds,&nbsp;null_mut(),&nbsp;null_mut(), &timeval) };
&nbsp; &nbsp;&nbsp;Ok(status&nbsp;>&nbsp;0)
}

10. 已实现命令

TCP Beacon 同样支持:

sleep
pwd
getuid
shell
cd
setenv
getprivs
ps
filebrowse
drives
mkdir
rm
cp
mv
upload
download
inject
spawn
dllinject
jobs
jobkill
execute-assembly
inline-execute
screenshot
keylogger
hashdump
AMSI / ETW patch

11. 代码模块

| 文件 | 作用 | | — | — | | src/tcp/beacon.rs | TCP Beacon 主循环、握手、命令处理 | | src/wsock.rs | Winsock 封装、select 等待 | | src/link.rs | 父 Beacon 的 TCP/SMB link 管理 | | src/command.rs | 统一命令分发 | | src/packet.rs | 命令 ID、回调类型、报文封装 | | src/crypto.rs | AES、HMAC、RSA |

12. 验证

测试覆盖:

tcp_link_read_timeout_returns
tcp_link_wait_readable_false_after_frame_read
link_frame_parser_handles_partial_frames
link_frame_parser_skips_empty_frames

验证流程:

启动 tcp_beacon.exe
HTTP Beacon 执行 connect 127.0.0.1 4444
子 beacon 执行 shell whoami
父 beacon 回传 PIPE_READ

14. 效果

成功实现tcp beacon


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。

本文转载自:freedom安全 cc cc《Rust Cobalt Strike 4.4 Beacon:SMB,TCP Beacon重写记录》

评论:0   参与:  0