diff --git a/processing/bloom_handler.go b/processing/bloom_handler.go index c03ad2b..b12d4f8 100644 --- a/processing/bloom_handler.go +++ b/processing/bloom_handler.go @@ -22,7 +22,8 @@ var sigs = map[string]string{ "http-url": "%s Possibly bad HTTP URL: ", "http-host": "%s Possibly bad HTTP host: ", "tls-sni": "%s Possibly bad TLS SNI: ", - "dns": "%s Possibly bad DNS lookup to ", + "dns-req": "%s Possibly bad DNS lookup to ", + "dns-resp": "%s Possibly bad DNS response for ", } // MakeAlertEntryForHit returns an alert Entry as raised by an external @@ -41,7 +42,7 @@ func MakeAlertEntryForHit(e types.Entry, eType string, alertPrefix string, ioc s value = fmt.Sprintf("%s | %s | %s", e.HTTPMethod, e.HTTPHost, e.HTTPUrl) } else if eType == "http-host" { value = e.HTTPHost - } else if eType == "dns" { + } else if strings.HasPrefix(eType, "dns") { value = e.DNSRRName } else if eType == "tls-sni" { value = e.TLSSni @@ -238,17 +239,24 @@ func (a *BloomHandler) Consume(e *types.Entry) error { } a.Unlock() - } - if e.EventType == "dns" { + } else if e.EventType == "dns" { a.Lock() if a.IocBloom.Check([]byte(e.DNSRRName)) { - n := MakeAlertEntryForHit(*e, "dns", a.AlertPrefix, e.DNSRRName) + var n types.Entry + if e.DNSType == "query" { + n = MakeAlertEntryForHit(*e, "dns-req", a.AlertPrefix, e.DNSRRName) + } else if e.DNSType == "answer" { + n = MakeAlertEntryForHit(*e, "dns-resp", a.AlertPrefix, e.DNSRRName) + } else { + log.Warnf("invalid DNS type: '%s'", e.DNSType) + a.Unlock() + return nil + } a.DatabaseEventChan <- n a.ForwardHandler.Consume(&n) } a.Unlock() - } - if e.EventType == "tls" { + } else if e.EventType == "tls" { a.Lock() if a.IocBloom.Check([]byte(e.TLSSni)) { n := MakeAlertEntryForHit(*e, "tls-sni", a.AlertPrefix, e.TLSSni) diff --git a/processing/bloom_handler_test.go b/processing/bloom_handler_test.go index 0e8257b..491a889 100644 --- a/processing/bloom_handler_test.go +++ b/processing/bloom_handler_test.go @@ -19,12 +19,14 @@ import ( "github.com/DCSO/bloom" log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" ) var ( reHTTPURL = regexp.MustCompile(`Possibly bad HTTP URL: [^ ]+ . ([^ ]+) . ([^" ]+)`) reHTTPHost = regexp.MustCompile(`Possibly bad HTTP host: ([^" ]+)`) - reDNS = regexp.MustCompile("Possibly bad DNS lookup to ([^\" ]+)") + reDNSReq = regexp.MustCompile("Possibly bad DNS lookup to ([^\" ]+)") + reDNSRep = regexp.MustCompile("Possibly bad DNS response for ([^\" ]+)") reSNI = regexp.MustCompile("Possibly bad TLS SNI: ([^\" ]+)") ) @@ -40,7 +42,8 @@ func makeBloomDNSEvent(rrname string) types.Entry { DNSRCode: []string{"NOERROR", "NXDOMAIN"}[rand.Intn(2)], DNSRData: fmt.Sprintf("10.%d.0.%d", rand.Intn(50), rand.Intn(50)+100), DNSRRName: rrname, - DNSRRType: "answer", + DNSRRType: "A", + DNSType: []string{"answer", "query"}[rand.Intn(2)], } eve := types.EveEvent{ EventType: e.EventType, @@ -54,6 +57,7 @@ func makeBloomDNSEvent(rrname string) types.Entry { Rrname: e.DNSRRName, Rdata: e.DNSRData, Rrtype: e.DNSRRType, + Type: e.DNSType, }, } json, err := json.Marshal(eve) @@ -202,8 +206,29 @@ func (h *CollectorHandler) Consume(e *types.Entry) error { h.Entries[host] = true return nil } - match = reDNS.FindStringSubmatch(e.JSONLine) + match = reDNSReq.FindStringSubmatch(e.JSONLine) if match != nil { + var eve types.EveEvent + var err = json.Unmarshal([]byte(e.JSONLine), &eve) + if err != nil { + log.Fatal(err) + } + if eve.DNS.Type != "query" { + log.Fatalf("request alert for type (%s) != query", eve.DNS.Type) + } + h.Entries[match[1]] = true + return nil + } + match = reDNSRep.FindStringSubmatch(e.JSONLine) + if match != nil { + var eve types.EveEvent + var err = json.Unmarshal([]byte(e.JSONLine), &eve) + if err != nil { + log.Fatal(err) + } + if eve.DNS.Type != "answer" { + log.Fatalf("request alert for type (%s) != answer", eve.DNS.Type) + } h.Entries[match[1]] = true return nil } @@ -738,5 +763,47 @@ func TestBloomHandlerURL(t *testing.T) { if len(fwhandler.GetEntries()) != 0 { t.Fatalf("too many alerts: %d", len(fwhandler.GetEntries())) } +} +func TestBloomHandlerInvalidDNS(t *testing.T) { + // make sure that alerts are forwarded + util.PrepareEventFilter([]string{"alert"}, false) + + // initalize Bloom filter and fill with 'interesting' values + bf := bloom.Initialize(100000, 0.0000001) + + // channel to receive events to be saved to database + dbChan := make(chan types.Entry) + + // handler to receive forwarded events + fwhandler := &CollectorHandler{ + Entries: make(map[string]bool), + } + + // concurrently gather entries to be written to DB + dbWritten := make([]types.Entry, 0) + consumeWaitChan := make(chan bool) + go func() { + for e := range dbChan { + dbWritten = append(dbWritten, e) + } + close(consumeWaitChan) + }() + + bh := MakeBloomHandler(&bf, dbChan, fwhandler, "FOO BAR") + e := makeBloomDNSEvent("foobar") + e.DNSType = "foobar" + bf.Add([]byte(e.DNSRRName)) + + hook := test.NewGlobal() + + bh.Consume(&e) + + entries := hook.AllEntries() + if len(entries) < 1 { + t.Fatal("missing log entries") + } + if entries[0].Message != "invalid DNS type: 'foobar'" { + t.Fatal("wrong log entry for invalid DNS type") + } }