mic.git


mic

~ proxy for JA4-TLS fingerprinting evasion
git clone https://github.com/djnnvx/mic.git
log | files | refs | archive | README | LICENSE

README.md (6411B)

      1 # mic
      2 
      3 mic (mina-is-cute) is a modular Go proxy for controlling outbound TLS fingerprints.
      4 Pick a browser profile and the proxy connects upstream with the matching
      5 [`bogdanfinn/utls`](https://github.com/bogdanfinn/utls) preset.
      6 
      7 Two modes:
      8 
      9 - **client-front**: HTTP CONNECT proxy with optional MitM TLS interception. The proxy
     10   generates a local CA, issues per-host leaf certs on the fly, terminates TLS from
     11   the client, and re-dials the target with the configured fingerprint. Standard
     12   tools (curl, browsers) work after importing the CA once.
     13 - **server-front**: the proxy terminates incoming TLS with your own cert/key, then
     14   re-dials the backend with the configured fingerprint. Use it when the client cannot
     15   be pointed at a CONNECT proxy.
     16 
     17 ## How it works
     18 
     19 ```mermaid
     20 sequenceDiagram
     21     participant C as Client
     22     participant P as mic proxy
     23     participant T as Target
     24 
     25     rect rgb(30, 30, 60)
     26         note over C,T: client-front mode (MitM TLS)
     27         C->>P: HTTP CONNECT target:443
     28         P->>T: TCP + uTLS handshake (configured fingerprint)
     29         note right of P: JA4 = configured profile
     30         P-->>C: 200 Connection Established
     31         C->>P: TLS handshake (mic-issued cert for target)
     32         P-->>C: TLS established
     33         note left of P: JA4S = stdlib crypto/tls (measured only)
     34         C->>P: HTTP request (decrypted by proxy)
     35         P->>T: request bytes (through uTLS tunnel)
     36         T-->>P: HTTP response (through uTLS)
     37         P-->>C: HTTP response (re-encrypted for client)
     38     end
     39 
     40     rect rgb(30, 60, 30)
     41         note over C,T: server-front mode
     42         C->>P: TLS handshake (proxy cert)
     43         P-->>C: TLS established
     44         note left of P: JA4S = stdlib crypto/tls (measured only)
     45         P->>T: TCP + uTLS handshake (configured fingerprint)
     46         note right of P: JA4 = configured profile
     47         C->>P: HTTP request (decrypted by proxy)
     48         P->>T: request bytes (through uTLS tunnel)
     49         T-->>P: HTTP response (through uTLS)
     50         P-->>C: HTTP response (re-encrypted for client)
     51     end
     52 ```
     53 
     54 The ServerHello mic returns to the client (JA4S) still comes from stdlib
     55 `crypto/tls`. It is measured, not spoofed. See the JA4S section.
     56 
     57 ## Build
     58 
     59 ```bash
     60 go build -o mic .
     61 ```
     62 
     63 ## Running
     64 
     65 ### client-front
     66 
     67 ```bash
     68 mic client --listen :8080 --fingerprint chrome-120 \
     69            --intercept-cert ca.pem --intercept-key ca-key.pem
     70 ```
     71 
     72 `--intercept-cert` and `--intercept-key` enable MitM interception. mic generates the
     73 CA files on first run and reuses them. Omit both to run as a plain CONNECT proxy with
     74 a raw tunnel and no MitM.
     75 
     76 **Trust the CA** (pick whichever applies):
     77 
     78 ```bash
     79 # curl: pass on every call, or set CURL_CA_BUNDLE
     80 curl --cacert ca.pem -x http://localhost:8080 https://tlsinfo.me/json
     81 
     82 # Debian / Ubuntu / Kali
     83 sudo cp ca.pem /usr/local/share/ca-certificates/mic-ca.crt && sudo update-ca-certificates
     84 
     85 # macOS
     86 sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.pem
     87 ```
     88 
     89 Once trusted, no extra flags are needed:
     90 
     91 ```bash
     92 curl -x http://localhost:8080 https://tlsinfo.me/json
     93 # check the "ja4" field. It should match the fingerprint you configured.
     94 ```
     95 
     96 ### server-front
     97 
     98 Generate a cert for the proxy to present to clients:
     99 
    100 ```bash
    101 go run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host="localhost,127.0.0.1"
    102 # produces cert.pem and key.pem
    103 ```
    104 
    105 ```bash
    106 mic server --listen :8080 --backend 10.0.0.1:443 \
    107            --cert cert.pem --key key.pem \
    108            --fingerprint chrome-120
    109 ```
    110 
    111 `--backend`, `--cert`, and `--key` are required. `--fingerprint` is optional. Without
    112 it the proxy falls back to a randomised uTLS preset.
    113 
    114 ### Available fingerprint profiles
    115 
    116 Hashes are measured by `cmd/probe` against tlsinfo.me and reflect what each utls
    117 preset actually emits. Re-run the probe after upgrading the utls dependency.
    118 
    119 | Profile | JA4 hash |
    120 |---|---|
    121 | `chrome-120` | `t13d1516h2_8daaf6152771_02713d6af862` |
    122 | `chrome-120-pq` | same as `chrome-120`¹ |
    123 | `chrome-131` | same as `chrome-120`¹ |
    124 | `chrome-133` | `t13d1516h2_8daaf6152771_d8a2da3f94cd` |
    125 | `firefox-120` | `t13d1715h2_5b57614c22b0_5c2c66f702b0` |
    126 | `safari-16` | `t13d2014h2_a09f3c656075_14788d8d241b` |
    127 | `ios-16` | same as `safari-16`² |
    128 | `edge-85` | `t13d1515h2_8daaf6152771_de4a06bb82e3` |
    129 | `edge-106` | `t13d1516h2_8daaf6152771_e5627efa2ab1` |
    130 | `opera-91` | same as `edge-106`³ |
    131 | `android-11-okhttp` | `t12d120700_d34a8e72043a_036209cd1ead` (TLS 1.2) |
    132 | `ipad-15` | same as `safari-16`² |
    133 | `qq-11` | same as `edge-106`³ |
    134 | `360-7` | `t12d2010s2_0bf03fa604e3_736b2a1ed4d3` (TLS 1.2, spdy ALPN) |
    135 | `360-11` | `t13d1616h2_46e7e9700bed_4551aecd7b38` |
    136 
    137 > ¹ JA4 does not distinguish key share entries. Use `chrome-120-pq` when you need the
    138 > X25519MLKEM768 post-quantum key exchange, `chrome-131` for the newest non-PQ Chrome
    139 > preset under this hash.
    140 >
    141 > ² `ios-16`, `ipad-15` and `safari-16` ship the same TLS stack.
    142 >
    143 > ³ `opera-91`, `qq-11` and `edge-106` are all Chromium derivatives with the same
    144 > ClientHello shape.
    145 
    146 ## Testing
    147 
    148 ```bash
    149 # unit tests
    150 go test ./...
    151 
    152 # integration tests: spin up in-process TLS servers, no network required
    153 go test -tags integration -v ./proxy/... ./fingerprint/...
    154 ```
    155 
    156 `TestClientFront_JA4` and `TestServerFront_JA4` capture the raw ClientHello the uTLS
    157 engine sends for each profile and assert the computed JA4 hash. This is the offline
    158 equivalent of running `cmd/probe` against tlsinfo.me.
    159 
    160 CI runs both suites on every push via `.github/workflows/ci.yml`.
    161 
    162 ## JA4S (server-side fingerprint, measurement only)
    163 
    164 mic computes JA4S, the fingerprint of the ServerHello it emits to clients. There is no
    165 spoofing engine. `TestServerFront_JA4S_Baseline` and `TestClientFront_JA4S_Baseline`
    166 capture the bytes mic writes during the handshake and assert the JA4S against a
    167 recorded baseline.
    168 
    169 The baseline is what stdlib `crypto/tls.Server` emits today: `t130200_1301_a56c5b993250`
    170 (TLS 1.3, no ALPN, `TLS_AES_128_GCM_SHA256`, default extension set). It applies to
    171 both modes because both terminate TLS with the same stdlib server.
    172 
    173 Why no spoofing yet:
    174 
    175 - `bogdanfinn/utls` does not expose server-side fingerprint control. Its `Server()`
    176   delegates to stdlib's TLS state machine.
    177 - TLS 1.3 ServerHello carries only 2-3 extensions, so the JA4S surface is much
    178   smaller than JA4.
    179 
    180 Spoofing would need either a utls fork adding a `ServerHelloSpec`, or a custom TLS server.