Merge pull request #106 from apernet/wip-new-trojan

feat: new heuristics for trojan analyzer
This commit is contained in:
Toby 2024-03-20 18:11:09 -07:00 committed by GitHub
commit f3b72895ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 50 additions and 42 deletions

View File

@ -21,7 +21,7 @@ Telegram グループ: https://t.me/OpGFW
- フル IP/TCP 再アセンブル、各種プロトコルアナライザー - フル IP/TCP 再アセンブル、各種プロトコルアナライザー
- HTTP、TLS、QUIC、DNS、SSH、SOCKS4/5、WireGuard、その他多数 - HTTP、TLS、QUIC、DNS、SSH、SOCKS4/5、WireGuard、その他多数
- Shadowsocks の「完全に暗号化されたトラフィック」の検出など (https://gfw.report/publications/usenixsecurity23/en/) - Shadowsocks の「完全に暗号化されたトラフィック」の検出など (https://gfw.report/publications/usenixsecurity23/en/)
- トロイの木馬キラー (https://github.com/XTLS/Trojan-killer) に基づくトロイの木馬 (プロキシプロトコル) 検出 - Trojan プロキシプロトコルの検出
- [WIP] 機械学習に基づくトラフィック分類 - [WIP] 機械学習に基づくトラフィック分類
- IPv4 と IPv6 をフルサポート - IPv4 と IPv6 をフルサポート
- フローベースのマルチコア負荷分散 - フローベースのマルチコア負荷分散

View File

@ -25,7 +25,7 @@ Telegram group: https://t.me/OpGFW
- HTTP, TLS, QUIC, DNS, SSH, SOCKS4/5, WireGuard, and many more to come - HTTP, TLS, QUIC, DNS, SSH, SOCKS4/5, WireGuard, and many more to come
- "Fully encrypted traffic" detection for Shadowsocks, - "Fully encrypted traffic" detection for Shadowsocks,
etc. (https://gfw.report/publications/usenixsecurity23/en/) etc. (https://gfw.report/publications/usenixsecurity23/en/)
- Trojan (proxy protocol) detection based on Trojan-killer (https://github.com/XTLS/Trojan-killer) - Trojan (proxy protocol) detection
- [WIP] Machine learning based traffic classification - [WIP] Machine learning based traffic classification
- Full IPv4 and IPv6 support - Full IPv4 and IPv6 support
- Flow-based multicore load balancing - Flow-based multicore load balancing

View File

@ -21,7 +21,7 @@ Telegram 群组: https://t.me/OpGFW
- 完整的 IP/TCP 重组,各种协议解析器 - 完整的 IP/TCP 重组,各种协议解析器
- HTTP, TLS, QUIC, DNS, SSH, SOCKS4/5, WireGuard, 更多协议正在开发中 - HTTP, TLS, QUIC, DNS, SSH, SOCKS4/5, WireGuard, 更多协议正在开发中
- Shadowsocks 等 "全加密流量" 检测 (https://gfw.report/publications/usenixsecurity23/zh/) - Shadowsocks 等 "全加密流量" 检测 (https://gfw.report/publications/usenixsecurity23/zh/)
- 基于 Trojan-killer 的 Trojan 检测 (https://github.com/XTLS/Trojan-killer) - Trojan 协议检测
- [开发中] 基于机器学习的流量分类 - [开发中] 基于机器学习的流量分类
- 同等支持 IPv4 和 IPv6 - 同等支持 IPv4 和 IPv6
- 基于流的多核负载均衡 - 基于流的多核负载均衡

View File

@ -9,22 +9,14 @@ import (
var _ analyzer.TCPAnalyzer = (*TrojanAnalyzer)(nil) var _ analyzer.TCPAnalyzer = (*TrojanAnalyzer)(nil)
// CCS stands for "Change Cipher Spec" // CCS stands for "Change Cipher Spec"
var trojanCCS = []byte{20, 3, 3, 0, 1, 1} var ccsPattern = []byte{20, 3, 3, 0, 1, 1}
const ( // TrojanAnalyzer uses length-based heuristics to detect Trojan traffic based on
trojanUpLB = 650 // its "TLS-in-TLS" nature. The heuristics are trained using a decision tree with
trojanUpUB = 1000 // about 2000 samples. This is highly experimental and is known to have significant
trojanDownLB1 = 170 // false positives (about 8% false positives & 2% false negatives).
trojanDownUB1 = 180 // We do NOT recommend directly blocking all positive connections, as this is likely
trojanDownLB2 = 3000 // to break many normal TLS connections.
trojanDownUB2 = 7500
)
// TrojanAnalyzer uses a very simple packet length based check to determine
// if a TLS connection is actually the Trojan proxy protocol.
// The algorithm is from the following project, with small modifications:
// https://github.com/XTLS/Trojan-killer
// Warning: Experimental only. This method is known to have significant false positives and false negatives.
type TrojanAnalyzer struct{} type TrojanAnalyzer struct{}
func (a *TrojanAnalyzer) Name() string { func (a *TrojanAnalyzer) Name() string {
@ -32,7 +24,7 @@ func (a *TrojanAnalyzer) Name() string {
} }
func (a *TrojanAnalyzer) Limit() int { func (a *TrojanAnalyzer) Limit() int {
return 16384 return 512000
} }
func (a *TrojanAnalyzer) NewTCP(info analyzer.TCPInfo, logger analyzer.Logger) analyzer.TCPStream { func (a *TrojanAnalyzer) NewTCP(info analyzer.TCPInfo, logger analyzer.Logger) analyzer.TCPStream {
@ -40,10 +32,12 @@ func (a *TrojanAnalyzer) NewTCP(info analyzer.TCPInfo, logger analyzer.Logger) a
} }
type trojanStream struct { type trojanStream struct {
logger analyzer.Logger logger analyzer.Logger
active bool first bool
upCount int count bool
downCount int rev bool
seq [4]int
seqIndex int
} }
func newTrojanStream(logger analyzer.Logger) *trojanStream { func newTrojanStream(logger analyzer.Logger) *trojanStream {
@ -57,33 +51,48 @@ func (s *trojanStream) Feed(rev, start, end bool, skip int, data []byte) (u *ana
if len(data) == 0 { if len(data) == 0 {
return nil, false return nil, false
} }
if !rev && !s.active && len(data) >= 6 && bytes.Equal(data[:6], trojanCCS) {
// Client CCS encountered, start counting if s.first {
s.active = true s.first = false
// Stop if it's not a valid TLS connection
if !(!rev && len(data) >= 3 && data[0] >= 0x16 && data[0] <= 0x17 &&
data[1] == 0x03 && data[2] <= 0x09) {
return nil, true
}
} }
if s.active {
if rev { if !rev && !s.count && len(data) >= 6 && bytes.Equal(data[:6], ccsPattern) {
// Down direction // Client Change Cipher Spec encountered, start counting
s.downCount += len(data) s.count = true
}
if s.count {
if rev == s.rev {
// Same direction as last time, just update the number
s.seq[s.seqIndex] = len(data)
} else { } else {
// Up direction // Different direction, bump the index
if s.upCount >= trojanUpLB && s.upCount <= trojanUpUB && s.seqIndex += 1
((s.downCount >= trojanDownLB1 && s.downCount <= trojanDownUB1) || if s.seqIndex == 4 {
(s.downCount >= trojanDownLB2 && s.downCount <= trojanDownUB2)) { // Time to evaluate
yes := s.seq[0] >= 100 &&
s.seq[1] >= 88 &&
s.seq[2] >= 40 &&
s.seq[3] >= 51
return &analyzer.PropUpdate{ return &analyzer.PropUpdate{
Type: analyzer.PropUpdateReplace, Type: analyzer.PropUpdateReplace,
M: analyzer.PropMap{ M: analyzer.PropMap{
"up": s.upCount, "seq": s.seq,
"down": s.downCount, "yes": yes,
"yes": true,
}, },
}, true }, true
} }
s.upCount += len(data) s.seq[s.seqIndex] = len(data)
s.rev = rev
} }
} }
// Give up when either direction is over the limit
return nil, s.upCount > trojanUpUB || s.downCount > trojanDownUB2 return nil, false
} }
func (s *trojanStream) Close(limited bool) *analyzer.PropUpdate { func (s *trojanStream) Close(limited bool) *analyzer.PropUpdate {

View File

@ -251,8 +251,7 @@ Check https://github.com/XTLS/Trojan-killer for more information.
```json ```json
{ {
"trojan": { "trojan": {
"down": 4712, "seq": [170, 282, 167, 470],
"up": 671,
"yes": true "yes": true
} }
} }