sub2api/antigravity/capture/capture_tls.sh
win 85ed193ff0
Some checks failed
CI / test (push) Failing after 10s
CI / golangci-lint (push) Failing after 6s
Security Scan / backend-security (push) Failing after 8s
Security Scan / frontend-security (push) Failing after 7s
feat(tls): 更新 DoWithTLS 所有调用点至新三模式签名
- DoWithTLS 签名变更:(bool/profile) → (TLSMode, profile)
- 所有调用方传入 account.GetTLSMode() 以支持 node/utls/off 三模式
- gateway_service.go、gemini_messages_compat、forward_as_* 全部更新
- claude_usage_service 的 ClaudeUsageFetchOptions 新增 TLSMode 字段
- 新增 decompressResponseBody(gzip/brotli/deflate)到 http_upstream.go
- 新增 antigravity_privacy_service.go(setAntigravityPrivacy)
- admin_service 新增 ForceOpenAIPrivacy/EnsureAntigravityPrivacy/ForceAntigravityPrivacy
- antigravity.Client 新增 SetUserSettings/FetchUserInfo API
2026-03-27 22:29:17 +08:00

219 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────
# capture_tls.sh - Capture TLS ClientHello fingerprints (JA3)
#
# mitmproxy terminates TLS so it can't see the real JA3 that
# Claude CLI / Antigravity sends to Anthropic. This script
# captures the REAL TLS fingerprint using tshark.
#
# Usage:
# # Run BEFORE starting claude login / claude "hello"
# # (don't use HTTPS_PROXY for this - direct connection)
#
# sudo ./capture_tls.sh # capture on default interface
# sudo ./capture_tls.sh en0 # specify interface
# sudo ./capture_tls.sh en0 30 # capture for 30 seconds
#
# Output:
# ./captures/tls_capture_<timestamp>.txt
# ./captures/tls_capture_<timestamp>.pcap
# ─────────────────────────────────────────────────────────────
set -euo pipefail
IFACE="${1:-en0}"
DURATION="${2:-60}"
OUTDIR="./captures"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
PCAP_FILE="${OUTDIR}/tls_capture_${TIMESTAMP}.pcap"
TXT_FILE="${OUTDIR}/tls_capture_${TIMESTAMP}.txt"
mkdir -p "$OUTDIR"
# Resolve target IPs
echo "Resolving target domains..."
DOMAINS=(
"api.anthropic.com"
"platform.claude.com"
"claude.ai"
"cloudaicompanion.googleapis.com"
"generativelanguage.googleapis.com"
"oauth2.googleapis.com"
"accounts.google.com"
)
HOST_FILTER=""
for domain in "${DOMAINS[@]}"; do
ips=$(dig +short "$domain" 2>/dev/null | grep -E '^[0-9]+\.' | head -5)
for ip in $ips; do
if [ -n "$HOST_FILTER" ]; then
HOST_FILTER="$HOST_FILTER or host $ip"
else
HOST_FILTER="host $ip"
fi
done
echo " $domain$ips"
done
if [ -z "$HOST_FILTER" ]; then
echo "ERROR: Could not resolve any target domains"
exit 1
fi
CAPTURE_FILTER="tcp port 443 and ($HOST_FILTER)"
echo ""
echo "═══════════════════════════════════════════════════════"
echo " TLS Fingerprint Capture"
echo " Interface: $IFACE"
echo " Duration: ${DURATION}s"
echo " Filter: $CAPTURE_FILTER"
echo " PCAP: $PCAP_FILE"
echo " Report: $TXT_FILE"
echo "═══════════════════════════════════════════════════════"
echo ""
echo ">>> Now run 'claude login' or 'claude \"hello\"' in another terminal <<<"
echo ">>> Press Ctrl+C to stop early <<<"
echo ""
# Capture pcap in background
tshark -i "$IFACE" -f "$CAPTURE_FILTER" -w "$PCAP_FILE" -a "duration:$DURATION" 2>/dev/null &
TSHARK_PID=$!
# Wait for capture to complete or Ctrl+C
trap "kill $TSHARK_PID 2>/dev/null; wait $TSHARK_PID 2>/dev/null" INT TERM
wait $TSHARK_PID 2>/dev/null || true
echo ""
echo "Capture complete. Analyzing..."
echo ""
# ─── Analysis ───
{
echo "═══════════════════════════════════════════════════════"
echo " TLS ClientHello Fingerprint Report"
echo " Captured: $(date)"
echo " PCAP: $PCAP_FILE"
echo "═══════════════════════════════════════════════════════"
echo ""
# Extract JA3 fingerprints
echo "─── JA3 Fingerprints (ClientHello) ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e frame.time \
-e ip.dst \
-e tls.handshake.extensions_server_name \
-e tls.handshake.ja3 \
-e tls.handshake.ja3_full \
2>/dev/null | while IFS=$'\t' read -r ts dst sni ja3 ja3_full; do
echo " Time: $ts"
echo " Dest IP: $dst"
echo " SNI: $sni"
echo " JA3 Hash: $ja3"
if [ -n "$ja3_full" ]; then
echo " JA3 Full: $ja3_full"
fi
echo ""
done
echo ""
echo "─── TLS Versions ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.version \
-e tls.handshake.extensions.supported_version \
2>/dev/null | sort -u | while IFS=$'\t' read -r sni ver supported; do
echo " SNI: $sni"
echo " Record Version: $ver"
echo " Supported Versions: $supported"
echo ""
done
echo ""
echo "─── ALPN Protocols ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.extensions_alpn_str \
2>/dev/null | sort -u | while IFS=$'\t' read -r sni alpn; do
echo " SNI: $sni → ALPN: $alpn"
done
echo ""
echo ""
echo "─── Cipher Suites (per ClientHello) ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.ciphersuite \
2>/dev/null | head -5 | while IFS=$'\t' read -r sni ciphers; do
echo " SNI: $sni"
echo " Cipher Suites:"
echo " $ciphers" | tr ',' '\n' | while read -r c; do
echo " $c"
done
echo ""
done
echo ""
echo "─── Extensions (per ClientHello) ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.extension.type \
2>/dev/null | head -5 | while IFS=$'\t' read -r sni exts; do
echo " SNI: $sni"
echo " Extensions: $exts"
echo ""
done
echo ""
echo "─── Unique JA3 Summary ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tls.handshake.type == 1" \
-T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.ja3 \
2>/dev/null | sort | uniq -c | sort -rn | while read -r count sni ja3; do
echo " ${count}x SNI: $sni JA3: $ja3"
done
echo ""
echo "─── TCP Fingerprint (Initial Window Size, TTL) ───"
echo ""
tshark -r "$PCAP_FILE" \
-Y "tcp.flags.syn == 1 && tcp.flags.ack == 0" \
-T fields \
-e ip.dst \
-e ip.ttl \
-e tcp.window_size_value \
-e tcp.options.mss_val \
-e tcp.options.wscale.shift \
2>/dev/null | sort -u | while IFS=$'\t' read -r dst ttl win mss wscale; do
echo " Dest: $dst TTL: $ttl Window: $win MSS: $mss WScale: $wscale"
done
} 2>/dev/null | tee "$TXT_FILE"
echo ""
echo "═══════════════════════════════════════════════════════"
echo " Report saved to: $TXT_FILE"
echo " PCAP saved to: $PCAP_FILE"
echo ""
echo " To re-analyze: tshark -r $PCAP_FILE -Y 'tls.handshake.type==1' ..."
echo "═══════════════════════════════════════════════════════"