splits fingerprinter and tlsdecoder

DecodingLayerParser
Jean-Louis Huynen 2019-02-15 10:28:25 +01:00
parent 4308e141b5
commit 00bd0836d9
4 changed files with 116 additions and 117 deletions

View File

@ -33,7 +33,6 @@ var nodefrag = flag.Bool("nodefrag", false, "If true, do not do IPv4 defrag")
var checksum = flag.Bool("checksum", false, "Check TCP checksum")
var nooptcheck = flag.Bool("nooptcheck", false, "Do not check TCP options (useful to ignore MSS on captures with TSO)")
var ignorefsmerr = flag.Bool("ignorefsmerr", false, "Ignore TCP FSM errors")
var allowmissinginit = flag.Bool("allowmissinginit", false, "Support streams without SYN/SYN+ACK/ACK sequence")
var verbose = flag.Bool("verbose", false, "Be verbose")
var debug = flag.Bool("debug", false, "Display debug information")
var quiet = flag.Bool("quiet", false, "Be quiet regarding errors")
@ -42,9 +41,6 @@ var quiet = flag.Bool("quiet", false, "Be quiet regarding errors")
var iface = flag.String("i", "eth0", "Interface to read packets from")
var fname = flag.String("r", "", "Filename to read from, overrides -i")
// decoding
//var LayerTypeETLS gopacket.LayerType
// writing
var outCerts = flag.String("w", "", "Folder to write certificates into")
var outJSON = flag.String("j", "", "Folder to write certificates into, stdin if not set")
@ -88,9 +84,8 @@ type tcpStreamFactory struct {
}
func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
Debug("* NEW: %s %s\n", net, transport)
fsmOptions := reassembly.TCPSimpleFSMOptions{
SupportMissingEstablishment: *allowmissinginit,
SupportMissingEstablishment: true,
}
stream := &tcpStream{
net: net,
@ -134,37 +129,36 @@ type tcpStream struct {
urls []string
ident string
tlsSession d4tls.TLSSession
ignorefsmerr bool
nooptcheck bool
checksum bool
sync.Mutex
}
func (t *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
// FSM
if !t.tcpstate.CheckState(tcp, dir) {
Error("FSM", "%s: Packet rejected by FSM (state:%s)\n", t.ident, t.tcpstate.String())
if !t.fsmerr {
t.fsmerr = true
}
if !*ignorefsmerr {
if !t.ignorefsmerr {
return false
}
}
// Options
err := t.optchecker.Accept(tcp, ci, dir, nextSeq, start)
if err != nil {
Error("OptionChecker", "%s: Packet rejected by OptionChecker: %s\n", t.ident, err)
if !*nooptcheck {
if !t.nooptcheck {
return false
}
}
// Checksum
accept := true
if *checksum {
if t.checksum {
c, err := tcp.ComputeChecksum()
if err != nil {
Error("ChecksumCompute", "%s: Got error computing checksum: %s\n", t.ident, err)
accept = false
} else if c != 0x0 {
Error("Checksum", "%s: Invalid checksum: 0x%x\n", t.ident, c)
accept = false
}
}
@ -174,7 +168,7 @@ func (t *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassem
func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
_, _, _, skip := sg.Info()
length, _ := sg.Lengths()
if skip == -1 && *allowmissinginit {
if skip == -1 {
// this is allowed
} else if skip != 0 {
// Missing bytes in stream: do not even try to parse it
@ -236,7 +230,6 @@ func getIPPorts(t *tcpStream) (string, string, string, string) {
}
func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
Debug("%s: Connection closed\n", t.ident)
// do not remove the connection to allow last ACK
return false
}
@ -371,6 +364,16 @@ func main() {
w.Wait()
}
// Tries to enqueue or false
func queueSession(t d4tls.TLSSession) bool {
select {
case jobQ <- t:
return true
default:
return false
}
}
func processCompletedSession(jobQ <-chan d4tls.TLSSession, w *sync.WaitGroup) {
for {
tlss, more := <-jobQ
@ -383,16 +386,6 @@ func processCompletedSession(jobQ <-chan d4tls.TLSSession, w *sync.WaitGroup) {
}
}
// Tries to enqueue or false
func queueSession(t d4tls.TLSSession) bool {
select {
case jobQ <- t:
return true
default:
return false
}
}
func output(t d4tls.TLSSession) {
jsonRecord, _ := json.MarshalIndent(t.Record, "", " ")

View File

@ -1,17 +1,12 @@
package d4tls
import (
"bytes"
"crypto/md5"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
"github.com/D4-project/sensor-d4-tls-fingerprinting/etls"
"github.com/glaslos/tlsh"
)
@ -22,93 +17,6 @@ var grease = map[uint16]bool{
0xcaca: true, 0xdada: true, 0xeaea: true, 0xfafa: true,
}
type certMapElm struct {
CertHash string
*x509.Certificate
}
type sessionRecord struct {
ServerIP string
ServerPort string
ClientIP string
ClientPort string
TLSH string
Timestamp time.Time
JA3 string
JA3Digest string
JA3S string
JA3SDigest string
Certificates []certMapElm
}
// TLSSession contains a handshakeRecord that had to be filled during the handshake,
// and a Record that will be at last exported to Json
type TLSSession struct {
Record sessionRecord
handShakeRecord etls.ETLSHandshakeRecord
stage int
}
// String returns a string that describes a TLSSession
func (t *TLSSession) String() string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("---------------SESSION START-------------------\n"))
buf.WriteString(fmt.Sprintf("Time: %v\n", t.Record.Timestamp))
buf.WriteString(fmt.Sprintf("Client: %v:%v\n", t.Record.ClientIP, t.Record.ClientPort))
buf.WriteString(fmt.Sprintf("Server: %v:%v\n", t.Record.ServerIP, t.Record.ServerPort))
buf.WriteString(fmt.Sprintf("TLSH: %q\n", t.Record.TLSH))
buf.WriteString(fmt.Sprintf("ja3: %q\n", t.Record.JA3))
buf.WriteString(fmt.Sprintf("ja3 Digest: %q\n", t.Record.JA3Digest))
buf.WriteString(fmt.Sprintf("ja3s: %q\n", t.Record.JA3S))
buf.WriteString(fmt.Sprintf("ja3s Digest: %q\n", t.Record.JA3SDigest))
for _, certMe := range t.Record.Certificates {
buf.WriteString(fmt.Sprintf("Certificate Issuer: %q\n", certMe.Certificate.Issuer))
buf.WriteString(fmt.Sprintf("Certificate Subject: %q\n", certMe.Certificate.Subject))
buf.WriteString(fmt.Sprintf("Certificate is CA: %t\n", certMe.Certificate.IsCA))
buf.WriteString(fmt.Sprintf("Certificate SHA256: %q\n", certMe.CertHash))
}
buf.WriteString(fmt.Sprintf("---------------SESSION END--------------------\n"))
return buf.String()
}
// PopulateClientHello takes a pointer to an etls ClientHelloMsg and writes it to the the TLSSession struct
func (t *TLSSession) PopulateClientHello(h *etls.ClientHelloMsg, cip string, sip string, cp string, sp string, ti time.Time) {
if t.stage < 1 {
t.Record.ClientIP = cip
t.Record.ServerIP = sip
t.Record.ClientPort = cp
t.Record.ServerPort = sp
t.Record.Timestamp = ti
t.handShakeRecord.ETLSHandshakeClientHello = h
t.stage = 1
}
}
// PopulateServerHello takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
func (t *TLSSession) PopulateServerHello(h *etls.ServerHelloMsg) {
if t.stage < 2 {
t.handShakeRecord.ETLSHandshakeServerHello = h
t.stage = 2
}
}
// PopulateCertificate takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
func (t *TLSSession) PopulateCertificate(c *etls.CertificateMsg) {
if t.stage < 3 {
t.handShakeRecord.ETLSHandshakeCertificate = c
for _, asn1Data := range t.handShakeRecord.ETLSHandshakeCertificate.Certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
//return err
} else {
h := sha256.New()
h.Write(cert.Raw)
t.Record.Certificates = append(t.Record.Certificates, certMapElm{Certificate: cert, CertHash: fmt.Sprintf("%x", h.Sum(nil))})
}
}
}
}
// D4Fingerprinting computes fingerprints doh
func (t *TLSSession) D4Fingerprinting(fd string) bool {
switch fd {

98
d4tls/tlsdecoder.go Normal file
View File

@ -0,0 +1,98 @@
package d4tls
import (
"bytes"
"crypto/sha256"
"crypto/x509"
"fmt"
"time"
"github.com/D4-project/sensor-d4-tls-fingerprinting/etls"
)
type certMapElm struct {
CertHash string
*x509.Certificate
}
type sessionRecord struct {
ServerIP string
ServerPort string
ClientIP string
ClientPort string
TLSH string
Timestamp time.Time
JA3 string
JA3Digest string
JA3S string
JA3SDigest string
Certificates []certMapElm
}
// TLSSession contains a handshakeRecord that had to be filled during the handshake,
// and a Record that will be at last exported to Json
type TLSSession struct {
Record sessionRecord
handShakeRecord etls.ETLSHandshakeRecord
stage int
}
// String returns a string that describes a TLSSession
func (t *TLSSession) String() string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("---------------SESSION START-------------------\n"))
buf.WriteString(fmt.Sprintf("Time: %v\n", t.Record.Timestamp))
buf.WriteString(fmt.Sprintf("Client: %v:%v\n", t.Record.ClientIP, t.Record.ClientPort))
buf.WriteString(fmt.Sprintf("Server: %v:%v\n", t.Record.ServerIP, t.Record.ServerPort))
buf.WriteString(fmt.Sprintf("TLSH: %q\n", t.Record.TLSH))
buf.WriteString(fmt.Sprintf("ja3: %q\n", t.Record.JA3))
buf.WriteString(fmt.Sprintf("ja3 Digest: %q\n", t.Record.JA3Digest))
buf.WriteString(fmt.Sprintf("ja3s: %q\n", t.Record.JA3S))
buf.WriteString(fmt.Sprintf("ja3s Digest: %q\n", t.Record.JA3SDigest))
for _, certMe := range t.Record.Certificates {
buf.WriteString(fmt.Sprintf("Certificate Issuer: %q\n", certMe.Certificate.Issuer))
buf.WriteString(fmt.Sprintf("Certificate Subject: %q\n", certMe.Certificate.Subject))
buf.WriteString(fmt.Sprintf("Certificate is CA: %t\n", certMe.Certificate.IsCA))
buf.WriteString(fmt.Sprintf("Certificate SHA256: %q\n", certMe.CertHash))
}
buf.WriteString(fmt.Sprintf("---------------SESSION END--------------------\n"))
return buf.String()
}
// PopulateClientHello takes a pointer to an etls ClientHelloMsg and writes it to the the TLSSession struct
func (t *TLSSession) PopulateClientHello(h *etls.ClientHelloMsg, cip string, sip string, cp string, sp string, ti time.Time) {
if t.stage < 1 {
t.Record.ClientIP = cip
t.Record.ServerIP = sip
t.Record.ClientPort = cp
t.Record.ServerPort = sp
t.Record.Timestamp = ti
t.handShakeRecord.ETLSHandshakeClientHello = h
t.stage = 1
}
}
// PopulateServerHello takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
func (t *TLSSession) PopulateServerHello(h *etls.ServerHelloMsg) {
if t.stage < 2 {
t.handShakeRecord.ETLSHandshakeServerHello = h
t.stage = 2
}
}
// PopulateCertificate takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
func (t *TLSSession) PopulateCertificate(c *etls.CertificateMsg) {
if t.stage < 3 {
t.handShakeRecord.ETLSHandshakeCertificate = c
for _, asn1Data := range t.handShakeRecord.ETLSHandshakeCertificate.Certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
//return err
} else {
h := sha256.New()
h.Write(cert.Raw)
t.Record.Certificates = append(t.Record.Certificates, certMapElm{Certificate: cert, CertHash: fmt.Sprintf("%x", h.Sum(nil))})
}
}
}
}