Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

admin 2025年5月26日19:34:27评论5 views字数 12737阅读42分27秒阅读模式
Chisel工具介绍

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

工具概述
Chisel是一款轻量级的,基于HTTP协议传输的快速TCP/UDP隧道工具,通过SSH实现安全加密,采用GO语言编写。其客户端和服务器端集成于同一个可执行文件中,服务器端作为受控代理节点运行,而客户端通过Chisel创建隧道与服务器通信。
Chisel主要用于穿透防火墙,也可作为安全接入端点访问内部网络。
功能特点
  • 简单高效
  • 跨平台支持
  • 支持反向端口转发
  • 使用SSH协议加密连接
  • 使用WebSocket协议通信
  • 客户端可以通过一个 TCP 连接创建多个隧道端点
工作原理
Chisel采用客户端-服务器架构,通过多层协议封装实现数据传输:
1、多层协议栈:应用数据 → SSH协议 → WebSocket → HTTP(S) → TCP
2、连接流程:
  • 客户端通过HTTP(S)连接服务器
  • 连接升级为WebSocket
  • 建立SSH安全隧道
  • 交换配置信息并设置端口转发
3、通信控制:
  • 使用配置消息交换设置参数
  • 采用ping-pong机制维持连接
  • 通过SSH通道实现多连接复用
简单示例
以下是 Chisel 工具的基础使用示例,适用于在内网中,失陷机器主动发起请求,来穿透防火墙的场景:
服务端启动监听:
chisel server -port 9999 -reverse
启动一个监听在 9999 端口的服务端,启用反向模式(-reverse参数),允许客户端请求反向隧道

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

chisel client <server_ip>:9999 R:socks
客户端在本地创建SOCKS代理服务,并通过Chisel隧道将此代理服务暴露给服务器端,所有流量通过一个加密的WebSocket隧道传输

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

同时,在客户端用python启动http服务。
最后在server端配置完proxychains后,通过代理访问http服务进行验证:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

特征分析
核心通信流程
连接建立
  • 客户端通过 HTTP/WebSocket 连接到服务器
  • WebSocket 连接升级时使用 "Sec-WebSocket-Protocol" 头标识协议版本
握手过程
  •  WebSocket 之上建立 SSH 连接进行加密和认证
  • 客户端发送配置信息,服务器验证并响应
隧道管理
  • 建立 SSH 通道用于传输实际数据
  • 根据配置支持正向或反向端口转发
  • 可选 SOCKS5 代理功能
连接维护
  • 使用 ping/pong 机制保持连接活跃
  • 实现断线重连和错误处理
连接建立
首先,客户端发起 WebSocket 连接请求。
client/client_connect.go:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

随后服务端处理 WebSocket 升级请求:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

这里Chisel使用特定的 WebSocket 子协议标识符chshare.ProtocolVersion,可以作为一个特征。
看一下来源:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

因此:
HTTP请求头包含 Upgrade: websocket
HTTP请求头包含 Sec-WebSocket-Protocol: chisel-v3

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

通过报文可以看到,还有一对Sec-WebSocket-Key/Sec-WebSocket-Accept的header,这两个header是websocket协议自带的部分,不能作为指纹来进行识别,大致过程如下:Sec-WebSocket-Key(客户端生成)生成方式:客户端生成一个 16字节(128位)的随机数。将该随机数进行 Base64编码,结果作为Sec-WebSocket-Key的值。要求:随机数必须足够随机(如使用密码学安全的随机数生成器)。每个握手请求必须使用新的随机值,防止重放攻击。Sec-WebSocket-Accept(服务器生成)生成步骤:服务器从客户端的Sec-WebSocket-Key中提取原始值(Base64解码)。将解码后的值与固定的 GUID字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接。对拼接后的字符串进行 SHA-1哈希,得到20字节的哈希值。将哈希值进行 Base64编码,结果作为Sec-WebSocket-Accept的值。公式:accept_value = base64(sha1(sec_websocket_key + GUID))
握手指纹
客户端进行ssh配置的初始化:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

同样,服务端进行ssh配置的初始化:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

最后,客户端进行ssh握手:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

