Commit f1dd9f2b authored by Matthew Holt's avatar Matthew Holt

mitm: Improve detection related to Chrome and Safari on iOS

Include test for iOS 11 beta
parent 6aba4a31
...@@ -361,7 +361,7 @@ func (info rawHelloInfo) looksLikeFirefox() bool { ...@@ -361,7 +361,7 @@ func (info rawHelloInfo) looksLikeFirefox() bool {
// "To determine whether a Firefox session has been // "To determine whether a Firefox session has been
// intercepted, we check for the presence and order // intercepted, we check for the presence and order
// of extensions, cipher suites, elliptic curves, // of extensions, cipher suites, elliptic curves,
// EC point formats, and handshake compression methods." // EC point formats, and handshake compression methods." (early 2016)
// We check for the presence and order of the extensions. // We check for the presence and order of the extensions.
// Note: Sometimes 0x15 (21, padding) is present, sometimes not. // Note: Sometimes 0x15 (21, padding) is present, sometimes not.
...@@ -431,7 +431,7 @@ func (info rawHelloInfo) looksLikeChrome() bool { ...@@ -431,7 +431,7 @@ func (info rawHelloInfo) looksLikeChrome() bool {
// to not support, but do not check for the inclusion of // to not support, but do not check for the inclusion of
// specific ciphers or extensions, nor do we validate their // specific ciphers or extensions, nor do we validate their
// order. When appropriate, we check the presence and order // order. When appropriate, we check the presence and order
// of elliptic curves, compression methods, and EC point formats." // of elliptic curves, compression methods, and EC point formats." (early 2016)
// Not in Chrome 56, but present in Safari 10 (Feb. 2017): // Not in Chrome 56, but present in Safari 10 (Feb. 2017):
// TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024) // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
...@@ -488,7 +488,7 @@ func (info rawHelloInfo) looksLikeEdge() bool { ...@@ -488,7 +488,7 @@ func (info rawHelloInfo) looksLikeEdge() bool {
// "SChannel connections can by uniquely identified because SChannel // "SChannel connections can by uniquely identified because SChannel
// is the only TLS library we tested that includes the OCSP status // is the only TLS library we tested that includes the OCSP status
// request extension before the supported groups and EC point formats // request extension before the supported groups and EC point formats
// extensions." // extensions." (early 2016)
// //
// More specifically, the OCSP status request extension appears // More specifically, the OCSP status request extension appears
// *directly* before the other two extensions, which occur in that // *directly* before the other two extensions, which occur in that
...@@ -534,24 +534,28 @@ func (info rawHelloInfo) looksLikeSafari() bool { ...@@ -534,24 +534,28 @@ func (info rawHelloInfo) looksLikeSafari() bool {
// in the HTTP User-Agent header. We allow for any of the // in the HTTP User-Agent header. We allow for any of the
// updates when validating handshakes, and we check for the // updates when validating handshakes, and we check for the
// presence and ordering of ciphers, extensions, elliptic // presence and ordering of ciphers, extensions, elliptic
// curves, and compression methods." // curves, and compression methods." (early 2016)
// Note that any C lib (e.g. curl) compiled on macOS // Note that any C lib (e.g. curl) compiled on macOS
// will probably use Secure Transport which will also // will probably use Secure Transport which will also
// share the TLS handshake characteristics of Safari. // share the TLS handshake characteristics of Safari.
// Let's do the easy check first... should be sufficient in many cases.
if len(info.cipherSuites) < 1 {
return false
}
if info.cipherSuites[0] != scsvRenegotiation {
return false
}
// We check for the presence and order of the extensions. // We check for the presence and order of the extensions.
requiredExtensionsOrder := []uint16{10, 11, 13, 13172, 16, 5, 18, 23} requiredExtensionsOrder := []uint16{10, 11, 13, 13172, 16, 5, 18, 23}
if !assertPresenceAndOrdering(requiredExtensionsOrder, info.extensions, true) { if !assertPresenceAndOrdering(requiredExtensionsOrder, info.extensions, true) {
return false // Safari on iOS 11 (beta) uses different set/ordering of extensions
requiredExtensionsOrderiOS11 := []uint16{65281, 0, 23, 13, 5, 13172, 18, 16, 11, 10}
if !assertPresenceAndOrdering(requiredExtensionsOrderiOS11, info.extensions, true) {
return false
}
} else {
// For these versions of Safari, expect TLS_EMPTY_RENEGOTIATION_INFO_SCSV first.
if len(info.cipherSuites) < 1 {
return false
}
if info.cipherSuites[0] != scsvRenegotiation {
return false
}
} }
if hasGreaseCiphers(info.cipherSuites) { if hasGreaseCiphers(info.cipherSuites) {
......
...@@ -108,20 +108,20 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) { ...@@ -108,20 +108,20 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
helloHex: `010000c003031dae75222dae1433a5a283ddcde8ddabaefbf16d84f250eee6fdff48cdfff8a00000201a1ac02bc02fc02cc030cca9cca8cc14cc13c013c014009c009d002f0035000a010000777a7a0000ff010001000000000e000c0000096c6f63616c686f73740017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a0008aaaa001d001700182a2a000100`, helloHex: `010000c003031dae75222dae1433a5a283ddcde8ddabaefbf16d84f250eee6fdff48cdfff8a00000201a1ac02bc02fc02cc030cca9cca8cc14cc13c013c014009c009d002f0035000a010000777a7a0000ff010001000000000e000c0000096c6f63616c686f73740017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a0008aaaa001d001700182a2a000100`,
interception: false, interception: false,
}, },
// TODO: Chrome on iOS will use iOS' TLS stack for requests that load {
// the web page (apparently required by the dev ToS) but will use its // Chrome on iOS will use iOS' TLS stack for requests that load
// own TLS stack for everything else, it seems. Figure out a decent way // the web page (apparently required by the dev ToS) but will use its
// to test this with a nice, unified corpus that allows for this variance. // own TLS stack for everything else, it seems.
// {
// // Chrome on iOS // Chrome on iOS
// userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.79 Mobile/14A456 Safari/602.1", userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.79 Mobile/14A456 Safari/602.1",
// helloHex: `010000de030358b062c509b21410a6496b5a82bfec74436cdecebe8ea1da29799939bbd3c17200002c00ffc02cc02bc024c023c00ac009c008c030c02fc028c027c014c013c012009d009c003d003c0035002f000a0100008900000014001200000f66696e6572706978656c732e636f6d000a00080006001700180019000b00020100000d00120010040102010501060104030203050306033374000000100030002e0268320568322d31360568322d31350568322d313408737064792f332e3106737064792f3308687474702f312e310005000501000000000012000000170000`, helloHex: `010000de030358b062c509b21410a6496b5a82bfec74436cdecebe8ea1da29799939bbd3c17200002c00ffc02cc02bc024c023c00ac009c008c030c02fc028c027c014c013c012009d009c003d003c0035002f000a0100008900000014001200000f66696e6572706978656c732e636f6d000a00080006001700180019000b00020100000d00120010040102010501060104030203050306033374000000100030002e0268320568322d31360568322d31350568322d313408737064792f332e3106737064792f3308687474702f312e310005000501000000000012000000170000`,
// }, },
// { {
// // Chrome on iOS (requesting favicon) // Chrome on iOS (requesting favicon)
// userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.79 Mobile/14A456 Safari/602.1", userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.79 Mobile/14A456 Safari/602.1",
// helloHex: `010000c20303863eb64788e3b9638c261300318411cbdd8f09576d58eec1e744b6ce944f574f0000208a8acca9cca8cc14cc13c02bc02fc02cc030c013c014009c009d002f0035000a01000079baba0000ff0100010000000014001200000f66696e6572706978656c732e636f6d0017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e31000b00020100000a000a00083a3a001d001700184a4a000100`, helloHex: `010000c20303863eb64788e3b9638c261300318411cbdd8f09576d58eec1e744b6ce944f574f0000208a8acca9cca8cc14cc13c02bc02fc02cc030c013c014009c009d002f0035000a01000079baba0000ff0100010000000014001200000f66696e6572706978656c732e636f6d0017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e31000b00020100000a000a00083a3a001d001700184a4a000100`,
// }, },
{ {
userAgent: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", userAgent: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
helloHex: `010000c603036f717a88212c3e9e41940f82c42acb3473e0e4a64e8f52d9af33d34e972e08a30000206a6ac02bc02fc02cc030cca9cca8cc14cc13c013c014009c009d002f0035000a0100007d7a7a0000ff0100010000000014001200000f66696e6572706978656c732e636f6d0017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a00087a7a001d001700188a8a000100`, helloHex: `010000c603036f717a88212c3e9e41940f82c42acb3473e0e4a64e8f52d9af33d34e972e08a30000206a6ac02bc02fc02cc030cca9cca8cc14cc13c013c014009c009d002f0035000a0100007d7a7a0000ff0100010000000014001200000f66696e6572706978656c732e636f6d0017000000230000000d00140012040308040401050308050501080606010201000500050100000000001200000010000e000c02683208687474702f312e3175500000000b00020100000a000a00087a7a001d001700188a8a000100`,
...@@ -185,6 +185,11 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) { ...@@ -185,6 +185,11 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
helloHex: `010000d2030358a295b513c8140c6ff880f4a8a73cc830ed2dab2c4f2068eb365228d828732e00002600ffc02cc02bc024c023c00ac009c030c02fc028c027c014c013009d009c003d003c0035002f010000830000000e000c0000096c6f63616c686f7374000a00080006001700180019000b00020100000d00120010040102010501060104030203050306033374000000100030002e0268320568322d31360568322d31350568322d313408737064792f332e3106737064792f3308687474702f312e310005000501000000000012000000170000`, helloHex: `010000d2030358a295b513c8140c6ff880f4a8a73cc830ed2dab2c4f2068eb365228d828732e00002600ffc02cc02bc024c023c00ac009c030c02fc028c027c014c013009d009c003d003c0035002f010000830000000e000c0000096c6f63616c686f7374000a00080006001700180019000b00020100000d00120010040102010501060104030203050306033374000000100030002e0268320568322d31360568322d31350568322d313408737064792f332e3106737064792f3308687474702f312e310005000501000000000012000000170000`,
interception: false, interception: false,
}, },
{
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.28 (KHTML, like Gecko) Version/11.0 Mobile/15A5318g Safari/604.1",
helloHex: `010000e10303be294e11847ba01301e0bb6129f4a0d66344602141a8f0a1ab0750a1db145755000028c02cc02bc024c023cca9c00ac009c030c02fc028c027cca8c014c013009d009c003d003c0035002f01000090ff0100010000000014001200000f66696e6572706978656c732e636f6d00170000000d00140012040308040401050308050501080606010201000500050100000000337400000012000000100030002e0268320568322d31360568322d31350568322d313408737064792f332e3106737064792f3308687474702f312e31000b00020100000a00080006001d00170018`,
interception: false,
},
}, },
"Tor": { "Tor": {
{ {
...@@ -306,28 +311,17 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) { ...@@ -306,28 +311,17 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
// should return false, with as little logic as possible, // should return false, with as little logic as possible,
// but with enough logic to force TLS proxies to do a // but with enough logic to force TLS proxies to do a
// good job preserving characterstics of the handshake. // good job preserving characterstics of the handshake.
var correct bool if (isChrome && (isFirefox || isSafari || isEdge || isTor)) ||
switch client { (isFirefox && (isChrome || isSafari || isEdge || isTor)) ||
case "Chrome": (isSafari && (isChrome || isFirefox || isEdge || isTor)) ||
correct = isChrome && !isFirefox && !isSafari && !isEdge && !isTor (isEdge && (isChrome || isFirefox || isSafari || isTor)) ||
case "Firefox": (isTor && (isChrome || isFirefox || isSafari || isEdge)) {
correct = !isChrome && isFirefox && !isSafari && !isEdge && !isTor t.Errorf("[%s] Test %d: Multiple fingerprinting functions matched: "+
case "Safari": "Chrome=%v Firefox=%v Safari=%v Edge=%v Tor=%v\n\tparsed hello dec: %+v\n\tparsed hello hex: %#x\n",
correct = !isChrome && !isFirefox && isSafari && !isEdge && !isTor
case "Edge":
correct = !isChrome && !isFirefox && !isSafari && isEdge && !isTor
case "Tor":
correct = !isChrome && !isFirefox && !isSafari && !isEdge && isTor
case "Other":
correct = !isChrome && !isFirefox && !isSafari && !isEdge && !isTor
}
if !correct {
t.Errorf("[%s] Test %d: Chrome=%v Firefox=%v Safari=%v Edge=%v Tor=%v\n\tparsed hello dec: %+v\n\tparsed hello hex: %#x\n",
client, i, isChrome, isFirefox, isSafari, isEdge, isTor, parsed, parsed) client, i, isChrome, isFirefox, isSafari, isEdge, isTor, parsed, parsed)
} }
// test the handler too // test the handler and detection results
var got, checked bool var got, checked bool
want := ch.interception want := ch.interception
handler := &tlsHandler{ handler := &tlsHandler{
...@@ -352,6 +346,8 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) { ...@@ -352,6 +346,8 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
if got != want { if got != want {
t.Errorf("[%s] Test %d: Expected MITM=%v but got %v (type assertion OK (checked)=%v)", t.Errorf("[%s] Test %d: Expected MITM=%v but got %v (type assertion OK (checked)=%v)",
client, i, want, got, checked) client, i, want, got, checked)
t.Errorf("[%s] Test %d: Looks like Chrome=%v Firefox=%v Safari=%v Edge=%v Tor=%v\n\tparsed hello dec: %+v\n\tparsed hello hex: %#x\n",
client, i, isChrome, isFirefox, isSafari, isEdge, isTor, parsed, parsed)
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment