diff --git a/maildigger/.gitignore b/maildigger/.gitignore
@@ -0,0 +1,48 @@
+# ---> Go
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
+
+# ---> Go.AllowList
+# Allowlisting gitignore template for GO projects prevents us
+# from adding various unwanted local files, such as generated
+# files, developer configurations or IDE-specific files etc.
+#
+# Recommended: Go.AllowList.gitignore
+
+# Ignore everything
+*
+
+# But not these files...
+!/.gitignore
+
+!*.go
+!go.sum
+!go.mod
+
+!README.md
+!LICENSE
+
+# !Makefile
+
+# ...even if they are in subdirectories
+!*/
+
diff --git a/maildigger/README.md b/maildigger/README.md
@@ -0,0 +1,55 @@
+# maildigger
+
+little CLI to check for the size of the key of DKIM records.
+
+```
+
+
+ .-.
+ /'v'\ maildigger
+ (/ \) ~djnn.sh
+==='="="===<
+ |_| v0.0.1
+
+ s/o vsim<3
+ hack the planet,
+ travel the world . . .
+------------------------------------------------
+ DNS scrapping tool to recover DKIM
+ records
+
+ ===> evil.djnn.sh/djnn/maildigger <===
+------------------------------------------------
+
+
+```
+
+> based on [this research](https://dmarcchecker.app/articles/crack-512-bit-dkim-rsa-key)
+
+## Installing & compiling
+
+Using `go v1.23`.
+
+```bash
+# please clone using https. couldnt be arsed to set up a tcp tunnel on cloudflare
+git clone https://evil.djnn.sh/djnn/maildigger.git
+
+cd maildigger/
+
+make
+```
+
+### Using docker
+
+```bash
+cd maildigger/
+
+make docker
+```
+
+
+## Running
+
+```bash
+./maildigger -d example.txt --dkim-max-len 128
+```
diff --git a/maildigger/dkim/runner.go b/maildigger/dkim/runner.go
@@ -0,0 +1,60 @@
+package dkim
+
+import (
+ "github.com/miekg/dns"
+
+ "fmt"
+ "strings"
+)
+
+func (dk *DkimRunner) Run(maxLen int32) error {
+ dkimPrefix := "k=rsa; p="
+
+ m := new(dns.Client)
+ for _, domain := range dk.Domains {
+ q := dns.Question{
+ Name: domain + ".",
+ Qtype: dns.TypeTXT,
+ Qclass: dns.ClassINET,
+ }
+
+ m1 := new(dns.Msg)
+ m1.Id = dns.Id()
+ m1.RecursionDesired = true
+ m1.Question = make([]dns.Question, 1)
+ m1.Question[0] = q
+
+ /* make DNS request */
+ msg, _, err := m.Exchange(m1, dk.DnsServer+":53")
+ if err != nil {
+ println("[+] Could not contact exchange server")
+ return err
+ }
+
+ /* get TXT records from Answer */
+ for _, rr := range msg.Answer {
+ if rr.Header().Rrtype == dns.TypeTXT {
+ txt := rr.(*dns.TXT).Txt
+
+ for _, t := range txt {
+
+ /* we have found something that looks like a DKIM record */
+ if strings.HasPrefix(t, dkimPrefix) {
+
+ key := strings.TrimPrefix(t, dkimPrefix)
+ kLen := len(key)
+
+ /* key is bigger than our max-size, we discard */
+ if int32(kLen) > maxLen {
+ continue
+ }
+
+ fmt.Printf("[+] => %s: %s (len: %d)\n", domain, key, kLen)
+ }
+ }
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/maildigger/dkim/types.go b/maildigger/dkim/types.go
@@ -0,0 +1,22 @@
+package dkim
+
+type DkimRunner struct {
+
+ /* Nameserver target in order to perform the request */
+ DnsServer string
+
+ /* list of domains to hit */
+ Domains []string
+}
+
+type DkimDomain struct {
+
+ /* related base domain */
+ domain string
+
+ /* DKIM key */
+ key string
+
+ /* DKIM key len */
+ keyLen int32
+}
diff --git a/maildigger/go.mod b/maildigger/go.mod
@@ -0,0 +1,18 @@
+module evil.djnn.sh/djnn/maildigger
+
+go 1.23.4
+
+require (
+ github.com/miekg/dns v1.1.62
+ github.com/spf13/cobra v1.8.1
+)
+
+require (
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ golang.org/x/mod v0.18.0 // indirect
+ golang.org/x/net v0.27.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.22.0 // indirect
+ golang.org/x/tools v0.22.0 // indirect
+)
diff --git a/maildigger/go.sum b/maildigger/go.sum
@@ -0,0 +1,22 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
+github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/maildigger/main.go b/maildigger/main.go
@@ -0,0 +1,95 @@
+package main
+
+import (
+ "github.com/spf13/cobra"
+
+ "evil.djnn.sh/djnn/maildigger/dkim"
+
+ "bufio"
+ "fmt"
+ "os"
+)
+
+const version = "0.0.1"
+const ASCII_ART = `
+
+ .-.
+ /'v'\ maildigger
+ (/ \) ~djnn.sh
+==='="="===<
+ |_| v0.0.1
+
+ s/o vsim<3
+ hack the planet,
+ travel the world . . .
+------------------------------------------------
+ DNS scrapping tool to recover DKIM
+ records
+
+ ===> evil.djnn.sh/djnn/maildigger <===
+------------------------------------------------
+
+`
+
+var (
+ domainsFilepath string
+ nameserver string
+
+ maxLenDKIM int32
+ maxLenSPF int32
+)
+
+var rootCmd = &cobra.Command{
+ Use: "maildigger",
+ Short: "simple cli to scrape DKIM or SPF records",
+ Long: ASCII_ART,
+ Version: version,
+ Run: func(cmd *cobra.Command, args []string) {
+ println(ASCII_ART) /* why make hacking CLIs if you cant print silly ascii art ? */
+
+ if domainsFilepath == "" {
+ println("[!] error: please specify domain.")
+ os.Exit(1)
+ }
+
+ file, err := os.Open(domainsFilepath)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ domains := make([]string, 1)
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ domains = append(domains, scanner.Text())
+ }
+
+ if err := scanner.Err(); err != nil {
+ panic(err)
+ }
+ fmt.Printf("[+] Loaded %d domains...\n", len(domains))
+
+ dkimRunner := dkim.DkimRunner{
+ DnsServer: nameserver,
+ Domains: domains,
+ }
+
+ err = dkimRunner.Run(maxLenDKIM)
+ if err != nil {
+ println("[!] Error while recovering DKIM records")
+ panic(err)
+ }
+
+ println("[+] DKIM check done.")
+
+ },
+}
+
+func main() {
+
+ rootCmd.Flags().StringVarP(&nameserver, "nameserver", "n", "8.8.8.8", "DNS nameserver")
+ rootCmd.Flags().StringVarP(&domainsFilepath, "domains", "d", "domains.txt", "file containing list of domains (line by line)")
+ rootCmd.Flags().Int32VarP(&maxLenDKIM, "dkim-max-len", "", 128, "DKIM key max size")
+
+ rootCmd.ExecuteC()
+}
| | | | | | |