注意,此时的握手发生在WebSocket连接上,而非TCP22端口。
SSH 握手中使用的版本字符串是独特的,包含 chshare.ProtocolVersion 并分别添加了 -client  -server 后缀。
特征如下:
  • 客户端SSH版本: SSH-chisel-v3-client
  • 服务端SSH版本: SSH-chisel-v3-server

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

隧道管理
客户端发送隧道配置:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

服务端验证配置:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

特征如下:
  • SSH请求类型为config
  • 使用JSON格式配置数据
  • 包含版本信息和隧道配置

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

连接维护
首先建立SSH通道:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

根据不同协议,走不同函数进行处理:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

特征如下:
  • SSH通道类型为 "chisel" (关键指纹)
  • 额外数据包含目标地址信息
  • 支持TCP、UDP和SOCKS5协议
保活循环:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

服务端响应:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

保活特征:
  • SSH请求类型: ping
  • 响应数据: pong
  • 默认25秒间隔
总结
HTTP/WebSocket层指纹
指纹特征描述在代码中的位置
WebSocket子协议
Sec-WebSocket-Protocol: chisel-v3 (或其他版本)
client/client_connect.go, server/server_handler.go
WebSocket升级
Upgrade: websocket
client/client_connect.go, server/server_handler.go
SSH层指纹
指纹特征描述在代码中的位置
客户端版本
SSH-chisel-v3-client
client/client.go
服务端版本
SSH-chisel-v3-server
server/server.go
配置请求
请求类型 config
client/client_connect.go, server/server_handler.go
保活机制
请求类型ping,响应 pong
tunnel/tunnel.go, tunnel/tunnel_out_ssh.go
SSH通道类型
通道类型 chisel
tunnel/tunnel_in_proxy.go
规则编写
除了上述特征,还有ssh指纹信息,因为使用的是golang.org/x/[email protected]/ssh加密,因此会带有GO的硬编码特征:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

但是该特征无法当作chisel的指纹,因为:
  • SSH-2.0-Go无法在请求流量中明文体现
  • 只要使用了该库进行加密,就会带有该指纹信息,而非chisel专属指纹
上面的特征中,ssh的config、chisel请求类型,以及ping、pong类型的心跳包,均经过ssh加密,因此,检测点只能落在连理连接的阶段,即:
  • Sec-WebSocket-Protocol: chisel-v3
  • Upgrade: websocket
以及经过websocket协议封装的握手指纹:
  • SSH-chisel-v3-client
  • SSH-chisel-v3-server
性能提升
多层过滤
  • HTTP流量初筛:仅分析源自客户端的HTTP请求
  • WebSocket协议验证:检查Upgrade和Protocol头部
  • 数据帧快速判断:检查最小长度(10字节)和SSH前缀
资源限制
  • 会话表容量控制:限制最大10,000个会话
  • 自动过期机制:30秒自动清理过期会话
  • 处理深度限制:每个连接最多分析4个数据帧
  • 数据截断:每个数据帧仅分析前30字节
