From 25b3965e84aee238fac3e18611651340c5062229 Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Mon, 14 Dec 2020 18:08:26 -0800 Subject: [PATCH 1/9] Fixed some basic logic flaws --- jarm.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/jarm.go b/jarm.go index 16aa0f8..06900fb 100644 --- a/jarm.go +++ b/jarm.go @@ -40,16 +40,16 @@ type JarmProbeOptions struct { // GetProbes returns the standard set of JARM probes in the correct order func GetProbes(hostname string, port int) []JarmProbeOptions { - tls12Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_Support", ExtensionOrder: "REVERSE"} - tls12Reverse := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "REVERSE", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_Support", ExtensionOrder: "FORWARD"} - tls12TopHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "TOP_HALF", Grease: "NO_GREASE", ALPN: "NO_SUPPORT", V13Mode: "1.2_Support", ExtensionOrder: "FORWARD"} + tls12Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_SUPPORT", ExtensionOrder: "REVERSE"} + tls12Reverse := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "REVERSE", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_SUPPORT", ExtensionOrder: "FORWARD"} + tls12TopHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "TOP_HALF", Grease: "NO_GREASE", ALPN: "NO_SUPPORT", V13Mode: "1.2_SUPPORT", ExtensionOrder: "FORWARD"} tls12BottomHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "BOTTOM_HALF", Grease: "NO_GREASE", ALPN: "RARE_ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "FORWARD"} tls12MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "RARE_ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "REVERSE"} tls11Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS11, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "FORWARD"} - tls13Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_Support", ExtensionOrder: "REVERSE"} - tls13Reverse := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "REVERSE", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_Support", ExtensionOrder: "FORWARD"} - tls13Invalid := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "NO1.3", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_Support", ExtensionOrder: "FORWARD"} - tls13MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "ALPN", V13Mode: "1.3_Support", ExtensionOrder: "REVERSE"} + tls13Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "REVERSE"} + tls13Reverse := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "REVERSE", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "FORWARD"} + tls13Invalid := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "NO1.3", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "FORWARD"} + tls13MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "REVERSE"} return []JarmProbeOptions{ tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, @@ -153,7 +153,7 @@ func GetCiphers(details JarmProbeOptions) []byte { } } - if details.CipherOrder != "FORWARD" { + if details.CipherOrder == "FORWARD" { ciphers = MungCiphers(ciphers, details.CipherOrder) } From a10202d8d6cd796d8faf8a16ef8da11e20f4ac8e Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Tue, 15 Dec 2020 22:03:21 -0800 Subject: [PATCH 2/9] Fixed grease I was missing. And added logging of raw hash string --- .vscode/launch.json | 17 +++++++++++++++++ jarm.go | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..58750fe --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/jarmscan", + "env": {}, + "args": ["23.115.74.102"] + } + ] +} \ No newline at end of file diff --git a/jarm.go b/jarm.go index 06900fb..527cadb 100644 --- a/jarm.go +++ b/jarm.go @@ -8,6 +8,7 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "log" "math/rand" "strconv" "strings" @@ -153,11 +154,11 @@ func GetCiphers(details JarmProbeOptions) []byte { } } - if details.CipherOrder == "FORWARD" { + if details.CipherOrder != "FORWARD" { ciphers = MungCiphers(ciphers, details.CipherOrder) } - if details.Grease != "GREASE" { + if details.Grease == "GREASE" { ciphers = append([][]byte{RandomGrease()}, ciphers...) } @@ -485,6 +486,7 @@ func RawHashToFuzzyHash(raw string) string { alpex = alpex + comp[2] alpex = alpex + comp[3] } + log.Print(raw) hash256 := sha256.Sum256([]byte(alpex)) fhash += hex.EncodeToString(hash256[:])[0:32] return fhash From 3fc15a9782d0d677969488461d7b0460bcd864fa Mon Sep 17 00:00:00 2001 From: stevenpon Date: Tue, 15 Dec 2020 22:42:50 -0800 Subject: [PATCH 3/9] fix construction of key_share extension --- jarm.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/jarm.go b/jarm.go index 527cadb..1b75a3d 100644 --- a/jarm.go +++ b/jarm.go @@ -53,8 +53,8 @@ func GetProbes(hostname string, port int) []JarmProbeOptions { tls13MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "REVERSE"} return []JarmProbeOptions{ - tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, - } + tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, + } } // GetUint16Bytes returns the 16-bit big endian version of an integer @@ -277,19 +277,20 @@ func ExtGetALPN(details JarmProbeOptions) []byte { // ExtGetKeyShare returns an encoded KeyShare extension func ExtGetKeyShare(grease bool) []byte { - shareExt := []byte{} - shareExt = append(shareExt, 0x00, 0x1d) - shareExt = append(shareExt, 0x00, 0x20) - shareExt = append(shareExt, RandomBytes(32)...) - ext := []byte{0x00, 0x33} + shareExt := []byte{} if grease { - shareExt = append(ext, RandomGrease()...) - shareExt = append(ext, 0x00, 0x01, 0x00) + shareExt = RandomGrease() + shareExt = append(shareExt, 0x00, 0x01, 0x00) } - ext = append(ext, GetUint16Bytes(len(shareExt)+2)...) - ext = append(ext, GetUint16Bytes(len(shareExt))...) + shareExt = append(shareExt, 0x00, 0x1d) + shareExt = append(shareExt, 0x00, 0x20) + shareExt = append(shareExt, RandomBytes(32)...) + secondLength := len(shareExt) + firstLength := secondLength + 2 + ext = append(ext, GetUint16Bytes(firstLength)...) + ext = append(ext, GetUint16Bytes(secondLength)...) ext = append(ext, shareExt...) return ext } From 2d696aa161ba45a7a15fa27bcbe8516fdcd6cd34 Mon Sep 17 00:00:00 2001 From: stevenpon Date: Tue, 15 Dec 2020 22:44:22 -0800 Subject: [PATCH 4/9] fix whitespace --- jarm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jarm.go b/jarm.go index 1b75a3d..22215f4 100644 --- a/jarm.go +++ b/jarm.go @@ -53,7 +53,7 @@ func GetProbes(hostname string, port int) []JarmProbeOptions { tls13MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "REVERSE"} return []JarmProbeOptions{ - tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, + tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, } } @@ -287,8 +287,8 @@ func ExtGetKeyShare(grease bool) []byte { shareExt = append(shareExt, 0x00, 0x1d) shareExt = append(shareExt, 0x00, 0x20) shareExt = append(shareExt, RandomBytes(32)...) - secondLength := len(shareExt) - firstLength := secondLength + 2 + secondLength := len(shareExt) + firstLength := secondLength + 2 ext = append(ext, GetUint16Bytes(firstLength)...) ext = append(ext, GetUint16Bytes(secondLength)...) ext = append(ext, shareExt...) From cd5963c1e4b3b5b3ff1581c52a285e7355ad4107 Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Wed, 16 Dec 2020 01:01:18 -0800 Subject: [PATCH 5/9] Patch supported version ordering and ALPN support on P3 --- jarm.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jarm.go b/jarm.go index 22215f4..bc31bf5 100644 --- a/jarm.go +++ b/jarm.go @@ -43,7 +43,7 @@ type JarmProbeOptions struct { func GetProbes(hostname string, port int) []JarmProbeOptions { tls12Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_SUPPORT", ExtensionOrder: "REVERSE"} tls12Reverse := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "REVERSE", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "1.2_SUPPORT", ExtensionOrder: "FORWARD"} - tls12TopHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "TOP_HALF", Grease: "NO_GREASE", ALPN: "NO_SUPPORT", V13Mode: "1.2_SUPPORT", ExtensionOrder: "FORWARD"} + tls12TopHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "TOP_HALF", Grease: "NO_GREASE", ALPN: "NO_SUPPORT", V13Mode: "NO_SUPPORT", ExtensionOrder: "FORWARD"} tls12BottomHalf := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "BOTTOM_HALF", Grease: "NO_GREASE", ALPN: "RARE_ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "FORWARD"} tls12MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS12, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "RARE_ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "REVERSE"} tls11Forward := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS11, Ciphers: "ALL", CipherOrder: "FORWARD", Grease: "NO_GREASE", ALPN: "ALPN", V13Mode: "NO_SUPPORT", ExtensionOrder: "FORWARD"} @@ -53,8 +53,8 @@ func GetProbes(hostname string, port int) []JarmProbeOptions { tls13MiddleOut := JarmProbeOptions{Hostname: hostname, Port: port, Version: tls.VersionTLS13, Ciphers: "ALL", CipherOrder: "MIDDLE_OUT", Grease: "GREASE", ALPN: "ALPN", V13Mode: "1.3_SUPPORT", ExtensionOrder: "REVERSE"} return []JarmProbeOptions{ - tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, - } + tls12Forward, tls12Reverse, tls12TopHalf, tls12BottomHalf, tls12MiddleOut, tls11Forward, tls13Forward, tls13Reverse, tls13Invalid, tls13MiddleOut, + } } // GetUint16Bytes returns the 16-bit big endian version of an integer @@ -308,8 +308,8 @@ func ExtGetSupportedVersions(details JarmProbeOptions, grease bool) []byte { tlsVersions = append(tlsVersions, []byte{0x03, 0x03}) tlsVersions = append(tlsVersions, []byte{0x03, 0x04}) } - if details.CipherOrder != "FORWARD" { - tlsVersions = MungCiphers(tlsVersions, details.CipherOrder) + if details.ExtensionOrder != "FORWARD" { + tlsVersions = MungCiphers(tlsVersions, details.ExtensionOrder) } ver := []byte{} From 94f87e98d0b196848bd2184b1af814bcf6a6a9dd Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Thu, 17 Dec 2020 12:55:19 -0800 Subject: [PATCH 6/9] Added 0 extensions handling --- jarm.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/jarm.go b/jarm.go index bc31bf5..1c4aa2a 100644 --- a/jarm.go +++ b/jarm.go @@ -374,6 +374,8 @@ func ParseServerHello(data []byte, details JarmProbeOptions) (string, error) { if !(data[0] == 22 && len(data) > 5 && data[5] == 2) { return "|||", nil } + // server_hello_length + server_hello_length := int(binary.BigEndian.Uint16(data[3:5])) // Too short if len(data) < 44 { @@ -388,24 +390,28 @@ func ParseServerHello(data []byte, details JarmProbeOptions) (string, error) { serverCip := hex.EncodeToString(data[cipherOffset : cipherOffset+2]) serverVer := hex.EncodeToString(data[9:11]) - serverExt := ExtractExtensionInfo(data, counter) + serverExt := ExtractExtensionInfo(data, counter, server_hello_length) return fmt.Sprintf("%s|%s|%s", serverCip, serverVer, serverExt), nil } // ExtractExtensionInfo returns parsed extension information from a server hello response -func ExtractExtensionInfo(data []byte, offset int) string { +func ExtractExtensionInfo(data []byte, offset int, server_hello_length int) string { if len(data) < 85 || len(data) < (offset+53) { - return "|||" + return "|" } if data[offset+47] == 11 { - return "|||" + return "|" + } + + if offset+47 >= server_hello_length+5 { + return "|" } if bytes.Equal(data[offset+50:offset+53], []byte{0x0e, 0xac, 0x0b}) || bytes.Equal(data[82:85], []byte{0x0f, 0xf0, 0x0b}) { - return "|||" + return "|" } ecnt := offset + 49 @@ -420,10 +426,10 @@ func ExtractExtensionInfo(data []byte, offset int) string { break } - etypes = append(etypes, data[ecnt:ecnt+2]) if len(data) < ecnt+4 { break } + etypes = append(etypes, data[ecnt:ecnt+2]) extlen := int(binary.BigEndian.Uint16(data[ecnt+2 : ecnt+4])) if len(data) < ecnt+4+extlen { From 720f64f362d0698b30f6270fdbdd19b1ae4fae6b Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Thu, 17 Dec 2020 12:56:04 -0800 Subject: [PATCH 7/9] Removed build info --- .vscode/launch.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 58750fe..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/cmd/jarmscan", - "env": {}, - "args": ["23.115.74.102"] - } - ] -} \ No newline at end of file From 051b7c3402cf40827bcb4d32ee3fa1a5497e2b9c Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Thu, 17 Dec 2020 14:26:50 -0800 Subject: [PATCH 8/9] Removed extra logs --- jarm.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/jarm.go b/jarm.go index 1c4aa2a..764e9e7 100644 --- a/jarm.go +++ b/jarm.go @@ -8,7 +8,6 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "log" "math/rand" "strconv" "strings" @@ -493,7 +492,6 @@ func RawHashToFuzzyHash(raw string) string { alpex = alpex + comp[2] alpex = alpex + comp[3] } - log.Print(raw) hash256 := sha256.Sum256([]byte(alpex)) fhash += hex.EncodeToString(hash256[:])[0:32] return fhash From 3aa804443c836bb2db22c6a1c13896ffd4a00379 Mon Sep 17 00:00:00 2001 From: Joseph Laycock Date: Thu, 17 Dec 2020 20:24:58 -0800 Subject: [PATCH 9/9] Simplified serverHelloLength calc. Used camelCase --- jarm.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jarm.go b/jarm.go index 764e9e7..66b2418 100644 --- a/jarm.go +++ b/jarm.go @@ -374,7 +374,7 @@ func ParseServerHello(data []byte, details JarmProbeOptions) (string, error) { return "|||", nil } // server_hello_length - server_hello_length := int(binary.BigEndian.Uint16(data[3:5])) + serverHelloLength := int(binary.BigEndian.Uint16(data[3:5])) // Too short if len(data) < 44 { @@ -389,13 +389,13 @@ func ParseServerHello(data []byte, details JarmProbeOptions) (string, error) { serverCip := hex.EncodeToString(data[cipherOffset : cipherOffset+2]) serverVer := hex.EncodeToString(data[9:11]) - serverExt := ExtractExtensionInfo(data, counter, server_hello_length) + serverExt := ExtractExtensionInfo(data, counter, serverHelloLength) return fmt.Sprintf("%s|%s|%s", serverCip, serverVer, serverExt), nil } // ExtractExtensionInfo returns parsed extension information from a server hello response -func ExtractExtensionInfo(data []byte, offset int, server_hello_length int) string { +func ExtractExtensionInfo(data []byte, offset int, serverHelloLength int) string { if len(data) < 85 || len(data) < (offset+53) { return "|" } @@ -404,7 +404,7 @@ func ExtractExtensionInfo(data []byte, offset int, server_hello_length int) stri return "|" } - if offset+47 >= server_hello_length+5 { + if offset+42 >= serverHelloLength { return "|" }