Skip to content

Commit

Permalink
Merge pull request #6 from 0x4f53/concurrent-multi-input
Browse files Browse the repository at this point in the history
Concurrent multi input
  • Loading branch information
0x4f53 authored Aug 20, 2024
2 parents 5d52ee7 + 95ed5d2 commit 9f4ea38
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 58 deletions.
Binary file modified .build/binaries/dnscovery-1.0.0-darwin-amd64
Binary file not shown.
Binary file modified .build/binaries/dnscovery-1.0.0-darwin-arm64
Binary file not shown.
Binary file modified .build/binaries/dnscovery-1.0.0-linux-386
Binary file not shown.
Binary file modified .build/binaries/dnscovery-1.0.0-linux-amd64
Binary file not shown.
Binary file modified .build/binaries/dnscovery-1.0.0-linux-arm64
Binary file not shown.
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ go 1.22.3
require (
github.com/miekg/dns v1.1.61
github.com/spf13/cobra v1.8.1
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/schollz/progressbar/v3 v3.14.6 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
Expand All @@ -21,12 +25,20 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
Expand All @@ -38,6 +50,8 @@ golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
94 changes: 64 additions & 30 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"strconv"
"sync"

"github.com/spf13/cobra"
)
Expand All @@ -31,11 +32,7 @@ var rootCmd = &cobra.Command{
},
}