检测规则
module ChiselDetection;redef ignore_checksums = T;export {    # Define Config path    # Define Notice Type    # Define Chisel State    # Define Session Track Table(via c$uid)    # Configuration options# Process HTTP Headersevent http_all_headers(c: connection, is_origbool, hlist: mime_header_list) {    # Skip if processed    # Scan all headers    # Create session status when both headers satified}# WebSocket data checkevent websocket_frame_data(c: connection, is_origbool, datastring) {    # Process marked session only    # Return if reached upper limit    # Record processed frames    # Check first 30 bytes    # Return if protocol_value is null    # Check client handshake    # Check server handshake    # Mark as completed if both directions handshake detected}event connection_state_remove(c: connection) {}
检测效果
修改ProtocolVersion默认签名:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

检测流程图
+-------------------+     WebSocket Upgrade     +------------------+| Initial HTTP      |-------------------------->| Potential Chisel  || Connection        |                           | Connection        |+-------------------+                           +------------------+                                                         |                                                         v                                               +-------------------+                                                     | Check Sec-WebSocket|                                                     | Protocol Header    |                                                     +-------------------+                                                               |                                               Missing                 |                                               +---------------------- | Present                                              |                       |                                               v                       v              +---------------------+          |    +---------------------------+   | Regular WebSocket   |<---------+    | Create ChiselState &      |   | Connection          |               | Track Connection          |   +---------------------+               +---------------------------+                                                      |                                                   v                                      +------------------+                                               | Monitor WebSocket|                                               | Frame Data       |                                               +------------------+                                                            |                                                   v                                      +---------------------------+                                      | Is Data Starting with SSH?|                                      +---------------------------+                                                   |                                         No        |                                              +----------- |                                         |            |Yes                                                   v            v                                   +---------------+        +-----------------+                      | Skip Frame    |        | Continue        |                      +---------------+        | Processing      |                                               +-----------------+                                                        |                                                        v                                      +---------------------------+                                      | Check for Client Handshake|                                      | SSH-{protocol}-client     |                                      +---------------------------+                                                   |                                                   v                                      +---------------------------+                                      | Check for Server Handshake|                                      | SSH-{protocol}-server     |                                      +---------------------------+                                                   |                                                   v                                      +---------------------------+                                      | Both Handshakes Detected? |                                      +---------------------------+                                                   |                                    No             |Yes                                     +--------------------------- |                                  |                            |                                   v                            v                   +---------------------+             +---------------------------+ | Continue Monitoring |             | Generate Chisel Tunnel    | | (max 4 frames)      |             | Detection Alert           | +---------------------+             +---------------------------+          |                                       |         v                                       v+---------------------+             +---------------------------+| Detection Incomplete|             | Mark Detection Complete   || (False Negative)    |             | (True Positive)           |+---------------------+             +---------------------------+
Debug
在规则编写过程中,首先需要匹配httpheader,但是始终无法正确匹配,由此开始漫长的debug。
先尝试使用各种event打印所有的header头:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

从打印结果来看,只识别了Server→Client方向的流量,即response的内容,从header来看确实都是响应头信息。
那么请求部分的数据呢?
到此想到,websocket是全双工的长连接,会不会因为该http请求是用来升级websocket协议的,因此和正常流量有所差异?
于是采用trans_depth的方式,不依赖方向标志,来识别流数据:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

结果不变,依然是只检测到了response,并成功打印出了响应头信息。
搜索websocket,发现存在一个http_connection_upgrade event,可以用来检测websocket事件,写一个最简单的脚本,看看该event能否正确识别:
module ChiselDetection;event http_connection_upgrade(c:connection, protocol: string){        print(protocol);    }

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

同样失败。要检测http升级到websocket协议,首先要保证zeek能够正确加载http分析器,结合前面无法正确识别header,应该是在http层面就出现了问题。
当前的pcap,只能识别response,会不会跟抓包也有关?
下面的chisel_exchange.pcap是将两台机器执行的命令对调后,抓取的报文,同样使用前面的脚本,打印所有header:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

此时竟然只识别出了Client→Server,即request,没有识别到response,正常打印出了request header。
也就是说,zeek只识别出了一个连接,查看conn.log:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

conn_state分别为OTH和S0,history分别为^had和SAD。
OTH代表TCP异常,而S0代表TCP三次握手未完成。
history字段含义如下:
- The originator sent a SYN segment.- The responder sent a SYN ACK segment.- The originator sent an ACK segment.- The originator sent at least one segment with payload data. In this case, that was HTTP over TCP.- The responder replied with an ACK segment.- The responder replied with at least one segment with payload data.- The originator sent a FIN ACK segment.- The responder replied with a FIN ACK segment.
^had:"^" - 表示TCP序列号异常接收方发送了一个SYN ACK接收方响应了一个ACK接收方响应了至少一个带有有效负载数据的分段SAD发起者发送了一个 SYN 包发起者发送了一个 ACK 包发起者发送了至少一个带有有效负载数据的分段(基于 TCP 的 HTTP)
至此可以看到,是zeek在解析的时候,未能正确看到完整的TCP握手过程(SYN—>SYN-ACK—>ACK),要么丢了SYN包,要么丢了SYN-ACK包。
通过脚本验证一下:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

问题的根源在于,zeek没能看到完整的TCP3次握手过程,导致在TCP重组时出错,进而影响了上层的HTTP以及websocket协议,因此,通过http相关event进行识别也均出错。
那能不能直接从TCP层进行特征匹配呢?
可以,但是目前还是没有解决只能识别单向流量的问题,从TCP层匹配也只能检测单侧数据,不考虑效率的情况下,结果也不够准确。
zeek还有一些日志文件,包括weird.log,其中包含了部分错误信息:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

在两个包的weird.log中,均有bad_IP_checksum提示,说明可能是在检查校验和的时候出错了。
在脚本开头加上redef ignore_checksums = T,忽略checksum的检查,进一步调试看看。
日志如下:
TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=S seq=0 ack=0 len=0  ** TCPxe6x8fxa1xe6x89x8bxe5x8cx85: S     * xe7xbaxafSYNxe5x8cx85 (xe8xbfx9exe6x8exa5xe5x88x9dxe5xa7x8bxe5x8cx96)1744884754.543732 expression error in ./Chisel/chisel.zeek, line 45: field value missing (c$conn)TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=SA seq=0 ack=1 len=0  ** TCPxe6x8fxa1xe6x89x8bxe5x8cx85: SA     * SYN-ACKxe5x8cx85 (xe6x9cx8dxe5x8axa1xe5x99xa8xe5x93x8dxe5xbax94)TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=AP seq=1 ack=1 len=223  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: 'GET / HTTP/1.1..Host: 192.168....'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=AP seq=1 ack=224 len=129  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: 'HTTP/1.1 101 Switching Protoco...'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=AP seq=224 ack=130 len=28  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '......]F..m}..ky..=8..gp....'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=AP seq=130 ack=224 len=24  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '..SSH-chisel-v3-server..'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=AP seq=252 ack=154 len=1096  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '[email protected]$..r ..f..z...../..|l......'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=AP seq=154 ack=252 len=708  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '.~.........'..y..S..o.D..Y.......'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=AP seq=1348 ack=862 len=54  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '.....I...e...I..T..;...S.vQ......'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=AP seq=862 ack=1402 len=276  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '.~...........h....ecdsa-sha2-n...'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe6x9cx8dxe5x8axa1xe5x99xa8xe2x86x92xe5xaexa2xe6x88xb7xe7xabxaf] flags=AP seq=1138 ack=1402 len=282  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '...........N.#.....~........e....'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] [xe5xaexa2xe6x88xb7xe7xabxafxe2x86x92xe6x9cx8dxe5x8axa1xe5x99xa8] flags=AP seq=1402 ack=1420 len=22  xe6x95xb0xe6x8dxaexe9xa2x84xe8xa7x88: '...C...C...VWr%..W~...'TCPxe6x8exa7xe5x88xb6xe5x8cx85: [orig_h=192.168.64.1, orig_p=51511/tcp, resp_h=192.168.64.8, resp_p=8000/tcp, proto=6] ......
调试的日志中发现:
1、完整的TCP握手序列
第1个包: flags=S (客户端SYN)
第2个包: flags=SA (服务器SYN-ACK)
(ACK包可能存在但在输出中被过滤)
2、完整的HTTP交换
客户端发送HTTPGET请求: GET / HTTP/1.1..Host: 192.168....
服务器回复101状态码: HTTP/1.1 101 Switching Protoco...
即,PCAP文件实际上包含了完整的双向TCP流量,说明之前的所有错误都是由Zeek对校验和错误的严格处理导致的。
问题的根本原因是数据包校验和错误:
默认情况下,Zeek会丢弃校验和不正确的包
这导致Zeek只看到了连接的部分片段
当启用ignore_checksums = T后,Zeek能正确处理整个连接
加上ignore_checksums=T,再次使用前面的脚本打印所有header:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

正确打印所有header,说明到http这一步已经能成功识别。
最后尝试http_connection_upgrade:

Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

Done!

原文始发于微信公众号(Crush Sec):Chisel解密:基于Zeek的检测规则开发与调试踩坑实录

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月26日19:34:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Chisel解密:基于Zeek的检测规则开发与调试踩坑实录https://cn-sec.com/archives/4099572.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息