关于go:go-hack九dns子域枚举

go网络安全代码地址

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
    "text/tabwriter"

    "github.com/miekg/dns"
)

// 遍历字典,枚举子域,并且查问子域名的a记录和cname记录
// 应用 go run subdomain_gusee.go -domain="xxx.xx" -wordlist="xx" -c=10 -dns="8.8.8.8:53"

var (
    fdomain    = flag.String("domain", "baidu.com", "猜解的域")
    fwordlist  = flag.String("wordlist", "", "暴破字典")
    fworkcount = flag.Int("c", 30, "协程数")
    fdns       = flag.String("dns", "8.8.8.8:53", "dns")
)

type result struct {
    ip      string // 解析的a记录
    host    string
    allHost []string // 所有的cname  可能cname1->cname2->cname3->a
}

// 查问a记录
func lookupA(fqdn, fdns string) ([]string, error) {
    var m dns.Msg
    var ips []string
    m.SetQuestion(dns.Fqdn(fqdn), dns.TypeA)
    in, err := dns.Exchange(&m, fdns)

    if err != nil {
        return ips, err
    }

    for _, answer := range in.Answer {
        if a, ok := answer.(*dns.A); ok {
            ips = append(ips, a.A.String())
        }
    }
    return ips, nil
}

// 查问a记录
func lookupCname(fqdn, fdns string) ([]string, error) {
    var m dns.Msg
    var fqdns []string
    m.SetQuestion(dns.Fqdn(fqdn), dns.TypeCNAME)
    in, err := dns.Exchange(&m, fdns)

    if err != nil {
        return fqdns, err
    }

    for _, answer := range in.Answer {
        if a, ok := answer.(*dns.CNAME); ok {
            log.Println(a.Target)
            fqdns = append(fqdns, a.Target)
        }
    }
    return fqdns, nil
}

func lookup(fqdn, fdns string) []result {
    var results []result
    var cnames []string
    var cfqdn = fqdn //拷贝出一份 避免篡改
    for {
        cname, err := lookupCname(cfqdn, fdns)
        if err != nil {
            //log.Println(err)
            return nil
        }
        if len(cname) > 0 {
            cfqdn = cname[0] // 跟踪出所有的cname,直到最初一个
            cnames = append(cnames, cname...)
            continue
        }
        ips, err := lookupA(cfqdn, fdns)
        if err != nil {
            //log.Println(err)
            return nil
        }

        for _, v := range ips {
            results = append(results, result{
                ip:      v,
                host:    cfqdn,
                allHost: cnames,
            })
        }
    }
    fmt.Println(results)
    return results
}

// 协程解决
// in输出fqdn  out输入result,在main中接管,isdone 标识是否完结
func worker(in chan string, out chan []result, isdone chan struct{}, fdns string) {
    for item := range in { // 从in队列中读取
        results := lookup(item, fdns)
        if len(results) > 0 {
            out <- results // 将result传出去
        }
    }
    isdone <- struct{}{} // 避免没有实现就终止
}

func main() {
    flag.Parse()

    if *fdomain == "" || *fwordlist == "" {
        fmt.Println("传错谬误")
        os.Exit(1)
    }
    in := make(chan string)
    out := make(chan []result)
    isdone := make(chan struct{})

    // 暴破文件读取
    fn, err := os.Open(*fwordlist) // 关上文件
    if err != nil {
        log.Fatalln(err)
    }
    defer fn.Close()
    // 创立遍历器
    scanner := bufio.NewScanner(fn)

    // 创立10个消费者
    for i := 0; i < *fworkcount; i++ {
        go worker(in, out, isdone, *fdns)
    }

    // 须要先创立期待工作的协程,不然会死锁
    // 生产者
    for scanner.Scan() {
        in <- fmt.Sprintf("%s.%s", scanner.Text(), *fdomain)
    }

    // 后果
    var results []result
    go func() {
        for item := range out {
            results = append(results, item...)
        }
        isdone <- struct{}{}
    }()

    close(in) // 所有数据发送实现,进行敞开管道

    // 回收worker过程的实现管道
    for i := 0; i < *fworkcount; i++ {
        <-isdone
    }
    // 接管完worker的数据 敞开
    close(out)

    <-isdone // result的is_done 管道

    w := tabwriter.NewWriter(os.Stdout,0,8,' ',' ',0) //NewWriter(output io.Writer, minwidth int, tabwidth int, padding int, padchar byte, flags uint) *tabwriter.Writer
    for _,v := range results{
        fmt.Fprintf(w,"%s\t%s\n",v.host,v.ip)
    }
    w.Flush()

}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理