func printServices(output Output) {

if verbose {
printProviders(output)
}
func printBasic(output Output) {

var services []string
for _, item := range output.Answers {
Expand All @@ -50,19 +47,9 @@ func printServices(output Output) {
}
services = RemoveDuplicatesAndEmptyStrings(services)

if verbose {
fmt.Println()
}
fmt.Printf("Found services: ")
if verbose {
fmt.Println()
}
fmt.Printf(output.Host + ": ")

for index, record := range services {
if verbose {
fmt.Printf(" %s. %s\n", strconv.Itoa(index+1), record)
continue
}

fmt.Printf("%s", record)

Expand All @@ -76,7 +63,33 @@ func printServices(output Output) {

}

func saveAsJson(output Output) {
func printVerbose(outputList []Output) {
for _, output := range outputList {
fmt.Println(output.Host)
fmt.Print(" Resolved by:")
for _, answer := range output.Answers {
fmt.Print(" " + answer.Resolver.Name + " (" + answer.Resolver.IP + ")")
}
var services []string
fmt.Print("\n Services:\n")
for _, answer := range output.Answers {
for _, record := range answer.Records {
for _, service := range record.Services {
serviceString := " " + service + "\n " + record.Value
services = append(services, serviceString)
}
}
}
services = RemoveDuplicatesAndEmptyStrings(services)
for _, service := range services {
fmt.Println(service)
}
fmt.Println()
}

}

func saveAsJson(output []Output) {
outputBytes, err := json.MarshalIndent(output, "", " ")

if err != nil {
Expand Down Expand Up @@ -126,8 +139,11 @@ func main() {
ErrorLog.Println(err)
os.Exit(-1)
}

Resolvers = resolvers

fmt.Print("\nReading resolvers...\t[ " + strconv.Itoa(len(resolvers)) + " found! ]")

fmt.Print("\nChecking if online...")

if !CheckInternet() {
Expand All @@ -136,34 +152,52 @@ func main() {
os.Exit(-2)
}

fmt.Print("\t[ ✓ ONLINE ]\n")
fmt.Print("\t[ ✓ ONLINE ]\n\n")

signatures, err := GetSignatures()
if err != nil {
ErrorLog.Println(err)
os.Exit(-1)
}

Signatures = signatures

var finalOutput []Output

var wg sync.WaitGroup

for _, domain := range input {
shuffleResolvers(resolvers)
Resolvers = resolvers

fmt.Println("Looking up '" + domain + "'...\t[ " + strconv.Itoa(len(resolvers)) + " resolvers found! ]")
wg.Add(1)
go func(domain string) {
defer wg.Done()

output, err := Dig(domain)
output, err := Dig(domain)
if err != nil {
ErrorLog.Println(err)
return
}

if err != nil {
ErrorLog.Println(err)
os.Exit(-1)
}
finalOutput = append(finalOutput, output)

if outputFlagSet {
fmt.Println("Output saved to '" + outputFile + "'")
saveAsJson(output)
return
}
if !verbose {
printBasic(output)
}

}(domain)
}

wg.Wait()

printServices(output)
if verbose {
printVerbose(finalOutput)
}

if outputFlagSet {
fmt.Println("Output saved to '" + outputFile + "'")
saveAsJson(finalOutput)
}

}
Binary file modified preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 37 additions & 24 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@

A lightning-fast Golang tool to discover services embedded into DNS records


## 🚀 Features

- Takes just 2 seconds to resolve a domain**
- Takes just 1 second to resolve multiple domains**
- Queries multiple DNS servers concurrently
- More than 100 service signatures supported
- Easy to customize regexes and resolvers lists in YAML format
- Verbose JSON output for in-depth debugging

_** - depending on factors like internet speed, DNS server availability etc._


## 🖊️ Usage

```bash
Expand All @@ -35,10 +37,10 @@ Flags:
```bash
❯ ./dnscovery 0x4f.in

Reading resolvers... [ 7 found! ]
Checking if online... [ ✓ ONLINE ]
Looking up '0x4f.in'... [ 7 resolvers found! ]

Found services: OpenAI Domain, Ethereum Name Service, Cloudflare Mail, Google Workspace
0x4f.in: OpenAI Domain, Cloudflare Mail, Google Workspace, Ethereum Name Service
```
- JSON output
Expand Down Expand Up @@ -72,38 +74,42 @@ Output saved to 'output.json'
- Trying multiple domains
```bash
./dnscovery 0x4f.in blackhat.com
❯ dnscovery nintendo.co.jp phase.dev huffpost.com redgear.com 0x4f.in lenovo.com apple.com microsoft.com netflix.com hackertyper.com tcl.com

Reading resolvers... [ 7 found! ]
Checking if online... [ ✓ ONLINE ]

Looking up '0x4f.in'... [ 7 resolvers found! ]
Found services: Ethereum Name Service, Cloudflare Mail, Google Workspace, OpenAI Domain

Looking up 'blackhat.com'... [ 7 resolvers found! ]
Found services: Google Search Console, Microsoft Office 365, Twilio SendGrid, Google Workspace
apple.com: Apple, Facebook, Google Cloud Platform, Atlassian
0x4f.in: Ethereum Name Service, Google Workspace, Cloudflare Mail, OpenAI Domain
tcl.com: Google Cloud Platform
lenovo.com: Microsoft Office 365
microsoft.com: Microsoft Office 365, Microsoft Dynamics 365, Docusign
netflix.com: Dropbox, Apple, Docusign
nintendo.co.jp: Microsoft Office 365, Docusign, Adobe Creative Cloud, Google Cloud Platform, Apple
huffpost.com: Microsoft Office 365, Dropbox, Docusign, KnowBe4, Facebook, Google Cloud Platform
phase.dev: Google Cloud Platform, Gandi.net, Google Workspace
redgear.com: Google Workspace, Microsoft Office 365, Barracuda.com, Google Cloud Platform, Dropbox
hackertyper.com: Google Cloud Platform, Google Workspace
```
- Verbose mode
```bash
❯ ./dnscovery 0x4f.in -v

Reading resolvers... [ 7 found! ]
Checking if online... [ ✓ ONLINE ]
Looking up '0x4f.in'... [ 7 resolvers found! ]

DNS providers with this host:
1. Quad9 (9.9.9.9)
2. Google (8.8.4.4)
4. Cloudflare (1.1.1.1)

Found services:
1. Ethereum Name Service (in TXT record):
ENS1 dnsname.ens.eth 0x6189345d91a667c4822A0afD7587a4994965a57C
2. OpenAI Domain (in TXT record):
openai-domain-verification=dv-ThXpvQCK0VDGRfFHh6hCP7cy
3. Cloudflare Mail (in TXT record):
v=spf1 include:_spf.mx.cloudflare.net include:_spf.google.com ~all
4. Google Workspace (in TXT record):
v=spf1 include:_spf.mx.cloudflare.net include:_spf.google.com ~all
0x4f.in
Resolved by: Control D (76.76.2.0) Cloudflare (1.1.1.1) Quad9 (9.9.9.9) OpenDNS (208.67.222.222) Google (8.8.4.4) Verisign (64.6.64.6)
Services:
OpenAI Domain
openai-domain-verification=dv-ThXpvQCK0VDGRfFHh6hCP7cy
Google Workspace
v=spf1 include:_spf.mx.cloudflare.net include:_spf.google.com ~all
Cloudflare Mail
v=spf1 include:_spf.mx.cloudflare.net include:_spf.google.com ~all
Ethereum Name Service
ENS1 dnsname.ens.eth 0x6189345d91a667c4822A0afD7587a4994965a57C
```
## ⚙️ Building
Expand Down Expand Up @@ -141,6 +147,13 @@ without installation
You can find the exe files in [`.build/binaries`](.build/binaries/)
## ❓ Why I made this
I made this tool to check common services that multiple hosts use, by running it on a list of top 10,000 sites,
for statistical purposes. This tool can also speed up a blue-teamer's inspection tasks or
provide instant attack vectors for red-teamers to experiment with.
## 👍 Credits
- [NetSPI's Powershell scripts](https://github.com/NetSPI/PowerShell/blob/master/Resolve-DnsDomainValidationToken.ps1)
Expand Down
10 changes: 10 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"regexp"
"strconv"
"sync"
"time"

"github.com/miekg/dns"
"golang.org/x/exp/rand"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -60,6 +62,14 @@ var recordTypes = []uint16{
dns.TypeSRV,
}

func shuffleResolvers(resolvers []Resolver) {
rand.Seed(uint64(time.Now().UnixNano()))
for i := len(resolvers) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
resolvers[i], resolvers[j] = resolvers[j], resolvers[i]
}
}

func queryDNS(domain string, recordType uint16, resolver Resolver) ([]Record, error) {
c := new(dns.Client)
m := new(dns.Msg)
Expand Down

0 comments on commit 9f4ea38

Please sign in to comment.