-
简单高效
-
跨平台支持
-
支持反向端口转发
-
使用SSH协议加密连接
-
使用WebSocket协议通信
-
客户端可以通过一个 TCP 连接创建多个隧道端点
-
客户端通过HTTP(S)连接服务器
-
连接升级为WebSocket
-
建立SSH安全隧道
-
交换配置信息并设置端口转发
-
使用配置消息交换设置参数
-
采用ping-pong机制维持连接
-
通过SSH通道实现多连接复用
chisel server -port 9999 -reverse
chisel client <server_ip>:9999 R:socks
-
客户端通过 HTTP/WebSocket 连接到服务器
-
WebSocket 连接升级时使用 "Sec-WebSocket-Protocol" 头标识协议版本
-
在 WebSocket 之上建立 SSH 连接进行加密和认证
-
客户端发送配置信息,服务器验证并响应
-
建立 SSH 通道用于传输实际数据
-
根据配置支持正向或反向端口转发
-
可选 SOCKS5 代理功能
-
使用 ping/pong 机制保持连接活跃
-
实现断线重连和错误处理
通过报文可以看到,还有一对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版本: SSH-chisel-v3-client
-
服务端SSH版本: SSH-chisel-v3-server
-
SSH请求类型为config
-
使用JSON格式配置数据
-
包含版本信息和隧道配置
-
SSH通道类型为 "chisel" (关键指纹)
-
额外数据包含目标地址信息
-
支持TCP、UDP和SOCKS5协议
-
SSH请求类型: ping
-
响应数据: pong
-
默认25秒间隔
|
||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
SSH-2.0-Go无法在请求流量中明文体现
-
只要使用了该库进行加密,就会带有该指纹信息,而非chisel专属指纹
-
Sec-WebSocket-Protocol: chisel-v3
-
Upgrade: 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 Headers
event http_all_headers(c: connection, is_orig: bool, hlist: mime_header_list) {
# Skip if processed
# Scan all headers
# Create session status when both headers satified
}
# WebSocket data check
event websocket_frame_data(c: connection, is_orig: bool, data: string) {
# 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) {
}
+-------------------+ 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) |
+---------------------+ +---------------------------+
module ChiselDetection;
event http_connection_upgrade(c:connection, protocol: string){
print(protocol);
}
S - The originator sent a SYN segment.
h - The responder sent a SYN ACK segment.
A - The originator sent an ACK segment.
D - The originator sent at least one segment with payload data. In this case, that was HTTP over TCP.
a - The responder replied with an ACK segment.
d - The responder replied with at least one segment with payload data.
F - The originator sent a FIN ACK segment.
f - The responder replied with a FIN ACK segment.
^had:
"^" - 表示TCP序列号异常
接收方发送了一个SYN ACK包
接收方响应了一个ACK包
接收方响应了至少一个带有有效负载数据的分段
SAD:
发起者发送了一个 SYN 包
发起者发送了一个 ACK 包
发起者发送了至少一个带有有效负载数据的分段(基于 TCP 的 HTTP)
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]
......
原文始发于微信公众号(Crush Sec):Chisel解密:基于Zeek的检测规则开发与调试踩坑实录
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论