主流防火墻策略繞過漏洞的修復方案與加固實踐
流量關鍵點分析(攻擊手法)
攻擊者通過精心構造的TCP序列號攻擊和惡意標志組合繞過防火墻DPI檢測,核心手法如下:
-
TCP連接建立(正常握手)
- 1049:客戶端 SYN(seq=x)
45 00 00 34 d5 f8 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a
- 1053:服務端 SYN-ACK(seq=y, ack=x+1)
45 00 00 34 a0 8a 00 00 32 06 08 22 ac fd 72 5a c0 a8 00 18
- 1054:客戶端 ACK(seq=x+1, ack=y+1)
45 00 00 28 d5 fa 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a
- 1049:客戶端 SYN(seq=x)
-
TLS握手拆分攻擊
-
1055:發送 TLS ClientHello頭部(4字節)
- 標志:
PUSH+ACK
- 數據:
16 03 01 02
(TLS握手頭,版本TLS1.0,長度512字節)
45 00 00 2c d5 fb 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a
- 標志:
-
1056:插入 惡意MD5-SIG報文
- 大包(557字節)含TCP MD5選項
- 標志:
PUSH+ACK
→ 強制DPI流控重置狀態
45 00 02 2d d5 fb 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a
-
1057:發送 ClientHello主體(130字節)
- 標志:
ACK
(無PUSH)→ 偽裝控制包 - 包含SNI字段起始部分
77 77 77 2e 67 6f 6f
(“www.goo”)
45 00 00 aa d5 fb 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a 00 01 00 01 fc 03 03 fc 9e d4 bd e7 e3 e2 90 12 79 b7 4b 68...
- 標志:
-
1058:重傳 1056惡意包
- 觸發防火墻"連續大包阻斷"規則
45 00 02 2d d5 fb 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a
-
1059:發送 ClientHello剩余部分(383字節)
- 完成SNI字段
67 6c 65 2e 63 6f 6d
(“gle.com” → “www.google.com”)
45 00 01 a7 d5 fb 40 00 40 06 00 00 c0 a8 00 18 ac fd 72 5a 67 6c 65 2e 63 6f 6d 00 17 00 00 ff 01 00 01 00...
- 完成SNI字段
-
-
攻擊原理
- DPI繞過:利用ACK without PUSH(1057)偽裝控制包
- 流控觸發:惡意包(1056/1058)觸發防火墻阻斷規則
- SNI隱藏:拆分SNI字段(1057+1059)使DPI無法提取域名
防火墻漏洞根源
-
TCP流控缺陷
- 依賴
PUSH
標志判斷數據邊界 → 被ACK without PUSH
(1057)繞過 - 未驗證序列號連續性 → 允許惡意包(1056)插入合法流
- 依賴
-
重組機制缺失
- 未緩沖分片TLS消息 → 無法重組ClientHello(1055+1057+1059)
- 未使用TLS長度字段(
02 00
=512字節)驗證完整性
-
協議處理漏洞
- 未過濾異常TCP選項(MD5-SIG)→ 被用作攻擊載體
- 未實現應用層超時機制 → 惡意包阻塞重組緩沖區
-
IF (TCP.FLAGS & TCP_PUSH) do…; PSH-only 漏洞
防火墻修復方案
1. TCP層強化
模塊 | 修復措施 | 防御目標 |
---|---|---|
流重組引擎 | 實現狀態化TCP重組 | 防止序列號跳躍攻擊(1056插入) |
- 緩沖數據直到應用層消息完整 | 重組被拆分的ClientHello | |
- 嚴格驗證SEQ/ACK連續性 | ||
標志處理 | 取消對PUSH標志的依賴 | 防御1057幀偽裝控制包 |
- 基于應用層長度判斷消息邊界 | ||
- 驗證標志組合合理性 | ||
選項過濾 | 默認丟棄MD5-SIG選項包 | 阻止1056/1058攻擊載體 |
if (tcp.option == MD5-SIG) DROP |
2. TCP標志位處理優化
關于TCP PUSH標志的澄清
在TCP協議中:
- PUSH標志(PSH) 用于指示接收方應立即將數據傳遞給應用層
- ACK標志 是大多數數據包的默認標志
- 合法標志組合:
ACK
(最常見)PSH|ACK
(帶數據的推送)RST|ACK
(連接重置)FIN|ACK
(連接終止)
異常標志處理規則
-
丟棄規則:
- 所有 PSH-only 包 (無ACK標志) → 立即丟棄
- 所有 non-ACK 數據包 (已建立連接中) → 丟棄
-
驗證邏輯偽代碼:
if (tcp.flags == PSH && !(tcp.flags & ACK)) {log("Invalid PSH-only packet", packet);DROP;}if (connection_state == ESTABLISHED && !(tcp.flags & ACK)) {log("Non-ACK packet in established connection", packet);DROP;}
標志位處理增強方案
異常標志處理規則
異常標志組合 | 風險等級 | 處理措施 | 攻擊防護目標 |
---|---|---|---|
PSH-only | 高危 | 立即丟棄 | 防止強制刷新攻擊 |
Non-ACK | 高危 | 丟棄并記錄日志 | 防止狀態機污染 |
**SYN | PSH** | 中危 | 丟棄 |
FIN-only | 中危 | 丟棄 | 防止連接異常終止 |
RST-only | 高危 | 丟棄并生成警報 | 防止拒絕服務攻擊 |
ACK-only | 低危 | SEQ驗證+流重組 | 防止偽裝控制包(如1057) |
PSH/ACK | 正常 | 延遲處理至應用層消息完整 | 防TLS拆分繞過 |
PSH-only 攻擊漏洞修復測試矩陣
測試用例 | 測試場景 | 測試包構造 | 預期結果 | 驗證指標 |
---|---|---|---|---|
PSH-only攻擊 | 基本漏洞驗證 | flags=PSH 無負載 | 立即丟棄 | 1. 防火墻丟棄計數增加 2. 無審計日志記錄 3. 目標主機無接收 |
合法PSH+ACK | 正常業務驗證 | flags=PSH+ACK 含TLS ClientHello | 正常處理 | 1. SNI成功提取 2. 審計日志完整記錄 3. 應用層正常響應 |
混合標志攻擊 | 高級繞過嘗試 | flags=PSH+URG flags=PSH+SYN | 立即丟棄 | 1. 異常標志告警觸發 2. 連接成功率=0% 3. CPU占用<5% |
洪水攻擊 | 壓力測試 | 1000+ PSH-only包 10Gbps速率 | 全部丟棄 | 1. 吞吐量保持>9.5Gbps 2. 內存波動<2% 3. 無漏包 |
滲透測試 | 真實攻擊模擬 | 使用Metasploit模塊:auxiliary/scanner/portscan/tcp_psh | 完全阻斷 | 1. IDS告警率100% 2. 掃描成功率=0% 3. 無異常連接 |
處理邏輯偽代碼
def handle_tcp_packet(packet):# 丟棄所有PSH-only包if packet.flags == TCP.PSH:log("Invalid PSH-only packet", packet)return DROP# 在已建立連接中丟棄所有non-ACK包if connection.state == ESTABLISHED and not (packet.flags & TCP.ACK):log("Non-ACK packet in established connection", packet)return DROP# 特殊標志組合處理if packet.flags & TCP.SYN and packet.flags & TCP.PSH:log("Suspicious SYN|PSH packet", packet)return DROP# ACK-only包需要嚴格SEQ驗證if packet.flags == TCP.ACK:if not validate_seq(packet.seq, expected_seq):return handle_out_of_order(packet)# PSH|ACK包進入重組緩沖區if packet.flags == (TCP.PSH | TCP.ACK):buffer_packet(packet)if is_application_message_complete():process_application_layer()return PROCESS
TCP 狀態機加固實現
操作系統對TCP標志的標準處理
RFC 793 明確要求
“The ACK bit MUST be set in all packets after the initial SYN packet, unless the RST bit is set.”
(在初始SYN包之后的所有數據包中,除非設置了RST位,否則必須設置ACK位)
3. TLS深度檢測增強
# TLS重組偽代碼
def handle_tls_packet(packet):session = get_session(packet.stream_id)# 驗證SEQ連續性(防御1056插入)if packet.seq != session.expected_seq:if not is_valid_tls_header(packet.data): # 檢查0x16握手標識return DROP # 丟棄插入包session.buffer += packet.data# 檢查TLS頭完整性(前5字節)if len(session.buffer) >= 5:tls_len = (session.buffer[3] << 8) + session.buffer[4] + 5# 緩沖完整消息(防御1055/1057/1059拆分)if len(session.buffer) >= tls_len:process_clienthello(session.buffer[:tls_len]) # 提取SNIsession.buffer = session.buffer[tls_len:]# 設置超時(防御阻塞攻擊)session.timer = set_timeout(500ms, flush_buffer)
4. 流控機制加固
序列號連續性引擎
class SeqTracker:def __init__(self):self.expected_seq = None # 預期序列號self.reassembly_buffer = [] # 重組緩沖區self.max_gap = 8192 # 最大允許序列號間隔def process_packet(self, packet):# 初始序列號設置if self.expected_seq is None:self.expected_seq = packet.seq + len(payload)return PROCESS# 計算序列號差距seq_gap = packet.seq - self.expected_seq# 完美連續包if seq_gap == 0:self.expected_seq += len(packet.payload)return PROCESS# 可接受范圍內的亂序包if 0 < seq_gap <= self.max_gap:self._buffer_packet(packet)return BUFFERED# 惡意序列號跳躍 (如1056插入)if seq_gap > self.max_gap:log_alert(f"Sequence jump attack detected: gap={seq_gap}")return DROP# 重復或舊包 (如1058重傳)if seq_gap < 0:return DUPdef _buffer_packet(self, packet):# 按序列號插入緩沖區bisect.insort(self.reassembly_buffer, packet, key=lambda p: p.seq)# 檢查連續性self._check_continuity()def _check_continuity(self):# 嘗試重組連續數據next_seq = self.expected_seqfor p in sorted(self.reassembly_buffer, key=lambda x: x.seq):if p.seq == next_seq:self.reassembly_buffer.remove(p)next_seq += len(p.payload)else:break# 更新預期序列號if next_seq > self.expected_seq:self.expected_seq = next_seq
應用層感知流控
惡意重傳防御系統
-
重傳檢測矩陣:
特征 正常重傳 惡意重傳 處理方式 SEQ差異 =0 =0 需進一步檢查 有效負載 相同 不同 標記惡意 時間間隔 >RTO <最小閾值(10ms) 標記惡意 標志位 相同 異常組合 丟棄 -
防御規則:
- IF 重傳包.有效負載 != 原始包.有效負載 THEN DROP
- IF 重傳間隔 < 10ms AND 重傳次數 > 3 THEN BLOCK_SESSION
- IF 重傳包.flags 包含非常規標志(如URG) THEN DROP
以下為本文捕獲的漏洞利用的IP報文數據:
WireShark 抓包數據:
1049:
0000 45 00 00 34 d5 f8 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1053:
0000 45 00 00 34 a0 8a 00 00 32 06 08 22 ac fd 72 5a
0010 c0 a8 00 181054:
0000 45 00 00 28 d5 fa 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1055:
0000 45 00 00 2c d5 fb 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1056:
0000 45 00 02 2d d5 fb 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1057:
0000 45 00 00 aa d5 fb 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1058:
0000 45 00 02 2d d5 fb 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1059:
0000 45 00 01 a7 d5 fb 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1067:
0000 01 bb 05 ea b3 21 4d 70 f2 2a 75 ec 80 12 ff ff
0010 1e b8 00 00 02 04 05 96 01 01 04 02 01 03 03 081068:
0000 01 bb 05 ea b3 21 4d 70 f2 2a 75 ec 80 12 ff ff
0010 1e b8 00 00 02 04 05 96 01 01 04 02 01 03 03 081069:
0000 45 00 00 34 d5 fe 40 00 40 06 00 00 c0 a8 00 18
0010 ac fd 72 5a1070:
0000 45 00 00 28 a1 39 00 00 32 06 07 7f ac fd 72 5a
0010 c0 a8 00 181071:
0000 45 00 00 28 a1 3a 00 00 32 06 07 7e ac fd 72 5a
0010 c0 a8 00 181072:
0000 45 00 00 28 a1 3b 00 00 32 06 07 7d ac fd 72 5a
0010 c0 a8 00 181073:
0000 01 bb 05 ea b3 21 4d 71 f2 2a 77 f1 50 10 01 09
0010 dc 87 00 001074:
0000 45 00 05 be a1 3d 00 00 32 06 01 e5 ac fd 72 5a
0010 c0 a8 00 18