Skip to content
This repository has been archived by the owner on Jan 7, 2024. It is now read-only.

support for dns resolvers list #84

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Examples:
Options:
- `-d test.com` if you want to test a single domain.
- `-w domains.txt` is your list of subdomains.
- `-r resolvers.txt` is your list of dns resolvers.
- `-t` is the number of threads (Default: 10 threads).
- `-timeout` is the seconds to wait before timeout connection (Default: 10 seconds).
- `-o results.txt` where to save results to. For JSON: `-o results.json`
Expand Down Expand Up @@ -90,6 +91,13 @@ dev.cody.su
dev2.twitter.com
```

**Q:** What should my resolvers list look like?

**A:** Your resolvers list should include a list of dns resolvers. For a list of resolvers you can check [https://public-dns.info/nameservers.txt](https://public-dns.info/nameservers.txt):
```
8.8.8.8
8.8.4.4
```
## References
Extra information about Hostile Subdomain Takeovers:

Expand Down
5 changes: 5 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"flag"
"fmt"
"os"
"time"
"math/rand"

"github.com/haccer/subjack/subjack"
)
Expand All @@ -26,6 +28,7 @@ func main() {
flag.StringVar(&o.Output, "o", "", "Output results to file (Subjack will write JSON if file ends with '.json').")
flag.StringVar(&o.Config, "c", defaultConfig, "Path to configuration file.")
flag.BoolVar(&o.Manual, "m", false, "Flag the presence of a dead record, but valid CNAME entry.")
flag.StringVar(&o.Resolverlist, "r", "", "Path to resolvers list.")

flag.Parse()

Expand All @@ -39,5 +42,7 @@ func main() {
os.Exit(1)
}

rand.Seed(time.Now().UnixNano())

subjack.Process(&o)
}
51 changes: 37 additions & 14 deletions subjack/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ import (
"fmt"
"net"
"strings"
"math/rand"

"github.com/haccer/available"
"github.com/miekg/dns"
)

func (s *Subdomain) dns(o *Options) {
func (s *Subdomain) dns(o *Options, resolvers []string) {
config := o.Fingerprints

if o.All {
detect(s.Url, o.Output, o.Ssl, o.Verbose, o.Manual, o.Timeout, config)
detect(s.Url, o.Output, o.Ssl, o.Verbose, o.Manual, o.Timeout, resolvers, config)
} else {
if VerifyCNAME(s.Url, config) {
detect(s.Url, o.Output, o.Ssl, o.Verbose, o.Manual, o.Timeout, config)
if VerifyCNAME(s.Url, config, resolvers) {
detect(s.Url, o.Output, o.Ssl, o.Verbose, o.Manual, o.Timeout, resolvers, config)
}

if o.Verbose {
Expand All @@ -36,13 +37,24 @@ func (s *Subdomain) dns(o *Options) {
}
}

func resolve(url string) (cname string) {
func resolve(url string, resolvers []string) (cname string) {
cname = ""
d := new(dns.Msg)
d.SetQuestion(url+".", dns.TypeCNAME)
ret, err := dns.Exchange(d, "8.8.8.8:53")
if err != nil {
return

default_resolver := "8.8.8.8:53"
resolver := default_resolver
if (len(resolvers) > 0) {
resolver = fmt.Sprintf("%s:53", resolvers[rand.Intn(len(resolvers))])
}

ret, err := dns.Exchange(d, resolver)
if err != nil && resolver != default_resolver {
// retry again with the default resolver
ret, err = dns.Exchange(d, default_resolver)
if err != nil {
return
}
}

for _, a := range ret.Answer {
Expand All @@ -54,12 +66,23 @@ func resolve(url string) (cname string) {
return cname
}

func nslookup(domain string) (nameservers []string) {
func nslookup(domain string, resolvers []string) (nameservers []string) {
m := new(dns.Msg)
m.SetQuestion(dotDomain(domain), dns.TypeNS)
ret, err := dns.Exchange(m, "8.8.8.8:53")
if err != nil {
return

default_resolver := "8.8.8.8:53"
resolver := default_resolver
if (len(resolvers) > 0) {
resolver = fmt.Sprintf("%s:53", resolvers[rand.Intn(len(resolvers))])
}

ret, err := dns.Exchange(m, resolver)
if err != nil && resolver != default_resolver {
// retry again with the default resolver
ret, err = dns.Exchange(m, default_resolver)
if err != nil {
return
}
}

nameservers = []string{}
Expand All @@ -83,8 +106,8 @@ func nxdomain(nameserver string) bool {
return false
}

func NS(domain, output string, verbose bool) {
nameservers := nslookup(domain)
func NS(domain, output string, verbose bool, resolvers []string) {
nameservers := nslookup(domain, resolvers)
for _, ns := range nameservers {
if verbose {
msg := fmt.Sprintf("[*] %s: Nameserver is %s\n", domain, ns)
Expand Down
12 changes: 6 additions & 6 deletions subjack/fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type Fingerprints struct {
* Triage step to check whether the CNAME matches
* the fingerprinted CNAME of a vulnerable cloud service.
*/
func VerifyCNAME(subdomain string, config []Fingerprints) (match bool) {
cname := resolve(subdomain)
func VerifyCNAME(subdomain string, config []Fingerprints, resolvers []string) (match bool) {
cname := resolve(subdomain, resolvers)
match = false

VERIFY:
Expand All @@ -36,8 +36,8 @@ VERIFY:
return match
}

func detect(url, output string, ssl, verbose, manual bool, timeout int, config []Fingerprints) {
service := Identify(url, ssl, manual, timeout, config)
func detect(url, output string, ssl, verbose, manual bool, timeout int, resolvers []string, config []Fingerprints) {
service := Identify(url, ssl, manual, timeout, config, resolvers)

if service != "" {
result := fmt.Sprintf("[%s] %s\n", service, url)
Expand Down Expand Up @@ -75,10 +75,10 @@ func detect(url, output string, ssl, verbose, manual bool, timeout int, config [
* is attached to a vulnerable cloud service and able to
* be taken over.
*/
func Identify(subdomain string, forceSSL, manual bool, timeout int, fingerprints []Fingerprints) (service string) {
func Identify(subdomain string, forceSSL, manual bool, timeout int, fingerprints []Fingerprints, resolvers []string) (service string) {
body := get(subdomain, forceSSL, timeout)

cname := resolve(subdomain)
cname := resolve(subdomain, resolvers)

if len(cname) <= 3 {
cname = ""
Expand Down
15 changes: 12 additions & 3 deletions subjack/subjack.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Options struct {
Config string
Manual bool
Fingerprints []Fingerprints
Resolverlist string
}

type Subdomain struct {
Expand All @@ -26,6 +27,7 @@ type Subdomain struct {
/* Start processing subjack from the defined options. */
func Process(o *Options) {
var list []string
var resolvers []string
var err error

urls := make(chan *Subdomain, o.Threads*10)
Expand All @@ -35,11 +37,18 @@ func Process(o *Options) {
} else {
list, err = open(o.Wordlist)
}

if err != nil {
log.Fatalln(err)
}


if(len(o.Resolverlist) > 0){
resolvers, err = open(o.Resolverlist)
if err != nil {
log.Fatalln(err)
}
}

o.Fingerprints = fingerprints(o.Config)

wg := new(sync.WaitGroup)
Expand All @@ -48,7 +57,7 @@ func Process(o *Options) {
wg.Add(1)
go func() {
for url := range urls {
url.dns(o)
url.dns(o, resolvers)
}

wg.Done()
Expand Down