Task DNS
Tasks for Monitoring and Alerting on DNS
1. Prepare a Custom DNS Server as a Honeypot
Simple honeypot, download it from gobee.go
package main
import (
"log"
"net"
"strconv"
"github.com/miekg/dns"
)
var domainsToAddresses map[string]string = map[string]string{
"google.com.": "1.2.3.4",
"not-a.xyz.": "1.3.3.7",
/* Add more use cases */
}
var domainsToMX map[string][]*dns.MX = map[string][]*dns.MX{
"google.com.": { {Hdr: dns.RR_Header{Name: "google.com.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 60}, Preference: 10, Mx: "mail.google.com."} },
"not-a.xyz.": { {Hdr: dns.RR_Header{Name: "not-a.xyz.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 60}, Preference: 10, Mx: "mail.not-a.xyz."} },
/* Add more use cases */
}
var domainsToCNAME map[string][]*dns.CNAME = map[string][]*dns.CNAME{
"google.com": { {Hdr: dns.RR_Header{Name: "google.com", Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 60}, Target: "www.not-a.xyz"} },
"not-a.xyz": { {Hdr: dns.RR_Header{Name: "not-a.xyz", Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 60}, Target: "www.not-a.xyz"} },
/* Add more use cases */
}
var domaintToCAA map[string][]*dns.CAA = map[string][]*dns.CAA{
"google.com": { {Hdr: dns.RR_Header{Name: "google.com", Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 60}, Value: "m.google.com"} },
"not-a.xyz": { {Hdr: dns.RR_Header{Name: "not-a.xyz", Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 60}, Value: "m.not-a.xyz"} },
/* Add more use cases */
}
type handler struct{}
func (h *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
msg := dns.Msg{}
msg.SetReply(r)
switch r.Question[0].Qtype {
case dns.TypeA:
msg.Authoritative = true
domain := msg.Question[0].Name
address, ok := domainsToAddresses[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: net.ParseIP(address),
})
/* Add rule */
}
/* Add more events */
case dns.TypeAAAA:
msg.Authoritative = true
domain := msg.Question[0].Name
address, ok := domainsToAddresses[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60},
AAAA: net.ParseIP(address),
})
/* Add rule */
}
/* Add more events */
case dns.TypeCNAME:
msg.Authoritative = true
domain := msg.Question[0].Name
address, ok := domainsToCNAME[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.CNAME{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 60},
Target: address[0].String(),
})
/* Add rule */
}
/* Add more events */
case dns.TypeCAA:
msg.Authoritative = false
domain := msg.Question[0].Name
address, ok := domaintToCAA[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.CAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 60},
Value: address[0].Value,
})
/* Add rule */
}
/* Add more events */
case dns.TypeMX:
msg.Authoritative = false
domain := msg.Question[0].Name
address, ok := domainsToMX[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.MX{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 60},
Mx: address[0].Mx,
})
/* Add rule */
}
/* Add more events */
case dns.TypeTXT:
msg.Authoritative = false
domain := msg.Question[0].Name
address, ok := domainsToAddresses[domain]
if ok {
msg.Answer = append(msg.Answer, &dns.TXT{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60},
Txt: []string{address},
})
/* Add rule */
}
/* Add more events */
}
w.WriteMsg(&msg)
}
func main() {
srv := &dns.Server{Addr: ":" + strconv.Itoa(53), Net: "udp"}
srv.Handler = &handler{}
defer srv.Shutdown()
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to set udp listener %s\n", err.Error())
}
}
2. From IoCs to Snort Rules File
- Save the downloaded IoCs into a Snort rule file.
You can download a tool to help you on this, use gosoc.go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
type IoCList struct {
Data []data `json:"data"`
}
type data struct {
Artifact string `json:"artifact"`
Type string `json:"artifact_type"`
Date string `json:"created_date"`
RefLink string `json:"reference_link"`
RefTxt string `json:"reference_text"`
}
func main() {
resp, err := http.Get("https://labs.inquest.net/api/iocdb/list")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
iocList := IoCList{}
err = json.Unmarshal(body, &iocList)
if err != nil {
fmt.Println(err)
return
}
rules := []string{}
for _, value := range iocList.Data {
if value.Artifact != "" && value.Type == "domain" || value.Type == "url" {
rule := fmt.Sprintf("alert ip any any -> %s any (msg:\"Potential IOC detected of TYPE %s reference %s\"; sid:1000001; rev:1;)\n", value.Artifact, value.Type, value.RefLink)
rules = append(rules, rule)
}
}
filePath := "inquest.rules"
file, err := os.Create(filePath)
if err != nil {
log.Fatalf("Failed creating file: %s", err)
}
for _, f := range rules {
_, err = file.WriteString(f)
if err != nil {
log.Fatalf("Failed writing the rule content: %s", err)
}
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Fatalf("Failed closing file: %s", err)
}
}(file)
log.Printf("File created: %s", filePath)
}
Disclaimer
DISCLAIMER: The information and code provided here are intended for educational and informational purposes only. The user assumes full responsibility for the use of this information and code. The provider of this information and code makes no representations or warranties, express or implied, about the completeness, accuracy, reliability, suitability, or availability of the information and code provided. Any reliance you place on such information and any use of this code is therefore strictly at your own risk. In no event will the provider be liable for any loss or damage including without limitation, indirect or consequential loss or damage, arising out of, or in connection with, the use of this information and code.