Very messy experimental extensions to TLSGuard to strip out sessions and TLS extensions in the handshake protocol.

shw_dev
Stephen Watt 7 years ago
parent ff8be65566
commit 71ee1964f4

@ -614,7 +614,7 @@ func toggleHover() {
func toggleValidRuleState() { func toggleValidRuleState() {
ok := true ok := true
// Unfortunately, this can cause deadlock since it's a part of the item removal cascade // XXX: Unfortunately, this can cause deadlock since it's a part of the item removal cascade
// globalPromptLock.Lock() // globalPromptLock.Lock()
// defer globalPromptLock.Unlock() // defer globalPromptLock.Unlock()

@ -3,6 +3,7 @@ package sgfw
import ( import (
"crypto/x509" "crypto/x509"
"encoding/binary" "encoding/binary"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -10,10 +11,12 @@ import (
"time" "time"
) )
const TLSGUARD_READ_TIMEOUT = 5 * time.Second const TLSGUARD_READ_TIMEOUT = 10 * time.Second
const TLSGUARD_MIN_TLS_VER_MAJ = 3 const TLSGUARD_MIN_TLS_VER_MAJ = 3
const TLSGUARD_MIN_TLS_VER_MIN = 1 const TLSGUARD_MIN_TLS_VER_MIN = 1
const TLS_RECORD_HDR_LEN = 5
const SSL3_RT_CHANGE_CIPHER_SPEC = 20 const SSL3_RT_CHANGE_CIPHER_SPEC = 20
const SSL3_RT_ALERT = 21 const SSL3_RT_ALERT = 21
const SSL3_RT_HANDSHAKE = 22 const SSL3_RT_HANDSHAKE = 22
@ -56,6 +59,12 @@ const TLS1_AD_USER_CANCELLED = 90
const TLS1_AD_NO_RENEGOTIATION = 100 const TLS1_AD_NO_RENEGOTIATION = 100
const TLS1_AD_UNSUPPORTED_EXTENSION = 110 const TLS1_AD_UNSUPPORTED_EXTENSION = 110
const TLSEXT_TYPE_server_name = 1
const TLSEXT_TYPE_signature_algorithms = 13
const TLSEXT_TYPE_client_certificate_type = 19
const TLSEXT_TYPE_extended_master_secret = 23
const TLSEXT_TYPE_renegotiate = 0xff01
type connReader struct { type connReader struct {
client bool client bool
data []byte data []byte
@ -65,7 +74,22 @@ type connReader struct {
var cipherSuiteMap map[uint16]string = map[uint16]string{ var cipherSuiteMap map[uint16]string = map[uint16]string{
0x0000: "TLS_NULL_WITH_NULL_NULL", 0x0000: "TLS_NULL_WITH_NULL_NULL",
0x000a: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
0x002f: "TLS_RSA_WITH_AES_128_CBC_SHA",
0x0033: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
0x0039: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
0x0035: "TLS_RSA_WITH_AES_256_CBC_SHA",
0x0030: "TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030: "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
0xc009: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
0xc00a: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
0xc013: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
0xc014: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
0xc02b: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
0xc02c: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
0xc02f: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
0xc030: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
0xcca9: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
0xcca8: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
} }
func getCipherSuiteName(value uint) string { func getCipherSuiteName(value uint) string {
@ -103,7 +127,7 @@ func connectionReader(conn net.Conn, is_client bool, c chan connReader, done cha
return return
default: default:
if stage == 1 { if stage == 1 {
header := make([]byte, 5) header := make([]byte, TLS_RECORD_HDR_LEN)
conn.SetReadDeadline(time.Now().Add(TLSGUARD_READ_TIMEOUT)) conn.SetReadDeadline(time.Now().Add(TLSGUARD_READ_TIMEOUT))
_, err := io.ReadFull(conn, header) _, err := io.ReadFull(conn, header)
conn.SetReadDeadline(time.Time{}) conn.SetReadDeadline(time.Time{})
@ -208,16 +232,17 @@ select_loop:
/* We expect only a single byte of data */ /* We expect only a single byte of data */
if cr.rtype == SSL3_RT_CHANGE_CIPHER_SPEC { if cr.rtype == SSL3_RT_CHANGE_CIPHER_SPEC {
fmt.Println("CHANGE CIPHER_SPEC: ", cr.data[TLS_RECORD_HDR_LEN])
if len(cr.data) != 6 { if len(cr.data) != 6 {
return errors.New(fmt.Sprintf("TLSGuard dropped connection with strange change cipher spec data length (%v bytes)", len(cr.data))) return errors.New(fmt.Sprintf("TLSGuard dropped connection with strange change cipher spec data length (%v bytes)", len(cr.data)))
} }
if cr.data[5] != 1 { if cr.data[TLS_RECORD_HDR_LEN] != 1 {
return errors.New(fmt.Sprintf("TLSGuard dropped connection with strange change cipher spec data (%#x bytes)", cr.data[5])) return errors.New(fmt.Sprintf("TLSGuard dropped connection with strange change cipher spec data (%#x bytes)", cr.data[TLS_RECORD_HDR_LEN]))
} }
} else if cr.rtype == SSL3_RT_ALERT { } else if cr.rtype == SSL3_RT_ALERT {
if cr.data[5] == SSL3_AL_WARNING { if cr.data[TLS_RECORD_HDR_LEN] == SSL3_AL_WARNING {
fmt.Println("SSL ALERT TYPE: warning") fmt.Println("SSL ALERT TYPE: warning")
} else if cr.data[5] == SSL3_AL_FATAL { } else if cr.data[TLS_RECORD_HDR_LEN] == SSL3_AL_FATAL {
fmt.Println("SSL ALERT TYPE: fatal") fmt.Println("SSL ALERT TYPE: fatal")
} else { } else {
fmt.Println("SSL ALERT TYPE UNKNOWN") fmt.Println("SSL ALERT TYPE UNKNOWN")
@ -226,7 +251,7 @@ select_loop:
alert_desc := int(int(cr.data[6])<<8 | int(cr.data[7])) alert_desc := int(int(cr.data[6])<<8 | int(cr.data[7]))
fmt.Println("ALERT DESCRIPTION: ", alert_desc) fmt.Println("ALERT DESCRIPTION: ", alert_desc)
if cr.data[5] == SSL3_AL_FATAL { if cr.data[TLS_RECORD_HDR_LEN] == SSL3_AL_FATAL {
return errors.New(fmt.Sprintf("TLSGuard dropped connection after fatal error alert detected")) return errors.New(fmt.Sprintf("TLSGuard dropped connection after fatal error alert detected"))
} else if alert_desc == SSL3_AD_CLOSE_NOTIFY { } else if alert_desc == SSL3_AD_CLOSE_NOTIFY {
return errors.New(fmt.Sprintf("TLSGuard dropped connection after close_notify alert detected")) return errors.New(fmt.Sprintf("TLSGuard dropped connection after close_notify alert detected"))
@ -251,9 +276,15 @@ select_loop:
return errors.New(fmt.Sprintf("TLSGuard dropping connection with unknown content type: %#x", cr.rtype)) return errors.New(fmt.Sprintf("TLSGuard dropping connection with unknown content type: %#x", cr.rtype))
} }
handshakeMsg := cr.data[5:] handshakeMsg := cr.data[TLS_RECORD_HDR_LEN:]
s := uint(handshakeMsg[0]) s := uint(handshakeMsg[0])
fmt.Printf("s = %#x\n", s) fmt.Printf("s = %#x\n", s)
// Message len, 3 bytes
if cr.rtype == SSL3_RT_HANDSHAKE {
handshakeMessageLen := handshakeMsg[1:4]
handshakeMessageLenInt := int(int(handshakeMessageLen[0])<<16 | int(handshakeMessageLen[1])<<8 | int(handshakeMessageLen[2]))
fmt.Println("lenint = \n", handshakeMessageLenInt)
}
if cr.client && s != uint(client_expected) { if cr.client && s != uint(client_expected) {
return errors.New(fmt.Sprintf("Client sent handshake type %#x but expected %#x", s, client_expected)) return errors.New(fmt.Sprintf("Client sent handshake type %#x but expected %#x", s, client_expected))
@ -261,31 +292,178 @@ select_loop:
return errors.New(fmt.Sprintf("Server sent handshake type %#x but expected %#x", s, server_expected)) return errors.New(fmt.Sprintf("Server sent handshake type %#x but expected %#x", s, server_expected))
} }
if cr.client { if (cr.client && s == SSL3_MT_CLIENT_HELLO) || (!cr.client && s == SSL3_MT_SERVER_HELLO) {
rewrite := false
rewrite_buf := []byte{}
SRC := ""
if s == SSL3_MT_CLIENT_HELLO { if s == SSL3_MT_CLIENT_HELLO {
fmt.Println("CLIENT HELLO") SRC = "CLIENT"
} else {
server_expected = SSL3_MT_CERTIFICATE
SRC = "SERVER"
}
hello_offset := 4 hello_offset := 4
// 2 byte protocol version // 2 byte protocol version
fmt.Println("CLIENT HELLO VERSION = ", handshakeMsg[hello_offset:hello_offset+2]) fmt.Println(SRC, "HELLO VERSION = ", handshakeMsg[hello_offset:hello_offset+2])
hello_offset += 2 hello_offset += 2
// 4 byte Random/GMT time // 4 byte Random/GMT time
fmt.Println("CLIENT HELLO GMT = ", handshakeMsg[hello_offset:hello_offset+4]) gmtbytes := binary.BigEndian.Uint32(handshakeMsg[hello_offset : hello_offset+4])
gmt := time.Unix(int64(gmtbytes), 0)
fmt.Println(SRC, "HELLO GMT = ", gmt)
hello_offset += 4 hello_offset += 4
// 28 bytes Random/random_bytes // 28 bytes Random/random_bytes
hello_offset += 28 hello_offset += 28
// 1 byte (32-bit session ID) // 1 byte (32-bit session ID)
fmt.Println("CLIENT HELLO SESSION ID = ", handshakeMsg[hello_offset:hello_offset+1]) sess_len := uint(handshakeMsg[hello_offset])
hello_offset++ fmt.Println(SRC, "HELLO SESSION ID = ", sess_len)
if sess_len != 0 {
fmt.Printf("ALERT: %v attempting to resume session; intercepting request\n", SRC)
rewrite = true
dcopy := make([]byte, len(cr.data))
copy(dcopy, cr.data)
// Copy the bytes before the session ID start
rewrite_buf = dcopy[0 : TLS_RECORD_HDR_LEN+hello_offset+1]
// Set the session ID to 0
rewrite_buf[len(rewrite_buf)-1] = 0
// Write the new TLS record length
binary.BigEndian.PutUint16(rewrite_buf[3:5], uint16(len(dcopy)-(int(sess_len)+TLS_RECORD_HDR_LEN)))
// Write the new ClientHello length
// Starts after the first 6 bytes (record header + type byte)
orig_len := binary.BigEndian.Uint32(handshakeMsg[0:4])
// But it's only 3 bytes so mask out the first one
b1 := orig_len & 0xff000000
orig_len &= 0x00ffffff
orig_len -= uint32(sess_len)
orig_len |= b1
binary.BigEndian.PutUint32(rewrite_buf[TLS_RECORD_HDR_LEN:], orig_len)
rewrite_buf = append(rewrite_buf, dcopy[TLS_RECORD_HDR_LEN+hello_offset+int(sess_len)+1:]...)
}
hello_offset += int(sess_len) + 1
// 2 byte cipher suite array // 2 byte cipher suite array
cs := binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2]) cs := binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
fmt.Printf("cs = %v / %#v\n", cs, cs) noCS := cs
fmt.Printf("CLIENT HELLO CIPHERSUITE: %v (%s)\n", handshakeMsg[hello_offset:hello_offset+2], getCipherSuiteName(uint(cs))) fmt.Printf("cs = %v / %#x\n", noCS, noCS)
if !cr.client {
fmt.Printf("SERVER selected ciphersuite: %#x (%s)\n", cs, getCipherSuiteName(uint(cs)))
hello_offset += 2
} else {
for csind := 0; csind < int(noCS/2); csind++ {
off := hello_offset + 2 + (csind * 2)
cs = binary.BigEndian.Uint16(handshakeMsg[off : off+2])
fmt.Printf("%s HELLO CIPHERSUITE: %d/%d: %#x (%s)\n", SRC, csind+1, noCS/2, cs, getCipherSuiteName(uint(cs)))
}
hello_offset += 2 + int(noCS)
} }
clen := uint(handshakeMsg[hello_offset])
hello_offset++
if !cr.client {
fmt.Println("SERVER selected compression method: ", clen)
} else {
fmt.Println(SRC, "HELLO COMPRESSION METHODS LEN = ", clen)
fmt.Println(SRC, "HELLO COMPRESSION METHODS: ", handshakeMsg[hello_offset:hello_offset+int(clen)])
hello_offset += int(clen)
}
var extlen uint16 = 0
if hello_offset == len(handshakeMsg) {
fmt.Println("Message didn't have any extensions present")
} else {
extlen = binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
fmt.Println(SRC, "HELLO EXTENSIONS LENGTH: ", extlen)
hello_offset += 2
}
var exttype uint16 = 0
if extlen > 2 {
exttype = binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
fmt.Println(SRC, "HELLO FIRST EXTENSION TYPE: ", exttype)
}
if cr.client {
ext_ctr := 0
for ext_ctr < int(extlen)-2 {
hello_offset += 2
ext_ctr += 2
fmt.Printf("PROGRESS: %v of %v, %v of %v\n", ext_ctr, extlen, hello_offset, len(handshakeMsg))
exttype2 := binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
fmt.Printf("EXTTYPE = %v, 2 = %v\n", exttype, exttype2)
if exttype2 == TLSEXT_TYPE_server_name {
fmt.Println("CLIENT specified server_name extension:")
}
if exttype != TLSEXT_TYPE_signature_algorithms {
fmt.Println("WTF")
}
hello_offset += 2
ext_ctr += 2
inner_len := binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
// fmt.Println("INNER LEN = ", inner_len)
hello_offset += int(inner_len)
ext_ctr += int(inner_len)
}
}
if extlen > 0 {
fmt.Printf("ALERT: %v attempting to send extensions; intercepting request\n", SRC)
rewrite = true
tocopy := cr.data
if len(rewrite_buf) > 0 {
tocopy = rewrite_buf
}
dcopy := make([]byte, len(tocopy)-int(extlen))
copy(dcopy, tocopy[0:len(tocopy)-int(extlen)])
rewrite_buf = dcopy
// Write the new TLS record length
binary.BigEndian.PutUint16(rewrite_buf[3:5], uint16(len(dcopy)-(int(sess_len)+TLS_RECORD_HDR_LEN)))
// Write the new ClientHello length
// Starts after the first 6 bytes (record header + type byte)
orig_len := binary.BigEndian.Uint32(rewrite_buf[TLS_RECORD_HDR_LEN:])
// But it's only 3 bytes so mask out the first one
b1 := orig_len & 0xff000000
orig_len &= 0x00ffffff
orig_len -= uint32(extlen)
orig_len |= b1
binary.BigEndian.PutUint32(rewrite_buf[TLS_RECORD_HDR_LEN:], orig_len)
// Write session length 0 at the end
rewrite_buf[len(rewrite_buf)-1] = 0
rewrite_buf[len(rewrite_buf)-2] = 0
}
if rewrite {
fmt.Println("TLSGuard writing back modified handshake data to server")
fmt.Printf("ORIGINAL[%d]: %v\n", len(cr.data), hex.Dump(cr.data))
fmt.Printf("NEW[%d]: %v\n", len(rewrite_buf), hex.Dump(rewrite_buf))
other.Write(rewrite_buf)
} else {
other.Write(cr.data) other.Write(cr.data)
}
continue continue
} }
if cr.client {
other.Write(cr.data)
continue
}
if !cr.client && server_expected == SSL3_MT_SERVER_HELLO {
server_expected = SSL3_MT_CERTIFICATE
}
if !cr.client && s == SSL3_MT_HELLO_REQUEST { if !cr.client && s == SSL3_MT_HELLO_REQUEST {
fmt.Println("Server sent hello request") fmt.Println("Server sent hello request")
continue continue

Loading…
Cancel
Save