├── .gitignore ├── LICENSE ├── README.md ├── defines └── defines.go ├── dics └── extras.txt ├── dns └── dns.go ├── dnsManager └── dnsManager.go ├── go.mod ├── go.sum ├── main.go ├── resolver └── resolver.go ├── tables └── tables.go ├── util └── util.go └── words.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .vscode/ 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Bp0lr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## dmut 2 | 3 | ### what? 4 | 5 | A tool written in golang to perform permutations, mutations and alteration of subdomains and brute force the result. 6 | 7 | ![https://asciinema.org/a/xNDmWT0xkVyuR3vwl99kqy9RB](https://asciinema.org/a/xNDmWT0xkVyuR3vwl99kqy9RB.png) 8 | 9 | ### why? 10 | 11 | I'm doing some work on automatization for bug bounty, and I found myself needing something to brute force for new subdomains using these techniques. 12 | 13 | Doing some research I found altdns, a tool that does what I need but written in python. 14 | 15 | Speed is everything in bug bounty, usually, you have many subdomains to scan so I put myself in the task of writing a new tool that did the same as altdns but focused on speed and adding some improvements to the complete process. 16 | 17 | 18 | ### type of permutations, mutations, alterations. 19 | 20 | The main subdomain is **a.b.com** 21 | from a word list, where you have for example the word **stage**, dmut will generate and try for a positive response: 22 | 23 | - stagea.b.com 24 | - astage.b.com 25 | - stage.a.b.com 26 | - a.stage.b.com 27 | - stage-a.b.com 28 | - a-stage.b.com 29 | 30 | 31 | ### dns servers 32 | 33 | To get the best from **dmut**, you need a DNS server list. 34 | 35 | 36 | Using [dnsFaster](https://github.com/bp0lr/dnsfaster), I have created a github action to run this tool again a public list generated from (https://public-dns.info/nameserver/us.txt). 37 | 38 | 39 | this action runs one time a day and update the repo automatically. 40 | 41 | You can download this list from the repo [dmut-resolvers](https://github.com/bp0lr/dmut-resolvers) or running **dmut** with the flag --update-dnslist to update your local copy. 42 | 43 | ``` 44 | dmut --update-dnslist 45 | ``` 46 | and the new list would be saved to /~/.dmut/resolvers.txt 47 | 48 | 49 | it's really important to have your list in the best shape possible. The resolution times varied from one DNS server to another, you have some server doing DNS hijacking for some domains or responding with errors after several connections. 50 | Be careful and take your time to test your list. 51 | 52 | 53 | ### Speed 54 | 55 | **dmut** is significantly much faster than his python brother. 56 | 57 | I did some tests to compare his speed using the same options and an accurate DNS server list. 58 | 59 | ``` 60 | root@dnsMaster# time python3 altdns.py -i list.txt -o data_output -r -w words.txt -t 100 -f /root/.dmut/resolvers.txt -s results.txt 61 | ... 62 | real 9m44.712s 63 | user 7m7.741s 64 | sys 1m6.288s 65 | 66 | root@dnsMaster# wc -l results.txt 67 | 55 68 | ``` 69 | 70 | ``` 71 | root@dnsMaster# time cat list.txt | dmut -w 100 -d words.txt --dns-retries 3 -o results.txt -s /root/.dmut/resolvers.txt --dns-errorLimit 50 --dns-timeout 350 --show-stats 72 | ... 73 | real 5m31.318s 74 | user 1m4.024s 75 | sys 0m41.876s 76 | 77 | root@dnsMaster# wc -l results.txt 78 | 55 79 | ``` 80 | 81 | If you run the same test but using a default DNS server list downloaded from public-dns.info, the difference is just too much. 82 | Here is where the anti-hijacking, found confirmations, DNS timeout and extra checks come to play in favor of dmut. 83 | 84 | ``` 85 | root@dnsMaster# time python3 altdns.py -i list.txt -o data_output -r -w words.txt -t 100 -f dnsinfo-list.txt -s results.txt 86 | ... 87 | real 112m6.295s 88 | user 8m17.104s 89 | sys 1m14.583s 90 | ``` 91 | 92 | ``` 93 | cat list.txt | ./dmut-binary -w 100 -d words.txt --dns-retries 3 -o results.txt -s dnsinfo-list.txt --dns-errorLimit 10 --dns-timeout 300 --show-stats 94 | real 8m21.627s 95 | user 1m14.191s 96 | sys 0m48.982s 97 | ``` 98 | 99 | just wow! 100 | 101 | 102 | 103 | ### Install 104 | 105 | Install is quick and clean 106 | ``` 107 | go install github.com/bp0lr/dmut@latest 108 | ``` 109 | 110 | You need a mutations list to make dmut works. 111 | 112 | You can use my list downloading the file from [here](https://raw.githubusercontent.com/bp0lr/dmut/main/words.txt) 113 | 114 | 115 | ### examples 116 | ``` 117 | dmut -u "test.example.com" -d mutations.txt -w 100 --dns-timeout 300 --dns-retries 5 --dns-errorLimit 25 --show-stats -o results.txt 118 | ``` 119 | this will run **dmut** again test.example.com, using the word list mutations.txt, using 100 workers, having a DNS timeout of 300ms and 5 retries for each error. 120 | If a DNS server reaches 25 errors, this server is blacklisted and not used again. 121 | 122 | Show stats add some verbose to the process. 123 | 124 | If we found something would be saved to results.txt 125 | 126 | ``` 127 | cat subdomainList.txt | dmut -d mutations.txt -w 100 --dns-timeout 300 --dns-retries 5 --dns-errorLimit 25 --show-stats -o results.txt 128 | ``` 129 | the same but using a subdomain list. 130 | 131 | 132 | ### options 133 | 134 | ``` 135 | Usage of dmut: 136 | -d, --dictionary string Dictionary file containing mutation list 137 | --dns-errorLimit int How many errors until we the DNS is disabled (default 25) 138 | --dns-retries int Amount of retries for failed dns queries (default 3) 139 | --dns-timeout int Dns Server timeOut in millisecond (default 500) 140 | -s, --dnsFile string Use DNS servers from this file 141 | -l, --dnsServers string Use DNS servers from a list separated by , 142 | -o, --output string Output file to save the results to 143 | --save-gen save generated permutations to a file and exit 144 | --save-to save generated permutations to this location 145 | --show-ip Display info for valid results 146 | --show-stats Display stats about the current job 147 | --update-dnslist Download a list of periodically validated public DNS resolvers 148 | --update-files Download all the default files to work with dmut. (default mutation list, resolvers, etc) 149 | -u, --url string Target URL 150 | --use-pb use a progress bar 151 | -v, --verbose Add verboicity to the process 152 | -w, --workers int Number of workers (default 25) 153 | --disable-addnumbers Disable add numbers generation 154 | --disable-addseparator Disable add separator generation 155 | --disable-permutations Disable permutations generation 156 | 157 | ``` 158 | 159 | ### Wildcard filtering 160 | **dmut** will test each subdomain for wildcards, requesting a not supposed to exist subdomain. 161 | 162 | If we get a positive response the job will be ignored. 163 | 164 | 165 | ### Contributing 166 | Everyone is encouraged to contribute to **dmut** by forking the Github repository and making a pull request or opening an issue. 167 | 168 | 169 | ### AltDNS 170 | 171 | altdns was originaly created by **infosec-au** and can be found here (https://github.com/infosec-au/altdns) 172 | 173 | Looks like the project was abandoned at some point, so I had forked and did my own version with some improvements. (https://github.com/bp0lr/altdns) 174 | 175 | I want to thank **infosec-au** because his work was my inspiration for dmut. 176 | -------------------------------------------------------------------------------- /defines/defines.go: -------------------------------------------------------------------------------- 1 | package defines 2 | 3 | //DmutJob desc 4 | type DmutJob struct { 5 | Domain string 6 | Tld string 7 | Sld string 8 | Trd string 9 | Tasks []string 10 | } 11 | 12 | //Stats desc 13 | type Stats struct{ 14 | Domains int 15 | Mutations int 16 | Founds int 17 | FoundDomains []string 18 | WorksToDo []string 19 | } 20 | 21 | //LoadStats desc 22 | type LoadStats struct{ 23 | Domains int 24 | Valid int 25 | Errors int 26 | } 27 | 28 | type PermutationList struct{ 29 | AddToDomain bool 30 | AddNumbers bool 31 | AddSeparator bool 32 | } -------------------------------------------------------------------------------- /dics/extras.txt: -------------------------------------------------------------------------------- 1 | a 2 | acceptatie 3 | access 4 | accounting 5 | accounts 6 | ad 7 | adm 8 | admin 9 | administrator 10 | ads 11 | adserver 12 | affiliate 13 | affiliates 14 | agenda 15 | alpha 16 | alumni 17 | analytics 18 | ann 19 | api 20 | apollo 21 | app 22 | apps 23 | ar 24 | archive 25 | art 26 | assets 27 | atlas 28 | auth 29 | auto 30 | autoconfig 31 | autodiscover 32 | av 33 | ayuda 34 | b 35 | b2b 36 | backup 37 | backups 38 | banner 39 | barracuda 40 | bb 41 | bbs 42 | beta 43 | biblioteca 44 | billing 45 | blackboard 46 | blog 47 | blogs 48 | board 49 | book 50 | booking 51 | bookings 52 | broadcast-ip 53 | bsd 54 | bt 55 | bug 56 | bugs 57 | business 58 | c 59 | ca 60 | cache 61 | cacti 62 | cal 63 | calendar 64 | cam 65 | careers 66 | cart 67 | cas 68 | catalog 69 | catalogo 70 | catalogue 71 | cc 72 | cctv 73 | cdn 74 | cdn1 75 | cdn2 76 | chat 77 | chimera 78 | chronos 79 | ci 80 | cisco 81 | citrix 82 | classroom 83 | client 84 | clientes 85 | clients 86 | cloud 87 | cloudflare-resolve-to 88 | club 89 | cms 90 | cn 91 | co 92 | community 93 | conference 94 | config 95 | connect 96 | contact 97 | contacts 98 | content 99 | control 100 | controller 101 | controlp 102 | controlpanel 103 | corp 104 | corporate 105 | correo 106 | correoweb 107 | cp 108 | cpanel 109 | crm 110 | cs 111 | css 112 | customers 113 | cvs 114 | d 115 | da 116 | data 117 | database 118 | db 119 | db1 120 | db2 121 | dbadmin 122 | dbs 123 | dc 124 | de 125 | default 126 | demo 127 | demo2 128 | demon 129 | demostration 130 | descargas 131 | design 132 | desktop 133 | dev 134 | dev01 135 | dev1 136 | dev2 137 | devel 138 | developers 139 | development 140 | dialin 141 | diana 142 | direct 143 | directory 144 | dl 145 | dmz 146 | dns 147 | dns1 148 | dns2 149 | dns3 150 | dns4 151 | doc 152 | docs 153 | domain 154 | domain-controller 155 | domainadmin 156 | domaincontrol 157 | domaincontroller 158 | domaincontrolpanel 159 | domainmanagement 160 | domains 161 | download 162 | downloads 163 | drupal 164 | e 165 | eaccess 166 | echo 167 | ecommerce 168 | edu 169 | ektron 170 | elearning 171 | email 172 | en 173 | eng 174 | english 175 | enterpriseenrollment 176 | enterpriseregistration 177 | erp 178 | es 179 | event 180 | events 181 | ex 182 | example 183 | examples 184 | exchange 185 | external 186 | extranet 187 | f 188 | facebook 189 | faq 190 | fax 191 | fb 192 | feedback 193 | feeds 194 | file 195 | files 196 | fileserver 197 | finance 198 | firewall 199 | folders 200 | forms 201 | foro 202 | foros 203 | forum 204 | forums 205 | foto 206 | fr 207 | free 208 | freebsd 209 | fs 210 | ftp 211 | ftp1 212 | ftp2 213 | ftpadmin 214 | ftpd 215 | fw 216 | g 217 | galeria 218 | gallery 219 | game 220 | games 221 | gate 222 | gateway 223 | gilford 224 | gis 225 | git 226 | gmail 227 | go 228 | google 229 | groups 230 | groupwise 231 | gu 232 | guest 233 | guia 234 | guide 235 | gw 236 | health 237 | help 238 | helpdesk 239 | hera 240 | heracles 241 | hercules 242 | hermes 243 | home 244 | homer 245 | host 246 | host2 247 | hosting 248 | hotspot 249 | hr 250 | hypernova 251 | i 252 | id 253 | idp 254 | im 255 | image 256 | images 257 | images1 258 | images2 259 | images3 260 | images4 261 | images5 262 | images6 263 | images7 264 | images8 265 | imail 266 | imap 267 | imap3 268 | imap3d 269 | imapd 270 | imaps 271 | img 272 | img1 273 | img2 274 | img3 275 | imgs 276 | imogen 277 | in 278 | incoming 279 | info 280 | inmuebles 281 | internal 282 | interno 283 | intra 284 | intranet 285 | io 286 | ip 287 | ip6 288 | ipfixe 289 | iphone 290 | ipmi 291 | ipsec 292 | ipv4 293 | ipv6 294 | irc 295 | ircd 296 | is 297 | isa 298 | it 299 | j 300 | ja 301 | jabber 302 | jboss 303 | jboss2 304 | jira 305 | job 306 | jobs 307 | jp 308 | js 309 | jupiter 310 | k 311 | kb 312 | kerberos 313 | l 314 | la 315 | lab 316 | laboratories 317 | laboratorio 318 | laboratory 319 | labs 320 | ldap 321 | legacy 322 | lib 323 | library 324 | link 325 | links 326 | linux 327 | lisa 328 | list 329 | lists 330 | live 331 | lms 332 | local 333 | localhost 334 | log 335 | loghost 336 | login 337 | logon 338 | logs 339 | london 340 | loopback 341 | love 342 | lp 343 | lync 344 | lyncdiscover 345 | m 346 | m1 347 | m2 348 | magento 349 | mail 350 | mail01 351 | mail1 352 | mail2 353 | mail3 354 | mail4 355 | mail5 356 | mailadmin 357 | mailbackup 358 | mailbox 359 | mailer 360 | mailgate 361 | mailhost 362 | mailing 363 | mailman 364 | mailserver 365 | main 366 | manage 367 | manager 368 | mantis 369 | map 370 | maps 371 | market 372 | marketing 373 | mars 374 | master 375 | math 376 | mb 377 | mc 378 | mdm 379 | media 380 | meet 381 | member 382 | members 383 | mercury 384 | meta 385 | meta01 386 | meta02 387 | meta03 388 | meta1 389 | meta2 390 | meta3 391 | miembros 392 | mijn 393 | minerva 394 | mirror 395 | ml 396 | mm 397 | mob 398 | mobil 399 | mobile 400 | monitor 401 | monitoring 402 | moodle 403 | movil 404 | mrtg 405 | ms 406 | msoid 407 | mssql 408 | munin 409 | music 410 | mx 411 | mx-a 412 | mx-b 413 | mx0 414 | mx01 415 | mx02 416 | mx03 417 | mx1 418 | mx2 419 | mx3 420 | my 421 | mysql 422 | mysql2 423 | n 424 | nagios 425 | nas 426 | nat 427 | nelson 428 | neon 429 | net 430 | netmail 431 | netscaler 432 | network 433 | network-ip 434 | networks 435 | new 436 | newmail 437 | news 438 | newsgroups 439 | newsite 440 | newsletter 441 | nl 442 | noc 443 | novell 444 | ns 445 | ns0 446 | ns01 447 | ns02 448 | ns03 449 | ns1 450 | ns10 451 | ns11 452 | ns12 453 | ns2 454 | ns3 455 | ns4 456 | ns5 457 | ns6 458 | ns7 459 | ns8 460 | nt 461 | ntp 462 | ntp1 463 | o 464 | oa 465 | office 466 | office2 467 | old 468 | oldmail 469 | oldsite 470 | oldwww 471 | on 472 | online 473 | op 474 | openbsd 475 | operation 476 | operations 477 | ops 478 | ora 479 | oracle 480 | origin 481 | orion 482 | os 483 | osx 484 | ou 485 | outgoing 486 | outlook 487 | owa 488 | ox 489 | p 490 | painel 491 | panel 492 | partner 493 | partners 494 | pay 495 | payment 496 | payments 497 | pbx 498 | pcanywhere 499 | pda 500 | pegasus 501 | pendrell 502 | personal 503 | pgsql 504 | phoenix 505 | photo 506 | photos 507 | php 508 | phpmyadmin 509 | pm 510 | pma 511 | poczta 512 | pop 513 | pop3 514 | portal 515 | portfolio 516 | post 517 | postgres 518 | postgresql 519 | postman 520 | postmaster 521 | pp 522 | ppp 523 | pr 524 | pre-prod 525 | pre-production 526 | preprod 527 | press 528 | preview 529 | private 530 | pro 531 | prod 532 | production 533 | project 534 | projects 535 | promo 536 | proxy 537 | prueba 538 | pruebas 539 | pt 540 | pub 541 | public 542 | q 543 | qa 544 | r 545 | ra 546 | radio 547 | radius 548 | ras 549 | rdp 550 | redirect 551 | redmine 552 | register 553 | relay 554 | remote 555 | remote2 556 | repo 557 | report 558 | reports 559 | repos 560 | research 561 | resources 562 | restricted 563 | reviews 564 | robinhood 565 | root 566 | router 567 | rss 568 | rt 569 | rtmp 570 | ru 571 | s 572 | s1 573 | s2 574 | s3 575 | s4 576 | sa 577 | sales 578 | sample 579 | samples 580 | sandbox 581 | sc 582 | search 583 | secure 584 | security 585 | seo 586 | server 587 | server1 588 | server2 589 | service 590 | services 591 | sftp 592 | share 593 | sharepoint 594 | shell 595 | shop 596 | shopping 597 | signup 598 | sip 599 | site 600 | siteadmin 601 | sitebuilder 602 | sites 603 | skype 604 | sms 605 | smtp 606 | smtp1 607 | smtp2 608 | smtp3 609 | snmp 610 | social 611 | software 612 | solaris 613 | soporte 614 | sp 615 | spam 616 | speedtest 617 | sport 618 | sports 619 | sql 620 | sqlserver 621 | squirrel 622 | squirrelmail 623 | ssh 624 | ssl 625 | sslvpn 626 | sso 627 | st 628 | staff 629 | stage 630 | staging 631 | start 632 | stat 633 | static 634 | static1 635 | static2 636 | stats 637 | status 638 | storage 639 | store 640 | stream 641 | streaming 642 | student 643 | sun 644 | support 645 | survey 646 | sv 647 | svn 648 | t 649 | team 650 | tech 651 | telewerk 652 | telework 653 | temp 654 | test 655 | test1 656 | test2 657 | test3 658 | testing 659 | testsite 660 | testweb 661 | tfs 662 | tftp 663 | thumbs 664 | ticket 665 | tickets 666 | time 667 | tools 668 | trac 669 | track 670 | tracker 671 | tracking 672 | train 673 | training 674 | travel 675 | ts 676 | tunnel 677 | tutorials 678 | tv 679 | tw 680 | u 681 | uat 682 | uk 683 | unix 684 | up 685 | update 686 | upload 687 | uploads 688 | us 689 | user 690 | users 691 | v 692 | v2 693 | vc 694 | ventas 695 | video 696 | videos 697 | vip 698 | virtual 699 | vista 700 | vle 701 | vm 702 | vms 703 | vmware 704 | vnc 705 | vod 706 | voip 707 | vpn 708 | vpn1 709 | vpn2 710 | vpn3 711 | vps 712 | vps1 713 | vps2 714 | w 715 | w3 716 | wap 717 | wc 718 | web 719 | web0 720 | web01 721 | web02 722 | web03 723 | web1 724 | web2 725 | web3 726 | web4 727 | web5 728 | webadmin 729 | webcam 730 | webconf 731 | webct 732 | webdb 733 | webdisk 734 | weblog 735 | webmail 736 | webmail2 737 | webmaster 738 | webmin 739 | webservices 740 | webstats 741 | webstore 742 | whm 743 | wifi 744 | wiki 745 | win 746 | win32 747 | windows 748 | wordpress 749 | work 750 | wp 751 | ws 752 | wsus 753 | ww 754 | ww0 755 | ww01 756 | ww02 757 | ww03 758 | ww1 759 | ww2 760 | ww3 761 | www 762 | www-test 763 | www0 764 | www01 765 | www02 766 | www03 767 | www1 768 | www2 769 | www3 770 | www4 771 | www5 772 | www6 773 | www7 774 | wwwm 775 | wwwold 776 | wwww 777 | x 778 | xml 779 | zabbix 780 | zeus 781 | zimbra 782 | -------------------------------------------------------------------------------- /dns/dns.go: -------------------------------------------------------------------------------- 1 | package retryabledns 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "encoding/json" 7 | "math/rand" 8 | "net" 9 | "reflect" 10 | "sort" 11 | "strings" 12 | "sync" 13 | "time" 14 | //"fmt" 15 | 16 | dnsManager "github.com/bp0lr/dmut/dnsManager" 17 | 18 | "github.com/miekg/dns" 19 | ) 20 | 21 | // Client is a DNS resolver client to resolve hostnames. 22 | type Client struct { 23 | resolvers []string 24 | maxRetries int 25 | dnsTimeOut int 26 | errorLimit int 27 | mutex *sync.Mutex 28 | } 29 | 30 | // New creates a new dns client 31 | func New(dnsTimeOut int, maxRetries int, errorLimit int) *Client { 32 | client := Client{ 33 | mutex: &sync.Mutex{}, 34 | dnsTimeOut: dnsTimeOut, 35 | maxRetries: maxRetries, 36 | errorLimit: errorLimit, 37 | } 38 | return &client 39 | } 40 | 41 | // Resolve is the underlying resolve function that actually resolves a host 42 | // and gets the ip records for that host. 43 | func (c *Client) Resolve(host string) (*DNSData, error) { 44 | return c.Query(host, dns.TypeA, "") 45 | } 46 | 47 | // Do sends a provided dns request and return the raw native response 48 | func (c *Client) Do(msg *dns.Msg) (resp *dns.Msg, err error) { 49 | 50 | cli := dns.Client{Net: "udp", Timeout: time.Duration(c.dnsTimeOut) * time.Millisecond} 51 | 52 | for i := 0; i < c.maxRetries; i++ { 53 | resolver := c.resolvers[rand.Intn(len(c.resolvers))] 54 | resp, _, err = cli.Exchange(msg, resolver) 55 | if err != nil { 56 | //fmt.Printf("err: %v\n", err) 57 | continue 58 | } 59 | 60 | // In case we get a non empty answer stop retrying 61 | if resp != nil { 62 | return 63 | } 64 | } 65 | 66 | return 67 | } 68 | 69 | // Query sends a provided dns request and return enriched response 70 | func (c *Client) Query(host string, requestType uint16, customDNSServer string) (*DNSData, error) { 71 | return c.QueryMultiple(host, []uint16{requestType}, customDNSServer) 72 | } 73 | 74 | // QueryMultiple sends a provided dns request and return the data 75 | func (c *Client) QueryMultiple(host string, requestTypes []uint16, customDNSServer string) (*DNSData, error) { 76 | 77 | var ( 78 | dnsdata DNSData 79 | err error 80 | msg dns.Msg 81 | ) 82 | 83 | cliUDP := dns.Client{Net: "udp", Timeout: time.Duration(c.dnsTimeOut) * time.Millisecond} 84 | for _, requestType := range requestTypes { 85 | 86 | msg.Id = dns.Id() 87 | msg.RecursionDesired = true 88 | msg.Question = make([]dns.Question, 1) 89 | 90 | name := dns.Fqdn(host) 91 | 92 | // In case of PTR adjust the domain name 93 | if requestType == dns.TypePTR { 94 | var err error 95 | if net.ParseIP(host) != nil { 96 | name, err = dns.ReverseAddr(host) 97 | if err != nil { 98 | return nil, err 99 | } 100 | } 101 | msg.SetEdns0(dns.DefaultMsgSize, false) 102 | } 103 | 104 | question := dns.Question{ 105 | Name: name, 106 | Qtype: requestType, 107 | Qclass: dns.ClassINET, 108 | } 109 | 110 | msg.Question[0] = question 111 | 112 | var dnsServer string 113 | for i := 0; i < c.maxRetries; i++ { 114 | 115 | if(len(customDNSServer) == 0){ 116 | val:=dnsManager.ReturnRandomDNSServerEntry(); 117 | dnsServer = val.Host 118 | }else{ 119 | dnsServer = customDNSServer 120 | } 121 | 122 | var resp *dns.Msg 123 | resp, _, err = cliUDP.Exchange(&msg, dnsServer) 124 | 125 | if err != nil { 126 | dnsManager.ReportDNSError(dnsServer, c.errorLimit) 127 | //fmt.Printf("err: %v\n", err) 128 | continue; 129 | } 130 | 131 | if resp != nil && resp.Truncated { 132 | //fmt.Printf("[truncate | %v]: %v\n", dnsServer, msg.Question[0].String()) 133 | 134 | //We have a truncated response, lets retry the query using TCP 135 | cliTCP := dns.Client{Net: "tcp", Timeout: time.Duration(c.dnsTimeOut) * time.Millisecond} 136 | resp, _, err = cliTCP.Exchange(&msg, dnsServer) 137 | } 138 | 139 | if err != nil && len(customDNSServer) == 0 { 140 | dnsManager.ReportDNSError(dnsServer, c.errorLimit) 141 | //fmt.Printf("err: %v\n", err) 142 | continue; 143 | } 144 | 145 | if(dns.RcodeToString[resp.Rcode] == "SERVFAIL"){ 146 | dnsManager.ReportDNSError(dnsServer, c.errorLimit) 147 | continue; 148 | } 149 | 150 | dnsdata.Host = host 151 | dnsdata.Raw += resp.String() 152 | dnsdata.StatusCode = dns.RcodeToString[resp.Rcode] 153 | 154 | if(dnsdata.StatusCode != "NXDOMAIN"){ 155 | //fmt.Printf("[%v] : %v\n", host, dnsdata.StatusCode) 156 | } 157 | 158 | dnsdata.Resolver = append(dnsdata.Resolver, dnsServer) 159 | dnsdata.OriReq = msg.String() 160 | dnsdata.OriRes = resp.String() 161 | 162 | dnsdata.ParseFromMsg(resp) 163 | break 164 | } 165 | } 166 | 167 | dnsdata.dedupe() 168 | return &dnsdata, err 169 | } 170 | 171 | func parse(answer *dns.Msg, requestType uint16) (results []string) { 172 | for _, record := range answer.Answer { 173 | switch requestType { 174 | case dns.TypeA: 175 | if t, ok := record.(*dns.A); ok { 176 | results = append(results, t.A.String()) 177 | } 178 | case dns.TypeNS: 179 | if t, ok := record.(*dns.NS); ok { 180 | results = append(results, t.Ns) 181 | } 182 | case dns.TypeCNAME: 183 | if t, ok := record.(*dns.CNAME); ok { 184 | results = append(results, t.Target) 185 | } 186 | case dns.TypeSOA: 187 | if t, ok := record.(*dns.SOA); ok { 188 | results = append(results, t.Mbox) 189 | } 190 | case dns.TypePTR: 191 | if t, ok := record.(*dns.PTR); ok { 192 | results = append(results, t.Ptr) 193 | } 194 | case dns.TypeMX: 195 | if t, ok := record.(*dns.MX); ok { 196 | results = append(results, t.Mx) 197 | } 198 | case dns.TypeTXT: 199 | if t, ok := record.(*dns.TXT); ok { 200 | results = append(results, t.Txt...) 201 | } 202 | case dns.TypeAAAA: 203 | if t, ok := record.(*dns.AAAA); ok { 204 | results = append(results, t.AAAA.String()) 205 | } 206 | } 207 | } 208 | 209 | return 210 | } 211 | 212 | //DNSData desc 213 | type DNSData struct { 214 | Host string `json:"host,omitempty"` 215 | TTL int `json:"ttl,omitempty"` 216 | Resolver []string `json:"resolver,omitempty"` 217 | A []string `json:"a,omitempty"` 218 | AAAA []string `json:"aaaa,omitempty"` 219 | CNAME []string `json:"cname,omitempty"` 220 | MX []string `json:"mx,omitempty"` 221 | PTR []string `json:"ptr,omitempty"` 222 | SOA []string `json:"soa,omitempty"` 223 | NS []string `json:"ns,omitempty"` 224 | TXT []string `json:"txt,omitempty"` 225 | Raw string `json:"raw,omitempty"` 226 | StatusCode string `json:"status_code,omitempty"` 227 | OriRes string 228 | OriReq string 229 | } 230 | 231 | // ParseFromMsg and enrich data 232 | func (d *DNSData) ParseFromMsg(msg *dns.Msg) error { 233 | for _, record := range msg.Answer { 234 | switch record.(type) { 235 | case *dns.A: 236 | d.A = append(d.A, trimChars(record.(*dns.A).A.String())) 237 | case *dns.NS: 238 | d.NS = append(d.NS, trimChars(record.(*dns.NS).Ns)) 239 | case *dns.CNAME: 240 | d.CNAME = append(d.CNAME, trimChars(record.(*dns.CNAME).Target)) 241 | case *dns.SOA: 242 | d.SOA = append(d.SOA, trimChars(record.(*dns.SOA).Mbox)) 243 | case *dns.PTR: 244 | d.PTR = append(d.PTR, trimChars(record.(*dns.PTR).Ptr)) 245 | case *dns.MX: 246 | d.MX = append(d.MX, trimChars(record.(*dns.MX).Mx)) 247 | case *dns.TXT: 248 | for _, txt := range record.(*dns.TXT).Txt { 249 | d.TXT = append(d.TXT, trimChars(txt)) 250 | } 251 | case *dns.AAAA: 252 | d.AAAA = append(d.AAAA, trimChars(record.(*dns.AAAA).AAAA.String())) 253 | } 254 | } 255 | 256 | return nil 257 | } 258 | 259 | // JSON returns the object as json string 260 | func (d *DNSData) JSON() (string, error) { 261 | b, err := json.Marshal(&d) 262 | return string(b), err 263 | } 264 | 265 | func trimChars(s string) string { 266 | return strings.TrimRight(s, ".") 267 | } 268 | 269 | func (d *DNSData) dedupe() { 270 | // dedupe all records 271 | dedupeSlice(&d.Resolver, less(&d.Resolver)) 272 | dedupeSlice(&d.A, less(&d.A)) 273 | dedupeSlice(&d.AAAA, less(&d.AAAA)) 274 | dedupeSlice(&d.CNAME, less(&d.CNAME)) 275 | dedupeSlice(&d.MX, less(&d.MX)) 276 | dedupeSlice(&d.PTR, less(&d.PTR)) 277 | dedupeSlice(&d.SOA, less(&d.SOA)) 278 | dedupeSlice(&d.NS, less(&d.NS)) 279 | dedupeSlice(&d.TXT, less(&d.TXT)) 280 | } 281 | 282 | //Marshal desc 283 | func (d *DNSData) Marshal() ([]byte, error) { 284 | var b bytes.Buffer 285 | enc := gob.NewEncoder(&b) 286 | err := enc.Encode(d) 287 | if err != nil { 288 | return nil, err 289 | } 290 | 291 | return b.Bytes(), nil 292 | } 293 | 294 | //Unmarshal desc 295 | func (d *DNSData) Unmarshal(b []byte) error { 296 | dec := gob.NewDecoder(bytes.NewBuffer(b)) 297 | err := dec.Decode(&d) 298 | if err != nil { 299 | return err 300 | } 301 | return nil 302 | } 303 | 304 | func less(v interface{}) func(i, j int) bool { 305 | s := *v.(*[]string) 306 | return func(i, j int) bool { return s[i] < s[j] } 307 | } 308 | 309 | func dedupeSlice(slicePtr interface{}, less func(i, j int) bool) { 310 | v := reflect.ValueOf(slicePtr).Elem() 311 | if v.Len() <= 1 { 312 | return 313 | } 314 | sort.Slice(v.Interface(), less) 315 | 316 | i := 0 317 | for j := 1; j < v.Len(); j++ { 318 | if !less(i, j) { 319 | continue 320 | } 321 | i++ 322 | v.Index(i).Set(v.Index(j)) 323 | } 324 | i++ 325 | v.SetLen(i) 326 | } -------------------------------------------------------------------------------- /dnsManager/dnsManager.go: -------------------------------------------------------------------------------- 1 | package dnsmanager 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "time" 7 | "strings" 8 | "math/rand" 9 | ) 10 | 11 | //DNSServerEntry desc 12 | type DNSServerEntry struct { 13 | Host string 14 | Status bool 15 | Errors int 16 | } 17 | 18 | var dnsServersTable []DNSServerEntry 19 | 20 | //GenerateDNSServersTable desc 21 | func GenerateDNSServersTable(hosts []string)bool{ 22 | 23 | hosts=validateDNSServers(hosts) 24 | 25 | if(len(hosts) < 1){ 26 | fmt.Printf("There is a problem with the dns server list. Please check manually\n") 27 | os.Exit(0) 28 | } 29 | 30 | for _, value:=range hosts{ 31 | d:=DNSServerEntry{value, true, 0} 32 | dnsServersTable = append(dnsServersTable, d) 33 | } 34 | return true 35 | } 36 | 37 | //ReturnFullServersList desc 38 | func ReturnFullServersList()([]DNSServerEntry, int){ 39 | return dnsServersTable, len(dnsServersTable) 40 | } 41 | 42 | //ReturnRandomDNSServerEntry desc 43 | func ReturnRandomDNSServerEntry() DNSServerEntry{ 44 | 45 | if(len(dnsServersTable) == 0){ 46 | fmt.Printf("Every DNS Server in our list has over past our error limit. Please try increasing this number using the flag ---dns-errorLimit and playing a bit with --dns-timeout") 47 | os.Exit(0) 48 | } 49 | 50 | var pick DNSServerEntry 51 | 52 | for i := 0; i < 100; i++ { 53 | rand.Seed(time.Now().UnixNano()) 54 | randomIndex := rand.Intn(len(dnsServersTable)) 55 | 56 | pick = dnsServersTable[randomIndex] 57 | if(dnsServersTable[randomIndex].Status == true){ 58 | return pick 59 | } 60 | } 61 | 62 | fmt.Printf("\nOur dns server list has reported to many errors. I can't continue.\n") 63 | os.Exit(0) 64 | 65 | return pick 66 | } 67 | 68 | //ReportDNSError desc 69 | func ReportDNSError(host string, errorsLimit int){ 70 | 71 | for id, v:=range dnsServersTable{ 72 | if(v.Host == host){ 73 | dnsServersTable[id].Errors = dnsServersTable[id].Errors + 1 74 | if(dnsServersTable[id].Errors > errorsLimit){ 75 | //fmt.Printf("CANCELING THIS SERVER: %v || errors: %v\n", host, dnsServersTable[id].Errors) 76 | dnsServersTable[id].Status = false 77 | } 78 | } 79 | } 80 | } 81 | 82 | //ValidateDNSServers func 83 | func validateDNSServers(servers []string) []string{ 84 | var res []string 85 | 86 | for _, value := range servers{ 87 | if(len(value)< 1){ 88 | continue 89 | } 90 | 91 | s := strings.Split(value, ":") 92 | if(len(s) > 1){ 93 | res = append(res, value) 94 | } else{ 95 | res = append(res, value+":53") 96 | } 97 | } 98 | 99 | return res 100 | } 101 | 102 | //ReturnDNSServersSlice desc 103 | func ReturnDNSServersSlice()[]string{ 104 | var s []string 105 | for _,v:=range dnsServersTable{ 106 | s=append(s, v.Host) 107 | } 108 | 109 | return s 110 | } 111 | 112 | //PrintDNSServerList desc 113 | func PrintDNSServerList(){ 114 | var separator = " ----------------------------------------- " 115 | 116 | fmt.Println("") 117 | fmt.Println(separator) 118 | fmt.Println(" | DNS Server List |") 119 | fmt.Println(separator) 120 | fmt.Println(" | ip | errors | status |") 121 | fmt.Println(separator) 122 | 123 | for _,v:=range dnsServersTable{ 124 | fmt.Printf(" | %20s | %6v | %6v |\n", v.Host, v.Errors, v.Status) 125 | } 126 | 127 | fmt.Println(separator) 128 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bp0lr/dmut 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect 7 | github.com/VividCortex/ewma v1.2.0 // indirect 8 | github.com/cheggaaa/pb/v3 v3.0.8 9 | github.com/go-ole/go-ole v1.2.5 // indirect 10 | github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 11 | github.com/miekg/dns v1.1.42 12 | github.com/projectdiscovery/retryabledns v1.0.5 13 | github.com/schollz/progressbar/v3 v3.7.2 14 | github.com/shirou/gopsutil v3.21.4+incompatible 15 | github.com/spf13/pflag v1.0.5 16 | github.com/weppos/publicsuffix-go v0.15.0 17 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect 18 | golang.org/x/net v0.0.0-20210508051633-16afe75a6701 // indirect 19 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY= 2 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 3 | github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= 4 | github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= 5 | github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= 6 | github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= 7 | github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= 8 | github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE= 9 | github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw= 10 | github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= 11 | github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= 15 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 16 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= 17 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 18 | github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= 19 | github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 20 | github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= 21 | github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= 22 | github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= 23 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 24 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 25 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 26 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 27 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 28 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 29 | github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= 30 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 31 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 32 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 33 | github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= 34 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 35 | github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 36 | github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= 37 | github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 38 | github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY= 39 | github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= 40 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= 41 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= 42 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 43 | github.com/projectdiscovery/retryabledns v1.0.5 h1:bQivGy5CuqKlwcxRkgA5ENincqIed/BR2sA6t2gdwuI= 44 | github.com/projectdiscovery/retryabledns v1.0.5/go.mod h1:/UzJn4I+cPdQl6pKiiQfvVAT636YZvJQYZhYhGB0dUQ= 45 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 46 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 47 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 48 | github.com/schollz/progressbar v1.0.0 h1:gbyFReLHDkZo8mxy/dLWMr+Mpb1MokGJ1FqCiqacjZM= 49 | github.com/schollz/progressbar/v3 v3.7.2 h1:0mjLacO6y9vSdcopQ8TEK8AsIWFJXTVU9eJDkoR/MkE= 50 | github.com/schollz/progressbar/v3 v3.7.2/go.mod h1:CG/f0JmacksUc6TkZToO7tVq4t03zIQSQUtTd7F9GR4= 51 | github.com/shirou/gopsutil v3.21.4+incompatible h1:fuHcTm5mX+wzo542cmYcV9RTGQLbnHLI5SyQ5ryTVck= 52 | github.com/shirou/gopsutil v3.21.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 53 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 54 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 55 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 56 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 57 | github.com/weppos/publicsuffix-go v0.13.0 h1:0Tu1uzLBd1jPn4k6OnMmOPZH/l/9bj9kUOMMkoRs6Gg= 58 | github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= 59 | github.com/weppos/publicsuffix-go v0.15.0 h1:2uQCwDczZ8YZe5uD0mM3sXRoZYA74xxPuiKK8LdPcGQ= 60 | github.com/weppos/publicsuffix-go v0.15.0/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= 61 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 62 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= 63 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 64 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU= 65 | golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 66 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 67 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 68 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 69 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 70 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= 71 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 72 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 73 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 74 | golang.org/x/net v0.0.0-20210508051633-16afe75a6701 h1:lQVgcB3+FoAXOb20Dp6zTzAIrpj1k/yOOBN7s+Zv1rA= 75 | golang.org/x/net v0.0.0-20210508051633-16afe75a6701/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 76 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 77 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 78 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 79 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 80 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 81 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 83 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= 84 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 85 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 86 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 87 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 88 | golang.org/x/sys v0.0.0-20201113135734-0a15ea8d9b02 h1:5Ftd3YbC/kANXWCBjvppvUmv1BMakgFcBKA7MpYYp4M= 89 | golang.org/x/sys v0.0.0-20201113135734-0a15ea8d9b02/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 | golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 93 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 94 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096 h1:5PbJGn5Sp3GEUjJ61aYbUP6RIo3Z3r2E4Tv9y2z8UHo= 95 | golang.org/x/sys v0.0.0-20210507161434-a76c4d0a0096/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 96 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 97 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 98 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 99 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 100 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 101 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 102 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 103 | golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 104 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 105 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // 2 | // @bp0lr - 30/11/2020 3 | // 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "fmt" 10 | "io/ioutil" 11 | "net/url" 12 | "os" 13 | "path" 14 | "strings" 15 | "sync" 16 | 17 | def "github.com/bp0lr/dmut/defines" 18 | dnsManager "github.com/bp0lr/dmut/dnsManager" 19 | resolver "github.com/bp0lr/dmut/resolver" 20 | tables "github.com/bp0lr/dmut/tables" 21 | util "github.com/bp0lr/dmut/util" 22 | 23 | flag "github.com/spf13/pflag" 24 | tld "github.com/weppos/publicsuffix-go/publicsuffix" 25 | 26 | miekg "github.com/miekg/dns" 27 | 28 | pb "github.com/cheggaaa/pb/v3" 29 | ) 30 | 31 | var ( 32 | workersArg int 33 | dnsRetriesArg int 34 | dnsTimeOutArg int 35 | dnserrorLimitArg int 36 | mutationsDic string 37 | urlArg string 38 | outputFileArg string 39 | dnsFileArg string 40 | dnsArg string 41 | saveLocationArg string 42 | verboseArg bool 43 | updateDNSArg bool 44 | updateNeededFIlesArg bool 45 | ipArg bool 46 | statsArg bool 47 | pbArg bool 48 | saveAndExitArg bool 49 | dnsServers []string 50 | PermutationListArg def.PermutationList 51 | ) 52 | 53 | 54 | //GlobalStats desc 55 | var GlobalStats def.Stats 56 | 57 | //GlobalLoadStats desc 58 | var GlobalLoadStats def.LoadStats 59 | 60 | var bar *pb.ProgressBar 61 | 62 | func main() { 63 | 64 | var alterations []string 65 | 66 | flag.IntVarP(&workersArg, "workers", "w", 25, "Number of workers") 67 | flag.StringVarP(&urlArg, "url", "u", "", "Target URL") 68 | flag.BoolVarP(&verboseArg, "verbose", "v", false, "Add verboicity to the process") 69 | flag.StringVarP(&mutationsDic, "dictionary", "d", "", "Dictionary file containing mutation list") 70 | flag.StringVarP(&outputFileArg, "output", "o", "", "Output file to save the results to") 71 | flag.StringVarP(&dnsFileArg, "dnsFile", "s", "", "Use DNS servers from this file") 72 | flag.StringVarP(&dnsArg, "dnsServers", "l", "", "Use DNS servers from a list separated by ,") 73 | flag.BoolVar(&updateDNSArg, "update-dnslist", false, "Download a list of periodically validated public DNS resolvers") 74 | flag.BoolVar(&ipArg, "show-ip", false, "Display info for valid results") 75 | flag.BoolVar(&statsArg, "show-stats", false, "Display stats about the current job") 76 | flag.IntVar(&dnsRetriesArg, "dns-retries", 3, "Amount of retries for failed dns queries") 77 | flag.IntVar(&dnsTimeOutArg, "dns-timeout", 500, "Dns Server timeOut in millisecond") 78 | flag.IntVar(&dnserrorLimitArg, "dns-errorLimit", 25, "How many errors until we the DNS is disabled") 79 | flag.BoolVar(&pbArg, "use-pb", false, "use a progress bar") 80 | flag.BoolVar(&saveAndExitArg, "save-gen", false, "save generated permutations to a file and exit") 81 | flag.StringVarP(&saveLocationArg, "save-to", "", "generated.txt", "save generated file to this location") 82 | 83 | flag.BoolVar(&PermutationListArg.AddToDomain, "disable-permutations", false, "Disable permutations generation") 84 | flag.BoolVar(&PermutationListArg.AddNumbers, "disable-addnumbers", false, "Disable add numbers generation") 85 | flag.BoolVar(&PermutationListArg.AddSeparator, "disable-addseparator", false, "Disable add separator generation") 86 | 87 | flag.BoolVar(&updateNeededFIlesArg, "update-files", false, "Download all the default files to work with dmut. (default mutation list, resolvers, etc)") 88 | 89 | flag.Parse() 90 | 91 | if(updateDNSArg || updateNeededFIlesArg){ 92 | dnsListTxt, errDNSListTxt:=util.DownloadFile("https://raw.githubusercontent.com/bp0lr/dmut-resolvers/main/resolvers.txt", "resolvers.txt") 93 | if(errDNSListTxt != nil){ 94 | fmt.Printf("[-] Error: %v\n", errDNSListTxt) 95 | }else{ 96 | fmt.Printf("[+] Location: %v\n", dnsListTxt) 97 | } 98 | 99 | dnsListTopTxt, errDNSListTopTxt:=util.DownloadFile("https://raw.githubusercontent.com/bp0lr/dmut-resolvers/main/top20.txt", "top20.txt") 100 | if(errDNSListTopTxt != nil){ 101 | fmt.Printf("[-] Error: %v\n", errDNSListTopTxt) 102 | }else{ 103 | fmt.Printf("[+] Location: %v\n", dnsListTopTxt) 104 | } 105 | 106 | mutationListTxt, errMutationTxt:=util.DownloadFile("https://raw.githubusercontent.com/bp0lr/dmut/main/words.txt", "words.txt") 107 | if(errMutationTxt != nil){ 108 | fmt.Printf("[-] Error: %v\n", errMutationTxt) 109 | }else{ 110 | fmt.Printf("[+] Location: %v\n", mutationListTxt) 111 | } 112 | 113 | fmt.Print("[+] download finished\n") 114 | return 115 | 116 | } 117 | 118 | //concurrency 119 | workers := 25 120 | if workersArg > 0 && workersArg < 151 { 121 | workers = workersArg 122 | }else{ 123 | fmt.Printf("[+] Workers amount should be between 1 and 150.\n") 124 | fmt.Printf("[+] The number of workers was set to 25.\n") 125 | } 126 | 127 | if(dnsTimeOutArg == 0 || dnsTimeOutArg > 10000) { 128 | dnsTimeOutArg = 500 129 | } 130 | 131 | if(verboseArg){ 132 | fmt.Printf("[+] Workers: %v\n", workers) 133 | } 134 | 135 | if(len(dnsFileArg) > 0){ 136 | if _, err := os.Stat(dnsFileArg); os.IsNotExist(err) { 137 | fmt.Printf("Error, %v\n", err) 138 | return 139 | } 140 | 141 | content, _ := ioutil.ReadFile(dnsFileArg) 142 | dnsServers = strings.Split(string(content), "\n") 143 | } 144 | 145 | if(len(dnsArg) > 0){ 146 | dnsServers = strings.Split(dnsArg, ",") 147 | } 148 | 149 | if(len(dnsServers) == 0){ 150 | userDir, err:=util.GetDir() 151 | if err != nil{ 152 | userDir="" 153 | } 154 | 155 | fullPath:= path.Join(userDir, "resolvers.txt") 156 | if _, err := os.Stat(fullPath); !os.IsNotExist(err) { 157 | content, _ := ioutil.ReadFile(fullPath) 158 | dnsServers = strings.Split(string(content), "\n") 159 | }else{ 160 | dnsServers = []string{ 161 | "1.1.1.1:53", // Cloudflare 162 | "1.0.0.1:53", // Cloudflare 163 | "8.8.8.8:53", // Google 164 | "8.8.4.4:53", // Google 165 | "9.9.9.9:53", // Quad9 166 | } 167 | } 168 | } 169 | 170 | dnsManager.GenerateDNSServersTable(dnsServers); 171 | 172 | if(verboseArg){ 173 | fmt.Printf("[+] we are using this dns servers: %v\n", dnsManager.ReturnDNSServersSlice()) 174 | fmt.Printf("[+] Current dns timeout is: %v\n", dnsTimeOutArg) 175 | } 176 | 177 | if(len(mutationsDic) == 0){ 178 | fmt.Printf("Error, you need to define a mutation file list using the arg -d\n") 179 | return 180 | } 181 | 182 | if(len(mutationsDic) > 0){ 183 | if _, err := os.Stat(mutationsDic); os.IsNotExist(err) { 184 | fmt.Printf("Error, %v\n", err) 185 | return 186 | } 187 | 188 | mutations, _ := ioutil.ReadFile(mutationsDic) 189 | alterations = strings.Split(string(mutations), "\n") 190 | } 191 | 192 | GlobalStats.Mutations = len(alterations) 193 | 194 | var outputFile *os.File 195 | var err0 error 196 | if outputFileArg != "" { 197 | outputFile, err0 = os.OpenFile(outputFileArg, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644) 198 | if err0 != nil { 199 | fmt.Printf("cannot write %s: %s", outputFileArg, err0.Error()) 200 | return 201 | } 202 | 203 | defer outputFile.Close() 204 | } 205 | 206 | var jobs []string 207 | 208 | if len(urlArg) < 1 { 209 | sc := bufio.NewScanner(os.Stdin) 210 | for sc.Scan() { 211 | jobs = append(jobs, sc.Text()) 212 | } 213 | } else { 214 | jobs = append(jobs, urlArg) 215 | } 216 | 217 | GlobalStats.Domains = len(jobs) 218 | 219 | /////////////////////////////// 220 | // generate taks list 221 | /////////////////////////////// 222 | targetDomains := make(chan string) 223 | var wg sync.WaitGroup 224 | var mu = &sync.Mutex{} 225 | 226 | for i := 0; i < 30; i++ { 227 | wg.Add(1) 228 | go func() { 229 | for task := range targetDomains { 230 | sl, _ :=generateTable(task, alterations, dnsTimeOutArg, dnsRetriesArg, dnserrorLimitArg, PermutationListArg) 231 | if(sl != nil){ 232 | mu.Lock() 233 | GlobalStats.WorksToDo = append(GlobalStats.WorksToDo, sl...) 234 | mu.Unlock() 235 | } 236 | } 237 | wg.Done() 238 | }() 239 | } 240 | 241 | for _, line := range jobs { 242 | targetDomains <- line 243 | } 244 | 245 | close(targetDomains) 246 | wg.Wait() 247 | 248 | if(saveAndExitArg){ 249 | var file, err = os.Create(saveLocationArg) 250 | if err != nil { 251 | fmt.Printf("Error saving to %v\n%v\n", saveLocationArg, err) 252 | return 253 | } 254 | defer file.Close() 255 | 256 | file.WriteString(fmt.Sprintln(strings.Join(GlobalStats.WorksToDo, "\n"))) 257 | 258 | file.Sync() 259 | 260 | fmt.Printf("Permutation list saved to %v\n", saveLocationArg) 261 | os.Exit(0) 262 | } 263 | 264 | /////////////////////////////// 265 | // Lets process the task list 266 | /////////////////////////////// 267 | if(verboseArg){ 268 | fmt.Printf("total Domains: %v | valid: %v | errors: %v\n", GlobalLoadStats.Domains, GlobalLoadStats.Valid, GlobalLoadStats.Errors) 269 | fmt.Printf("Works to do: %v\n", len(GlobalStats.WorksToDo)) 270 | } 271 | 272 | if(pbArg){ 273 | tmpl := `{{ red "Mutations:" }} {{counters . | red}} {{ bar . "<" "-" (cycle . "↖" "↗" "↘" "↙" ) "." ">"}} {{percent .}} [{{speed . | green }}] [{{rtime . "ETA %s"}}]` 274 | bar = pb.ProgressBarTemplate(tmpl).Start(len(GlobalStats.WorksToDo)) 275 | //bar = pb.Full.Start(len(GlobalStats.WorksToDo)) 276 | bar.SetWidth(100) 277 | } 278 | 279 | tasks := make(chan string) 280 | var wg2 sync.WaitGroup 281 | 282 | for i := 0; i < workers; i++ { 283 | wg2.Add(1) 284 | go func() { 285 | for task := range tasks { 286 | //fullDomain:= task + "." + job.sld + "." + job.tld + "." 287 | processDNS(task, outputFile, dnsTimeOutArg, dnsRetriesArg, dnserrorLimitArg) 288 | } 289 | wg2.Done() 290 | }() 291 | } 292 | 293 | for _, line := range GlobalStats.WorksToDo { 294 | tasks <- line 295 | } 296 | 297 | close(tasks) 298 | wg2.Wait() 299 | 300 | /////////////////////////////// 301 | // Lets print the results 302 | /////////////////////////////// 303 | 304 | if(pbArg){ 305 | bar.Finish() 306 | } 307 | 308 | if(len(GlobalStats.FoundDomains) > 0 && pbArg){ 309 | fmt.Println("") 310 | for _,v:=range GlobalStats.FoundDomains{ 311 | fmt.Println(v) 312 | } 313 | } 314 | 315 | //if we didn't found anything, delete the result file. 316 | if(len(outputFileArg) > 0){ 317 | fi, err := os.Stat(outputFileArg) 318 | if err == nil { 319 | if(fi.Size() == 0){ 320 | os.Remove(outputFileArg) 321 | } 322 | } 323 | } 324 | 325 | if(statsArg){ 326 | dnsManager.PrintDNSServerList() 327 | fmt.Printf(" | Domains: %24v | \n", GlobalStats.Domains) 328 | fmt.Printf(" | mutations: %24v | \n", GlobalStats.Mutations) 329 | fmt.Printf(" | Queries: %24v | \n", len(GlobalStats.WorksToDo)) 330 | fmt.Printf(" | Sub Found: %24v | \n", GlobalStats.Founds) 331 | fmt.Printf(" -----------------------------------------\n") 332 | } 333 | } 334 | 335 | func generateTable(domain string, alterations [] string, dnsTimeOut int, dnsRetries int, dnsErrorLimit int, permutationList def.PermutationList) ([]string, error){ 336 | 337 | GlobalLoadStats.Domains++ 338 | 339 | _, err := url.Parse(domain) 340 | if err != nil { 341 | if verboseArg { 342 | fmt.Printf("[-] Invalid url: %s\n", domain) 343 | } 344 | GlobalLoadStats.Errors++ 345 | return nil, err 346 | } 347 | 348 | domParse, err :=tld.Parse(domain) 349 | if(err != nil){ 350 | if(verboseArg){ 351 | fmt.Printf("[-] Error parsing url: %s\n", domain) 352 | } 353 | 354 | GlobalLoadStats.Errors++ 355 | return nil, err 356 | } 357 | 358 | var job def.DmutJob 359 | job.Domain = domain //domain: lala.test.val.redbull.com 360 | job.Sld = domParse.SLD //sld: redbull 361 | job.Tld = domParse.TLD //tld: com 362 | job.Trd = domParse.TRD //trd: lala.test.val 363 | 364 | 365 | //testing if domain response like wildcard. If this is the case, we cancel this task. 366 | if(!saveAndExitArg){ 367 | if(checkWildCard(job, dnsTimeOut, dnsRetries, dnsErrorLimit)){ 368 | if(verboseArg){ 369 | fmt.Printf("[%v] dns wild card detected. Canceling this job!\n", domain) 370 | } 371 | GlobalLoadStats.Errors++ 372 | return nil, nil 373 | } 374 | } 375 | 376 | tmp:= tables.GenerateTables(job, alterations, permutationList) 377 | 378 | GlobalLoadStats.Valid++ 379 | 380 | return tmp, nil 381 | } 382 | 383 | func processDNS(domain string, outputFile *os.File, dnsTimeOut int, dnsRetries int, dnsErrorLimit int) { 384 | 385 | if verboseArg { 386 | fmt.Printf("[+] Testing: %v\n", domain) 387 | } 388 | 389 | qtype:= []uint16 {miekg.TypeA, miekg.TypeCNAME} 390 | // I prefer to make a single query for each type, stop it if a have found something to win some milliseconds. 391 | for _, value := range qtype{ 392 | 393 | //fmt.Printf("[%v] send type %v\n", domain, value) 394 | resp, err := resolver.GetDNSQueryResponse(domain, value, dnsTimeOut, dnsRetries, dnsErrorLimit, "") 395 | if(verboseArg){ 396 | if(err != nil){ 397 | fmt.Printf("err resolver: %v\n", err) 398 | } 399 | } 400 | 401 | if(!resp.Status){ 402 | continue 403 | } 404 | 405 | found:=processResponse(domain, resp, outputFile, value) 406 | if(found){ 407 | break 408 | } 409 | } 410 | 411 | if(pbArg){ 412 | bar.Increment() 413 | } 414 | } 415 | 416 | func processResponse(domain string, result resolver.JobResponse, outputFile *os.File, qType uint16)bool{ 417 | 418 | if (result.Status) { 419 | 420 | trimDomain:= util.TrimLastPoint(domain, ".") 421 | if(result.Data.StatusCode != "NOERROR"){ 422 | if(verboseArg){ 423 | fmt.Printf("[%v] code: %v\n", domain, result.Data.StatusCode) 424 | } 425 | return false 426 | } 427 | 428 | if(qType == miekg.TypeCNAME){ 429 | if(len(result.Data.CNAME) < 1){ 430 | //fmt.Printf("A NOERROR was reported for domain %v but CNAME was empty.\n", domain) 431 | //fmt.Printf("raw: %v\n", result.Data.Raw) 432 | return false 433 | } 434 | 435 | //fmt.Printf("[%v] reported a valid CNAME value for %v size: %v!\n", result.Data.Resolver, domain, len(result.Data.CNAME)) 436 | //fmt.Printf("debug: %v\n", result.Data.CNAME) 437 | } 438 | 439 | if(qType == miekg.TypeA){ 440 | if(len(result.Data.A) < 1){ 441 | //fmt.Printf("A NOERROR was reported for domain %v but A was empty.\n", domain) 442 | //fmt.Printf("raw: %v\n", result.Data.Raw) 443 | return false 444 | } 445 | 446 | //fmt.Printf("[%v] reported a valid A value for %v size: %v!\n", result.Data.Resolver, domain, len(result.Data.A)) 447 | //fmt.Printf("debug: %v\n", result.Data.A) 448 | 449 | } 450 | 451 | //re validated what we found again google dns just to be sure. 452 | retest, reErr := resolver.GetDNSQueryResponse(domain, qType, 500, 3, 10, "8.8.8.8:53") 453 | if(verboseArg){ 454 | if(reErr != nil){ 455 | //fmt.Printf("err resolver: %v\n", reErr) 456 | } 457 | } 458 | 459 | if(retest.Status){ 460 | if(retest.Data.StatusCode != "NOERROR"){ 461 | 462 | //fmt.Printf("[%v] ban by goole retest %v <> %v\n", domain, result.Data.StatusCode, retest.Data.StatusCode) 463 | //fmt.Printf("The domain %v was reported like OK, but can't pass the retest again google.\n", domain) 464 | //fmt.Printf("Verboise: %v\n", retest.Data.StatusCode) 465 | return false 466 | } 467 | 468 | //fmt.Printf("[%v] confirm by goole retest %v <> %v\n", domain, result.Data.StatusCode, retest.Data.StatusCode) 469 | //fmt.Printf("domain %v pass the re test!\n", domain) 470 | //fmt.Printf("Verboise: %v\n", retest.Data.StatusCode) 471 | //fmt.Printf("Verboise: %v\n", retest.Data.OriRes) 472 | }else{ 473 | return false 474 | } 475 | 476 | if outputFileArg != "" { 477 | if(ipArg){ 478 | outputFile.WriteString(trimDomain + ":" + util.TrimChars(strings.Join(result.Data.CNAME,",")) + util.TrimChars(strings.Join(result.Data.A,",")) + "\n") 479 | } else { 480 | outputFile.WriteString(trimDomain + "\n") 481 | } 482 | } 483 | if(!pbArg){ 484 | if(ipArg){ 485 | fmt.Printf("%v : [%v]:[%v]\n", trimDomain, util.TrimChars(strings.Join(result.Data.CNAME,",")) , util.TrimChars(strings.Join(result.Data.A,","))) 486 | }else{ 487 | fmt.Printf("%v\n", trimDomain) 488 | } 489 | }else{ 490 | GlobalStats.FoundDomains=append(GlobalStats.FoundDomains, trimDomain) 491 | } 492 | 493 | GlobalStats.Founds++ 494 | 495 | return true 496 | } 497 | 498 | return false 499 | } 500 | 501 | func checkWildCard(job def.DmutJob, dnsTimeOut int, dnsRetries int, dnsErrorLimit int)bool{ 502 | 503 | var res resolver.JobResponse 504 | var err error 505 | 506 | var mutations []string 507 | var wildcard bool = false 508 | var text = []string{"supposedtonotexistmyfriend"} 509 | 510 | tables.AddToDomain(job, text, &mutations) 511 | 512 | for _, mutation := range mutations{ 513 | //fmt.Printf("[%v] trying %v\n", job.Domain, mutation) 514 | res, err = resolver.GetDNSQueryResponse(mutation, miekg.TypeA, dnsTimeOut, dnsRetries, dnsErrorLimit, "8.8.8.8:53") 515 | if(err != nil){ 516 | //fmt.Printf("antiWild reported err: %v\n", err) 517 | continue 518 | } 519 | 520 | if(res.Status && res.Data.StatusCode != "NXDOMAIN"){ 521 | //fmt.Printf("[%v] Wilcard Positive response. Canceling tasks: %v\n", job.Domain, mutation) 522 | wildcard = true 523 | break 524 | } 525 | 526 | res, err = resolver.GetDNSQueryResponse(mutation, miekg.TypeCNAME, dnsTimeOut, dnsRetries, dnsErrorLimit, "8.8.8.8:53") 527 | if(err != nil){ 528 | //fmt.Printf("antiWild reported err: %v\n", err) 529 | continue 530 | } 531 | 532 | if(res.Status && res.Data.StatusCode != "NXDOMAIN"){ 533 | //fmt.Printf("[%v] Wilcard Positive response. Canceling tasks: %v\n", job.Domain, mutation) 534 | wildcard = true 535 | break 536 | } 537 | } 538 | 539 | return wildcard 540 | } -------------------------------------------------------------------------------- /resolver/resolver.go: -------------------------------------------------------------------------------- 1 | package resolver 2 | 3 | import ( 4 | dns "github.com/bp0lr/dmut/dns" 5 | ) 6 | 7 | //JobResponse desc 8 | type JobResponse struct { 9 | Domain string 10 | Status bool 11 | Data dns.DNSData 12 | } 13 | 14 | //GetDNSQueryResponse desc 15 | func GetDNSQueryResponse(fqdn string, qType uint16, dnsTimeOut int, retries int, errorLimit int, customDNSServer string) (JobResponse, error) { 16 | var res JobResponse 17 | res.Domain = fqdn 18 | 19 | dnsClient := dns.New(dnsTimeOut, retries, errorLimit) 20 | resp, err := dnsClient.Query(fqdn, qType, customDNSServer) 21 | if err == nil { 22 | res.Status = true 23 | res.Data = *resp 24 | 25 | return res, nil 26 | } 27 | 28 | res.Status = false 29 | return res, nil 30 | } 31 | -------------------------------------------------------------------------------- /tables/tables.go: -------------------------------------------------------------------------------- 1 | package tables 2 | 3 | import ( 4 | //"os" 5 | //"fmt" 6 | 7 | "strconv" 8 | "strings" 9 | 10 | def "github.com/bp0lr/dmut/defines" 11 | util "github.com/bp0lr/dmut/util" 12 | ) 13 | 14 | type dmutJob = def.DmutJob 15 | 16 | //GenerateTables desc 17 | func GenerateTables(job def.DmutJob, alterations []string, pList def.PermutationList) []string{ 18 | 19 | var res []string 20 | 21 | if(!pList.AddToDomain){ 22 | AddToDomain(job, alterations, &res) 23 | } 24 | 25 | if(!pList.AddNumbers){ 26 | AddNumbers(job, &res) 27 | } 28 | 29 | if(!pList.AddSeparator){ 30 | AddSeparator(job, alterations, &res) 31 | } 32 | 33 | //IncreaseNumbers(job, &res) 34 | 35 | //removing duplicated from job.tasks 36 | res = util.RemoveDuplicatesSlice(res) 37 | 38 | return res 39 | } 40 | 41 | //AddToDomain desc 42 | func AddToDomain(job dmutJob, alterations []string, res *[]string){ 43 | 44 | // this will add each alteration to the existing domain. 45 | // for example to test some.test.com we are going to generate alt1.some.test.com and some.alt1.test.com 46 | /////////////////////////////////////////////////////////////////////////////////////////////// 47 | for _, alt := range alterations { 48 | if(len(alt) < 1){ 49 | continue 50 | } 51 | 52 | strSplit := strings.Split(job.Trd, ".") 53 | 54 | if(strSplit[0] == ""){ 55 | fullDomain:= alt + "." + job.Sld + "." + job.Tld 56 | *res = append(*res, fullDomain) 57 | continue 58 | } 59 | 60 | for i := 0; i <= len(strSplit); i++ { 61 | val:=util.Insert(strSplit, i, alt) 62 | fullDomain:= strings.Join(val, ".") + "." + job.Sld + "." + job.Tld 63 | //fmt.Printf("val: %v\n", fullDomain) 64 | *res = append(*res, fullDomain) 65 | } 66 | } 67 | } 68 | /* 69 | //IncreaseNumbers number 70 | func IncreaseNumbers(job def.DmutJob, res *[]string){ 71 | 72 | strSplit := strings.Split(job.Trd, ".") 73 | 74 | for i := 0; i < len(strSplit); i++ { 75 | ok, err := strconv.Atoi(strSplit[i]) 76 | if(err == nil){ 77 | fmt.Printf("test: %v | %v\n", strSplit, len(strSplit)) 78 | fmt.Printf("[%v] Valid: %v => %v\n", job.Domain, strSplit[i], ok); 79 | 80 | for i = 81 | strSplit[i] = strclean+"-"+alt 82 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 83 | *res = append(*res, fullDomain) 84 | 85 | 86 | } 87 | } 88 | 89 | } 90 | */ 91 | 92 | //AddNumbers desc 93 | func AddNumbers(job def.DmutJob, res *[]string){ 94 | 95 | // this will add a number to the end of each subdmain part. 96 | // for example to test some.test.com we are going to generate some1.some.test.com, some2.alt1.test.com, etc 97 | /////////////////////////////////////////////////////////////////////////////////////////////// 98 | for index := 0; index < 10; index++ { 99 | strSplit := strings.Split(job.Trd, ".") 100 | 101 | if(strSplit[0] == ""){ 102 | fullDomain:= strconv.Itoa(index) + "." + job.Sld + "." + job.Tld 103 | *res = append(*res, fullDomain) 104 | continue 105 | } 106 | 107 | var fullDomain string 108 | for i := 0; i < len(strSplit); i++ { 109 | strclean:=strSplit[i] 110 | strSplit[i] = strclean+"-"+strconv.Itoa(index) 111 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 112 | *res = append(*res, fullDomain) 113 | 114 | strSplit[i] = strclean+strconv.Itoa(index) 115 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 116 | *res = append(*res, fullDomain) 117 | } 118 | } 119 | } 120 | 121 | //AddSeparator desc 122 | func AddSeparator(job def.DmutJob, alterations []string, res *[]string){ 123 | 124 | // this will add (clean and using a -) each alteration to each subdomain part. 125 | // for example to test some.test.com we are going to generate some-alt1.test.com, alt1-some.test.com, etc 126 | /////////////////////////////////////////////////////////////////////////////////////////////// 127 | for _, alt := range alterations { 128 | if(len(alt) < 1){ 129 | continue 130 | } 131 | 132 | var fullDomain string 133 | 134 | strSplit := strings.Split(job.Trd, ".") 135 | 136 | if(strSplit[0] == ""){ 137 | continue 138 | } 139 | 140 | for i := 0; i < len(strSplit); i++ { 141 | strclean:=strSplit[i] 142 | 143 | strSplit[i] = strclean+"-"+alt 144 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 145 | *res = append(*res, fullDomain) 146 | 147 | strSplit[i] = alt+"-"+strclean 148 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 149 | *res = append(*res, fullDomain) 150 | 151 | strSplit[i] = strclean+alt 152 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 153 | *res = append(*res, fullDomain) 154 | 155 | strSplit[i] = alt+strclean 156 | fullDomain= strings.Join(strSplit, ".") + "." + job.Sld + "." + job.Tld 157 | *res = append(*res, fullDomain) 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "os/user" 7 | "path/filepath" 8 | "strings" 9 | "net/http" 10 | 11 | mem "github.com/shirou/gopsutil/mem" 12 | ) 13 | 14 | //Insert func 15 | func Insert(a []string, index int, value string) []string { 16 | if len(a) == index { 17 | return append(a, value) 18 | } 19 | a = append(a[:index+1], a[index:]...) 20 | a[index] = value 21 | return a 22 | } 23 | 24 | //TrimLastPoint func 25 | func TrimLastPoint(s, suffix string) string { 26 | if strings.HasSuffix(s, suffix) { 27 | s = s[:len(s)-len(suffix)] 28 | } 29 | return s 30 | } 31 | 32 | //RemoveDuplicatesSlice func 33 | func RemoveDuplicatesSlice(s []string) []string { 34 | m := make(map[string]bool) 35 | for _, item := range s { 36 | if _, ok := m[item]; ok { 37 | //fmt.Printf("Duplicate: %v\n", item) 38 | } else { 39 | m[item] = true 40 | } 41 | } 42 | 43 | var result []string 44 | for item := range m { 45 | result = append(result, item) 46 | } 47 | 48 | return result 49 | } 50 | 51 | //TrimChars func 52 | func TrimChars(s string) string { 53 | return strings.TrimRight(s, ".") 54 | } 55 | 56 | //DownloadFile func 57 | func DownloadFile(url string, saveName string) (string, error){ 58 | 59 | dir,err := GetDir() 60 | if(err != nil){ 61 | return "", err 62 | } 63 | os.MkdirAll(dir, 0644) 64 | 65 | fullPath := filepath.Join(dir, saveName) 66 | 67 | os.Remove(fullPath) 68 | out, err := os.Create(fullPath) 69 | if err != nil { 70 | return "", err 71 | } 72 | defer out.Close() 73 | 74 | resp, err := http.Get(url) 75 | if err != nil { 76 | return "", err 77 | } 78 | defer resp.Body.Close() 79 | 80 | _, err = io.Copy(out, resp.Body) 81 | if err != nil { 82 | return "", err 83 | } 84 | 85 | return fullPath, nil 86 | } 87 | 88 | //GetDir desc 89 | func GetDir() (string, error) { 90 | usr, err := user.Current() 91 | if err != nil { 92 | return "", err 93 | } 94 | 95 | return filepath.Join(usr.HomeDir, ".dmut"), nil 96 | } 97 | 98 | //GetTotalMemory desc 99 | func GetTotalMemory()int{ 100 | vmStat, err := mem.VirtualMemory() 101 | if(err == nil){ 102 | return int(vmStat.Total/(1024*1024)) 103 | } 104 | 105 | return 0 106 | } -------------------------------------------------------------------------------- /words.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 10 3 | 11 4 | 12 5 | 13 6 | 14 7 | 15 8 | 16 9 | 17 10 | 18 11 | 19 12 | 2 13 | 20 14 | 2009 15 | 2010 16 | 2011 17 | 2012 18 | 2013 19 | 2014 20 | 2015 21 | 2016 22 | 2017 23 | 2018 24 | 2019 25 | 2020 26 | 2021 27 | 2022 28 | 2023 29 | 3 30 | 4 31 | 5 32 | 6 33 | 7 34 | 8 35 | 9 36 | a 37 | acc 38 | accept 39 | accounts 40 | infra 41 | d 42 | adm 43 | admin 44 | admin1 45 | administrator 46 | akali 47 | akamai 48 | alpha 49 | alt 50 | america 51 | analytics 52 | api 53 | api1 54 | apis 55 | api-docs 56 | apollo 57 | april 58 | aws 59 | b 60 | backend 61 | beta 62 | billing 63 | boards 64 | box 65 | brand 66 | bucket 67 | bucky 68 | c 69 | cdn 70 | cf 71 | chef 72 | ci 73 | client 74 | cloudfront 75 | cms 76 | cms1 77 | cn 78 | com 79 | config 80 | conf 81 | confluence 82 | container 83 | control 84 | data 85 | dec 86 | demo 87 | dev 88 | dev1 89 | developer 90 | devel 91 | test1 92 | test2 93 | q 94 | v 95 | auth 96 | repo 97 | edge 98 | qq 99 | dd 100 | development 101 | testing 102 | integration 103 | inter 104 | design 105 | designs 106 | des 107 | ads 108 | quiz 109 | prod 110 | production 111 | produ 112 | sap 113 | devops 114 | docker 115 | docs 116 | drop 117 | elasticbeanstalk 118 | elb 119 | email 120 | mail 121 | eng 122 | engima 123 | engine 124 | plugins 125 | engineering 126 | eu 127 | europe 128 | euw 129 | euwe 130 | events 131 | feb 132 | fet 133 | firewall 134 | forms 135 | forum 136 | frontpage 137 | fw 138 | games 139 | gh 140 | ghcpi 141 | git 142 | github 143 | gitlab 144 | global 145 | hkg 146 | hw 147 | hwcdn 148 | i 149 | ids 150 | int 151 | internal 152 | jenkins 153 | jinx 154 | july 155 | june 156 | lan 157 | las 158 | lax 159 | lax1 160 | lb 161 | loadbalancer 162 | login 163 | machine 164 | mail 165 | march 166 | merch 167 | mirror 168 | na 169 | nautilus 170 | net 171 | nginx 172 | apache 173 | nl 174 | node 175 | nov 176 | oct 177 | ops 178 | org 179 | origin 180 | page 181 | pantheon 182 | pass 183 | pay 184 | payment 185 | pc 186 | php 187 | pl 188 | preferences 189 | priv 190 | private 191 | profile 192 | profiles 193 | promo 194 | promotion 195 | proxy 196 | redirector 197 | redir 198 | region 199 | repository 200 | repo 201 | reset 202 | restrict 203 | restricted 204 | reviews 205 | s 206 | s3 207 | sandbox 208 | search 209 | secure 210 | security 211 | sept 212 | server 213 | service 214 | singed 215 | skins 216 | spring 217 | ssl 218 | staff 219 | stage 220 | stage1 221 | staging 222 | static 223 | support 224 | swagger 225 | system 226 | tool 227 | tools 228 | addons 229 | addon 230 | preprod 231 | op 232 | t 233 | train 234 | training 235 | team 236 | test 237 | testbed 238 | testing1 239 | tomcat 240 | tpe 241 | tr 242 | trial 243 | twitch 244 | uat 245 | v1 246 | v2 247 | vi 248 | vpn 249 | w3 250 | web 251 | web1 252 | webapp 253 | app 254 | z 255 | --------------------------------------------------------------------------------