Expand JA3 fingerprint database from 4 to 501 profiles

New seed_ja3.py generates comprehensive JA3 TLS fingerprint profiles
covering Chrome/Chromium (100-124 x 4 platforms), Firefox (100-125 x 3),
Edge, Safari (macOS + iOS), Opera, Brave, Tor Browser, Vivaldi, ChromeOS,
TLS libraries (OpenSSL, BoringSSL, GnuTLS, NSS, Go, Java, .NET, Node.js,
mbedTLS, wolfSSL, rustls), common tools (curl, wget, Python, httpx),
mobile clients (Samsung Internet, Android WebView, iOS WKWebView),
VPN clients (AnyConnect, GlobalProtect, OpenVPN, WARP), Electron apps,
and IoT/embedded devices (ESP32, AWS IoT, smart home).

JA3 hashes are computed correctly from TLS ClientHello parameters using
the standard MD5(version,ciphers,extensions,curves,formats) formula.

DevTrack: bigbrother #416
This commit is contained in:
n0mad1k
2026-04-10 07:02:56 -04:00
parent fa0e2491cf
commit 0d92b97682
2 changed files with 989 additions and 80 deletions
+5 -80
View File
@@ -381,88 +381,13 @@ def create_dhcp_fingerprints_db(db_path: str) -> None:
def create_ja3_fingerprints_db(db_path: str) -> None:
"""Create JA3 TLS client fingerprint database.
"""Create and seed JA3 TLS client fingerprint database with 500+ profiles.
JA3 hashes uniquely identify TLS client implementations.
Used by ja3_spoofer to match outbound traffic to common browsers.
Table name and column names match what ja3_spoofer.py queries:
ja3_profiles(name, ja3_hash, description, cipher_suites,
extensions, elliptic_curves, ec_point_formats)
All list columns are stored as JSON arrays.
Uses seed_ja3.py to generate comprehensive profiles across browsers,
TLS libraries, tools, mobile clients, and IoT devices.
"""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA journal_mode=WAL")
conn.executescript("""
CREATE TABLE IF NOT EXISTS ja3_profiles (
name TEXT PRIMARY KEY,
ja3_hash TEXT NOT NULL,
description TEXT DEFAULT '',
cipher_suites TEXT NOT NULL DEFAULT '[]',
extensions TEXT NOT NULL DEFAULT '[]',
elliptic_curves TEXT NOT NULL DEFAULT '[]',
ec_point_formats TEXT NOT NULL DEFAULT '[0]'
);
CREATE INDEX IF NOT EXISTS idx_ja3_hash ON ja3_profiles(ja3_hash);
""")
# Mirror of BUILTIN_PROFILES in ja3_spoofer.py — ensures the DB has
# the same data available for external queries and future updates.
import json as _json
ja3s = [
(
"chrome_120_win",
"cd08e31494f9531f560d64c695473da9",
"Chrome 120 on Windows 10/11",
_json.dumps([0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030,
0xcca9, 0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035]),
_json.dumps([0, 23, 65281, 10, 11, 35, 16, 5, 13, 18, 51, 45, 43, 27, 17513, 21]),
_json.dumps([0x001d, 0x0017, 0x0018]),
_json.dumps([0]),
),
(
"firefox_121_win",
"579ccef312d18482fc42e2b822ca2430",
"Firefox 121 on Windows 10/11",
_json.dumps([0x1301, 0x1303, 0x1302, 0xc02b, 0xc02f, 0xcca9, 0xcca8,
0xc02c, 0xc030, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035]),
_json.dumps([0, 23, 65281, 10, 11, 35, 16, 5, 34, 51, 43, 13, 45, 28, 21]),
_json.dumps([0x001d, 0x0017, 0x0018, 0x0019]),
_json.dumps([0]),
),
(
"edge_120_win",
"b32309a26951912be7dba376398abc3b",
"Edge 120 on Windows 10/11",
_json.dumps([0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030,
0xcca9, 0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035]),
_json.dumps([0, 23, 65281, 10, 11, 35, 16, 5, 13, 18, 51, 45, 43, 27, 17513, 21]),
_json.dumps([0x001d, 0x0017, 0x0018]),
_json.dumps([0]),
),
(
"chrome_120_linux",
"a17a3bfd385b62b1e15606dbd08c9f89",
"Chrome 120 on Linux",
_json.dumps([0x1301, 0x1302, 0x1303, 0xc02b, 0xc02f, 0xc02c, 0xc030,
0xcca9, 0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035]),
_json.dumps([0, 23, 65281, 10, 11, 35, 16, 5, 13, 18, 51, 45, 43, 27, 17513, 21]),
_json.dumps([0x001d, 0x0017, 0x0018]),
_json.dumps([0]),
),
]
conn.executemany(
"INSERT OR IGNORE INTO ja3_profiles "
"(name, ja3_hash, description, cipher_suites, extensions, elliptic_curves, ec_point_formats) "
"VALUES (?, ?, ?, ?, ?, ?, ?)",
ja3s,
)
conn.commit()
count = conn.execute("SELECT COUNT(*) FROM ja3_profiles").fetchone()[0]
conn.close()
from seed_ja3 import seed_ja3_db
count = seed_ja3_db(db_path)
print(f" ja3_fingerprints.db: {count} JA3 profiles")