output to files / stdtout
parent
94aa59fc3f
commit
6837969a68
116
main.go
116
main.go
|
@ -6,11 +6,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -51,7 +54,8 @@ var iface = flag.String("i", "eth0", "Interface to read packets from")
|
||||||
var fname = flag.String("r", "", "Filename to read from, overrides -i")
|
var fname = flag.String("r", "", "Filename to read from, overrides -i")
|
||||||
|
|
||||||
// writing
|
// writing
|
||||||
var outFolder = flag.String("w", "output", "Folder to write to")
|
var outCerts = flag.String("w", "", "Folder to write certificates into")
|
||||||
|
var outJSON = flag.String("j", "", "Folder to write certificates into, stdin if not set")
|
||||||
var jobQ chan TLSSession
|
var jobQ chan TLSSession
|
||||||
var cancelC chan string
|
var cancelC chan string
|
||||||
|
|
||||||
|
@ -75,25 +79,23 @@ var stats struct {
|
||||||
overlapPackets int
|
overlapPackets int
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSRecord struct {
|
type SessionRecord struct {
|
||||||
ServerIP string `json:"server_ip"`
|
ServerIP string
|
||||||
ServerPort string `json:"server_port"`
|
ServerPort string
|
||||||
ClientIP string `json:"client_ip"`
|
ClientIP string
|
||||||
ClientPort string `json:"client_port"`
|
ClientPort string
|
||||||
TLSHDigest string `json:"tlsh_digest"`
|
TLSHDigest string
|
||||||
Timestamp uint64 `json:"timestamp"`
|
Timestamp time.Time
|
||||||
JA3 string `json:"ja3"`
|
JA3 string
|
||||||
JA3Digest string `json:"ja3_digest"`
|
JA3Digest string
|
||||||
JA3S string `json:"ja3s"`
|
JA3S string
|
||||||
JA3SDigest string `json:"ja3s_digest"`
|
JA3SDigest string
|
||||||
Certificate string `json: "certificate"`
|
Certificates []*x509.Certificate
|
||||||
CertificateDigest string `json: "certificate_digest"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSSession struct {
|
type TLSSession struct {
|
||||||
record TLSRecord
|
record SessionRecord
|
||||||
tlsHdskR layers.TLSHandshakeRecord
|
tlsHdskR layers.TLSHandshakeRecord
|
||||||
certs []*x509.Certificate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var grease = map[uint16]bool{
|
var grease = map[uint16]bool{
|
||||||
|
@ -111,6 +113,25 @@ var errorsMap map[string]uint
|
||||||
var errorsMapMutex sync.Mutex
|
var errorsMapMutex sync.Mutex
|
||||||
var errors uint
|
var errors uint
|
||||||
|
|
||||||
|
func (t *TLSSession) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(fmt.Sprintf("---------------SESSION START-------------------\n"))
|
||||||
|
buf.WriteString(fmt.Sprintf("Time: %d\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("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 _, cert := range t.record.Certificates {
|
||||||
|
buf.WriteString(fmt.Sprintf("Certificate Issuer: %q\n", cert.Issuer))
|
||||||
|
buf.WriteString(fmt.Sprintf("Certificate Subject: %q\n", cert.Subject))
|
||||||
|
buf.WriteString(fmt.Sprintf("Certificate is CA: %t\n", cert.IsCA))
|
||||||
|
}
|
||||||
|
buf.WriteString(fmt.Sprintf("---------------SESSION END--------------------\n"))
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// Too bad for perf that a... is evaluated
|
// Too bad for perf that a... is evaluated
|
||||||
func Error(t string, s string, a ...interface{}) {
|
func Error(t string, s string, a ...interface{}) {
|
||||||
errorsMapMutex.Lock()
|
errorsMapMutex.Lock()
|
||||||
|
@ -296,7 +317,8 @@ func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
||||||
t.tlsSession.tlsHdskR.TLSHandshakeClientHello = tlsrecord.TLSHandshakeClientHello
|
t.tlsSession.tlsHdskR.TLSHandshakeClientHello = tlsrecord.TLSHandshakeClientHello
|
||||||
t.tlsSession.record.ClientIP, t.tlsSession.record.ServerIP, t.tlsSession.record.ClientPort, t.tlsSession.record.ServerPort = getIPPorts(t)
|
t.tlsSession.record.ClientIP, t.tlsSession.record.ServerIP, t.tlsSession.record.ClientPort, t.tlsSession.record.ServerPort = getIPPorts(t)
|
||||||
// Set up first seen
|
// Set up first seen
|
||||||
t.tlsSession.record.Timestamp = uint64(time.Now().Unix())
|
info := sg.CaptureInfo(0)
|
||||||
|
t.tlsSession.record.Timestamp = info.Timestamp
|
||||||
t.tlsSession.gatherJa3()
|
t.tlsSession.gatherJa3()
|
||||||
// Server Hello
|
// Server Hello
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -309,8 +331,9 @@ func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
||||||
cert, err := x509.ParseCertificate(asn1Data)
|
cert, err := x509.ParseCertificate(asn1Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("tls: failed to parse certificate from server: " + err.Error())
|
panic("tls: failed to parse certificate from server: " + err.Error())
|
||||||
|
} else {
|
||||||
|
t.tlsSession.record.Certificates = append(t.tlsSession.record.Certificates, cert)
|
||||||
}
|
}
|
||||||
t.tlsSession.certs = append(t.tlsSession.certs, cert)
|
|
||||||
}
|
}
|
||||||
// If we get a cert, we consider the handshake as finished and ready to ship to D4
|
// If we get a cert, we consider the handshake as finished and ready to ship to D4
|
||||||
queueSession(t.tlsSession)
|
queueSession(t.tlsSession)
|
||||||
|
@ -585,22 +608,49 @@ func queueSession(t TLSSession) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func output(t TLSSession, wg *sync.WaitGroup) {
|
func output(t TLSSession, wg *sync.WaitGroup) {
|
||||||
fmt.Println("---------------SESSION START-------------------")
|
|
||||||
fmt.Printf("Time: %d\n", t.record.Timestamp)
|
jsonRecord, _ := json.MarshalIndent(t.record, "", " ")
|
||||||
fmt.Printf("Client: %v:%v\n", t.record.ClientIP, t.record.ClientPort)
|
|
||||||
fmt.Printf("Server: %v:%v\n", t.record.ServerIP, t.record.ServerPort)
|
// If an output folder was specified for certificates
|
||||||
fmt.Printf("ja3: %q\n", t.record.JA3)
|
if *outCerts != "" {
|
||||||
fmt.Printf("ja3 Digest: %q\n", t.record.JA3Digest)
|
if _, err := os.Stat(fmt.Sprintf("./%s", *outCerts)); !os.IsNotExist(err) {
|
||||||
fmt.Printf("ja3s: %q\n", t.record.JA3S)
|
for _, cert := range t.record.Certificates {
|
||||||
fmt.Printf("ja3s Digest: %q\n", t.record.JA3SDigest)
|
go func(cert *x509.Certificate) {
|
||||||
for i, cert := range t.certs {
|
wg.Add(1)
|
||||||
fmt.Printf("Certificate Issuer: %q\n", cert.Issuer)
|
err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.crt", *outCerts, t.record.Timestamp.Format(time.RFC3339)), cert.Raw, 0644)
|
||||||
fmt.Printf("Certificate Subject: %q\n", cert.Subject)
|
if err != nil {
|
||||||
err := ioutil.WriteFile(fmt.Sprintf("./cert%d.crt", i), cert.Raw, 0644)
|
panic("Could not write to file.")
|
||||||
if err != nil {
|
} else {
|
||||||
panic("Could not write to file.")
|
wg.Done()
|
||||||
|
}
|
||||||
|
}(cert)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("./%s does not exist", *outCerts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("---------------SESSION END--------------------")
|
|
||||||
|
// If an output folder was specified for json files
|
||||||
|
if *outJSON != "" {
|
||||||
|
if _, err := os.Stat(fmt.Sprintf("./%s", *outJSON)); !os.IsNotExist(err) {
|
||||||
|
go func() {
|
||||||
|
wg.Add(1)
|
||||||
|
err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.json", *outJSON, t.record.Timestamp.Format(time.RFC3339)), jsonRecord, 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic("Could not write to file.")
|
||||||
|
} else {
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("./%s does not exist", *outJSON))
|
||||||
|
}
|
||||||
|
// If not folder specidied, we output to stdout
|
||||||
|
} else {
|
||||||
|
r := bytes.NewReader(jsonRecord)
|
||||||
|
io.Copy(os.Stdout, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(t.String())
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue