refraction-networking / utls

Fork of the Go standard TLS library, providing low-level access to the ClientHello for mimicry purposes.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Question] How to capture TLS clienthello handshake raw data on a server?

1366613 opened this issue · comments

I need to capture the client hello message in a server context to generate a ja3 hash from it.
Though I'm currently using gopacket, things are a bit messy.
As far as I see, the vanilla crypto/tls misses one key piece of data in order to generate a ja3 hash.
Is it possible with utls?

To capture TLS clienthello handshake raw data on a server, I am assuming you mean to capture the raw packet/bytes sent on wire.

I am not understanding what is your use case so here are some general advices.

Despite tcpdump/wireshark and other pcap tools, if you want to process/handle your ClientHello in real-time, you may go with the approach of tlsfingerprint.io, which is powered by clienthellod (demo).

Just to clarify, refraction's TLS suite (utls, tlsfingerprint.io, clienthellod) DOES NOT use or provide support for JA3 hashes, which means you will have to implement it for your own use cases.

Sorry for comment on closed issue.
If you want to get raw ClientHello bytes inside your golang application, you can take a look at https://github.com/fedosgad/mirror_proxy/blob/master/hijackers/utls.go (disclaimer: I'm the author). This is exactly what is done in the code in order to mimic incoming connection's TLS fingerprint.

@fedosgad Doesn't it use any C bindings anywhere in the chain?
Can this be used in the context of a custom net listener?

@aurora1369
No C bindings are used.
If you mean context.Context, then I'm not sure (AFAIK stdlib's net.Listener methods usually do not accept context.Context). Otherwise - yes (it is actually the way I did it).

commented

@fedosgad Doesn't it use any C bindings anywhere in the chain? Can this be used in the context of a custom net listener?

you can use gopacket/pcap

handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever)
var filter string = "tcp and port 443"
	if err := handle.SetBPFFilter(filter); err != nil {
		log.Fatal(err)
	}
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
tcpLayer := packet.Layer(layers.LayerTypeTCP)
		if tcpLayer == nil {
			panic("TCP layer not found")
		}
tcp, _ := tcpLayer.(*layers.TCP)
}

then look for first tcp.Payload which has 0x16 as first byte and send it ReadClientHello: ch2, err := clienthellod.ReadClientHello(bytes.NewReader(tcp.Payload))