refraction-networking / utls

Fork of the Go standard TLS library, providing low-level access to the ClientHello for mimicry purposes.
BSD 3-Clause "New" or "Revised" License
1.57k stars 231 forks source link

Example ImportTLSClientHelloFromJSON #288

Open jonreesman opened 3 months ago

jonreesman commented 3 months ago

I'm curious if I'm missing any instructions on how to add new/custom browser fingerprints. I followed the instructions in the docstrings for ClientHelloSpec.ImportTLSClientHelloFromJSON() and pasted my results from https://client.tlsfingerprint.io using Chrome 122 into a json file.

Using the below code, I was unable to import a new ClientHello:

spec := utls.ClientHelloSpec{}
specFile, err := os.Open("chrome_122.json")
if err != nil {
    log.Fatalf("failed to load spec with err %v", err)
}
rawSpec, err := io.ReadAll(specFile)
if err != nil {
    log.Fatalf("failed to load raw spec with err %v", err)
}
if err := spec.ImportTLSClientHelloFromJSON(rawSpec); err != nil {
    log.Fatalf("failed to read raw spec with err %v", err)
}

My code err'ed out at the last fatal log with err: cannot unmarshal number 4865 into Go value of type uint8

The offending part of chrome_122.json:

{
"cipher_suites": [
        4865,
        4866,
        4867,
        49195,
        49199,
        49196,
        49200,
        52393,
        52392,
        49171,
        49172,
        156,
        157,
        47,
        53
    ],
...
}

Now, it seems to me that either this function is just very outdated and didn't forecast integers of this size in cipher_suite (this is really an issue in most of the fields in the TLS spec now), or perhaps I just misunderstood and am looking in the wrong place to construct a new fingerprint.

Does anyone have better guidance on what the best way to generate new specs would be? It seems Chrome 120 is getting blocked a fair bit (although I was able to get around it with the appropriate HTTP2 fingerprint).

jonreesman commented 3 months ago

Ah, i see now that this was brought up a few months ago here.

So, I suppose that answers my question. A better question would be, has any momentum been built around this feature since?

gaukas commented 3 months ago

We haven't been able to focus on this feature yet since there are much more to be done with TLSfingerprint.io... It is not too bad (see an example here) and we just need more time to actually start working on it ;)

gaukas commented 3 months ago

Just to clarify, the ImportTLSClientHelloFromJSON is meant to allow user importing an existing (known and prerecorded) ClientHello from a database.

The major blocker on this is that we have to make some modifications to TLSfingerprint.io before we can fully support this feature. For now the database from TLSFingerprint.io does not record that many different fields that do not impact the result hash on the website (e.g., the content of ApplicationSettings) but subject to be fingerprintable. It is not a very trivial work as the database might need to be redesigned into an extensible structure, and we DO need stronger database servers 😄


I see you are trying to replicate the ClientHello of your web browser. In which case you might just want to use func (f *Fingerprinter) RawClientHello(raw []byte) (clientHelloSpec *ClientHelloSpec, err error) which takes your ClientHello message as raw bytes.

gaukas commented 3 months ago

And we are also planning to support importing directly from https://client.tlsfingerprint.io/, which would be much easier to achieve since we will not have to modify the database.

jonreesman commented 3 months ago

I appreciate the fast reply, that helped a lot.

For anyone who comes along with this question, it was easy to do this via Wireshark by just grabbing a ClientHello packet from the browser I wanted to fingerprint, and exporting the packet bytes of specifically the TLS frame.

gaukas commented 3 months ago

Just a reminder that the ClientHello you grab from your pcap may or may not fully cover the "ClientHello space" of a TLS client.

For example, Chrome shuffles the TLS extensions list and use a few different combinations of settings in ECH.