分析命令與控制通訊
使用時機
- 逆向工程一個惡意軟體樣本時,發現其網路通訊需要協定分析
- 針對特定 C2 框架(Cobalt Strike、Metasploit、Sliver)建立網路層級的偵測特徵
- 繪製 C2 基礎設施,包含主要伺服器、備用網域與死信信箱
- 分析加密或編碼的 C2 流量,以了解命令集與資料格式
- 根據 C2 基礎設施模式與工具集,將惡意軟體歸因給特定威脅行為者
請勿使用於一般網路異常偵測;此技能僅針對從惡意軟體分析中得知或懷疑的 C2 協定進行深入理解。
前提條件
- 惡意軟體網路流量的 PCAP 封包擷取(來自沙箱、網路分流器或完整封包擷取)
- Wireshark/tshark 進行封包層級分析
- 逆向工程工具(Ghidra、dnSpy)用以理解惡意軟體二進位檔中的 C2 程式碼
- Python 3.8+ 搭配
scapy、dpkt與requests進行協定分析與重播 - 威脅情資資料庫用於 C2 基礎設施關聯(VirusTotal、Shodan、Censys)
- JA3/JA3S 指紋資料庫用於基於 TLS 的 C2 識別
工作流程
步驟 1:識別 C2 通道
判斷 C2 通訊所使用的協定與傳輸方式:
C2 通訊通道:
━━━━━━━━━━━━━━━━━━━━━━━━━
HTTP/HTTPS: 最常見;使用標準網路流量以融入其中
指標:規律的 POST/GET 請求、特定 URI 模式、自訂標頭
DNS: 透過 DNS 查詢與回應隧道傳輸資料
指標:高頻率的 TXT 查詢、長的子網域名稱、高熵值
自訂 TCP/UDP: 專有二進位協定,使用非標準通訊埠
指標:高埠上的非 HTTP 流量、未知協定
ICMP: 資料編碼於 ICMP 回應/回覆的酬載中
指標:酬載過大或格式異常的 ICMP 封包
WebSocket: 持續的雙向連線,用於即時 C2
指標:WebSocket 升級後緊接二進位框架
雲端服務: 使用合法的 API(Telegram、Discord、Slack、GitHub)
指標:來自非預期程序的雲端服務 API 呼叫
電子郵件: SMTP/IMAP 用於 C2 命令與資料外洩
指標:來自非郵件程式的自動電子郵件操作
步驟 2:分析信標模式
描述規律的通訊模式:
from scapy.all import rdpcap, IP, TCP
from collections import defaultdict
import statistics
import json
packets = rdpcap("c2_traffic.pcap")
# 按目的地分組 TCP SYN 封包
connections = defaultdict(list)
for pkt in packets:
if IP in pkt and TCP in pkt and (pkt[TCP].flags & 0x02):
key = f"{pkt[IP].dst}:{pkt[TCP].dport}"
connections[key].append(float(pkt.time))
# 分析每個目的地是否有信標行
for dst, times in sorted(connections.items()):
if len(times) < 3:
continue
intervals = [times[i+1] - times[i] for i in range(len(times)-1)]
avg_interval = statistics.mean(intervals)
stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0
jitter_pct = (stdev / avg_interval * 100) if avg_interval > 0 else 0
duration = times[-1] - times[0]
beacon_data = {
"destination": dst,
"connections": len(times),
"duration_seconds": round(duration, 1),
"avg_interval_seconds": round(avg_interval, 1),
"stdev_seconds": round(stdev, 1),
"jitter_percent": round(jitter_pct, 1),
"is_beacon": 5 < avg_interval < 7200 and jitter_pct < 25,
}
if beacon_data["is_beacon"]:
print(f"[!] 偵測到信標:{dst}")
print(f" 間隔:{avg_interval:.0f}s +/- {stdev:.0f}s ({jitter_pct:.0f}% 抖動)")
print(f" 連線數:{len(times)},持續 {duration:.0f}s")
步驟 3:解碼 C2 協定結構
從捕獲的流量中逆向分析訊息格式:
# 基於 HTTP 的 C2 協定分析
import dpkt
import base64
with open("c2_traffic.pcap", "rb") as f:
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
if not isinstance(eth.data, dpkt.ip.IP):
continue
ip = eth.data
if not isinstance(ip.data, dpkt.tcp.TCP):
continue
tcp = ip.data
if tcp.dport == 80 or tcp.dport == 443:
if len(tcp.data) > 0:
try:
http = dpkt.http.Request(tcp.data)
print(f"\n--- C2 請求 ---")
print(f"方法:{http.method}")
print(f"URI:{http.uri}")
print(f"標頭:{dict(http.headers)}")
if http.body:
print(f"主體({len(http.body)} 位元組):")
# 嘗試 Base64 解碼
try:
decoded = base64.b64decode(http.body)
print(f" 解碼後:{decoded[:200]}")
except:
print(f" 原始:{http.body[:200]}")
except:
pass
步驟 4:識別 C2 框架
將觀察到的模式與已知的 C2 框架進行比對:
已知 C2 框架特徵:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cobalt Strike:
- 預設 URI:/pixel、/submit.php、/___utm.gif、/ca、/dpixel
- Malleable C2 設定檔可自訂所有流量特徵
- JA3:依設定檔而異,可查閱 ja3er.com
- Beacon 設定中的浮水印(每個授權唯一)
- 設定檔提取:使用 CobaltStrikeParser 或 1768.py
Metasploit/Meterpreter:
- 預設階段 URI 模式:隨機 4 字元檢查碼
- 反向 HTTP(S) 處理器模式
- Meterpreter TLV(Type-Length-Value)協定結構
Sliver:
- 支援 mTLS、HTTP、DNS、WireGuard 傳輸選項
- Protobuf 編碼的訊息
- 通訊中包含唯一的植入識別碼
Covenant:
- 基於 .NET 的 C2 框架
- 可自訂設定檔的 HTTP 通訊
- 基於任務的命令執行
PoshC2:
- 基於 PowerShell/C#
使用加密酬載的 HTTP 通訊
- 基於 Cookie 的工作階段管理
# 從 PCAP 或樣本中提取 Cobalt Strike Beacon 設定
python3 << 'PYEOF'
# 使用 CobaltStrikeParser(pip install cobalt-strike-parser)
from cobalt_strike_parser import BeaconConfig
try:
config = BeaconConfig.from_file("suspect.exe")
print("Cobalt Strike Beacon 設定:")
for key, value in config.items():
print(f" {key}: {value}")
except Exception as e:
print(f"不是 Cobalt Strike Beacon 或解析錯誤:{e}")
PYEOF
步驟 5:繪製 C2 基礎設施
記錄完整的 C2 基礎設施與容錯轉移機制:
# 基礎設施對應
import requests
import json
c2_indicators = {
"primary_c2": "185.220.101.42",
"domains": ["update.malicious.com", "backup.evil.net"],
"ports": [443, 8443],
"failover_dns": ["ns1.malicious-dns.com"],
}
# 使用 Shodan 豐富化
def shodan_lookup(ip, api_key):
resp = requests.get(f"https://api.shodan.io/shodan/host/{ip}?key={api_key}")
if resp.status_code == 200:
data = resp.json()
return {
"ip": ip,
"ports": data.get("ports", []),
"os": data.get("os"),
"org": data.get("org"),
"asn": data.get("asn"),
"country": data.get("country_code"),
"hostnames": data.get("hostnames", []),
"last_update": data.get("last_update"),
}
return None
# 使用被動 DNS 豐富化
def pdns_lookup(domain):
# 使用 VirusTotal 被動 DNS
resp = requests.get(
f"https://www.virustotal.com/api/v3/domains/{domain}/resolutions",
headers={"x-apikey": VT_API_KEY}
)
if resp.status_code == 200:
data = resp.json()
resolutions = []
for r in data.get("data", []):
resolutions.append({
"ip": r["attributes"]["ip_address"],
"date": r["attributes"]["date"],
})
return resolutions
return []
步驟 6:建立網路偵測特徵
根據分析出的 C2 特性建立偵測規則:
# 分析出的 C2 的 Suricata 規則
cat << 'EOF' > c2_detection.rules
# HTTP 信標模式
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX C2 信標 HTTP";
flow:established,to_server;
http.method; content:"POST";
http.uri; content:"/gate.php"; startswith;
http.header; content:"User-Agent: Mozilla/5.0 (compatible; MSIE 10.0)";
threshold:type threshold, track by_src, count 5, seconds 600;
sid:9000010; rev:1;
)
# JA3 指紋比對
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX TLS JA3 指紋";
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
sid:9000011; rev:1;
)
# DNS 信標偵測(高熵子網域)
alert dns $HOME_NET any -> any any (
msg:"MALWARE 疑似 DNS C2 隧道";
dns.query; pcre:"/^[a-z0-9]{20,}\./";
threshold:type threshold, track by_src, count 10, seconds 60;
sid:9000012; rev:1;
)
# 基於憑證的偵測
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"MALWARE MalwareX 自簽 C2 憑證";
tls.cert_subject; content:"CN=update.malicious.com";
sid:9000013; rev:1;
)
EOF
關鍵概念
| 術語 | 定義 |
|---|---|
| 信標行 | 惡意軟體以規律間隔向 C2 伺服器進行的定期簽到通訊,通常帶有抖動以避免模式偵測 |
| 抖動 | 應用於信標間隔的隨機化(例如 60s +/- 15%),使時間模式更難預測與偵測 |
| Malleable C2 | Cobalt Strike 功能,允許操作者自訂 C2 流量的所有面向(URI、標頭、編碼)以模仿合法服務 |
| 死信信箱 | 中繼位置(如貼文網站、雲端儲存、社群媒體),C2 命令在此發布,供惡意軟體擷取 |
| 域前置 | 在 TLS SNI 中使用受信任的 CDN 網域,同時將流量路由至不同的後端,使 C2 流量看起來流向合法服務 |
| 快速變換 | 迅速變更 C2 網域的 DNS 記錄,以分散流量至多個 IP,抵抗下架行動 |
| C2 框架 | 提供 C2 伺服器、植入產生器與操作者介面的軟體工具集(Cobalt Strike、Metasploit、Sliver、Covenant) |
工具與系統
- Wireshark:封包分析器,用於在封包層級進行詳細的 C2 協定分析
- RITA (Real Intelligence Threat Analytics):開源工具,分析 Zeek 日誌以進行信標偵測與 DNS 隧道偵測 |
- CobaltStrikeParser:從樣本與記憶體傾印中提取 Cobalt Strike Beacon 設定的工具
- JA3/JA3S:用於透過 TLS 實作特徵識別 C2 框架的 TLS 指紋識別方法
- Shodan/Censys:網路掃描平台,用於繪製 C2 基礎設施與識別相關伺服器
常見情境
情境:逆向工程自訂 C2 協定
背景:一個惡意軟體樣本使用未知的二進位協定,透過 TCP 通訊埠 8443 與其 C2 伺服器通訊。需要解碼此協定以了解命令集並建立偵測特徵。
方法:
- 過濾 PCAP 中 TCP 8443 埠的交談,並提取 TCP 串流
- 分析前幾次交握以識別交握/驗證機制
- 繪製訊息結構(長度前綴、類型欄位、酬載編碼)
- 與 Ghidra 反組譯的惡意軟體發送/接收函式進行交叉比對
- 識別命令調度器,並記錄每個命令碼的功能
- 以 Python 建立協定解碼器,用於持續流量分析
- 建立比對協定交握或靜態標頭位元組的 Suricata 規則
常見陷阱:
- 假設協定是靜態的;某些 C2 框架在交握期間會協商加密
- 未捕獲足夠流量以查看所有命令類型(有些命令很少出現)
- 遺漏在主通道失敗時啟動的備用 C2 通道(DNS、ICMP)
- 將加密的酬載資料與協定框架結構混淆
輸出格式
C2 通訊分析報告
===================================
樣本: malware.exe (SHA-256: e3b0c44...)
C2 框架: Cobalt Strike 4.9
信標設定
C2 伺服器: hxxps://185.220.101[.]42/updates
信標類型: HTTPS (反向)
休眠時間: 60 秒
抖動: 15%
使用者代理: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
URI (GET): /dpixel
URI (POST): /submit.php
浮水印: 1234567890
協定分析
傳輸方式: HTTPS (TLS 1.2)
JA3 雜湊: a0e9f5d64349fb13191bc781f81f42e1
憑證: CN=Microsoft Update (自簽)
編碼: Base64 搭配 XOR 金鑰 0x69
命令格式: [4B 長度][4B 命令 ID][酬載]
命令集
0x01 - 休眠 變更信標間隔
0x02 - Shell 執行 cmd.exe 命令
0x03 - 下載 從 C2 傳輸檔案
0x04 - 上傳 將檔案外洩至 C2
0x05 - 注入 程序注入
0x06 - 鍵盤記錄 啟動鍵盤記錄器
0x07 - 螢幕截圖 捕捉螢幕畫面
基礎設施
主要: 185.220.101[.]42 (AS12345, Hosting Co, NL)
備用: 91.215.85[.]17 (AS67890, VPS Provider, RU)
DNS: update.malicious[.]com -> 185.220.101[.]42
註冊商: NameCheap
註冊日期: 2025-09-01
偵測特徵
SID 9000010: HTTP 信標模式
SID 9000011: JA3 TLS 指紋
SID 9000013: C2 憑證比對