├── .gitignore ├── LICENSE ├── README.md ├── auxiliars ├── arguments.py ├── banner.py ├── blockchain.py ├── constants.py ├── generator.py ├── normalization.py ├── screen.py ├── tlds.json ├── update.py └── worker.py ├── files ├── json_file.py └── txt_file.py ├── mutations ├── adictions.py ├── change_tld.py ├── countries.py ├── distance.py ├── integration.py ├── keyboard.py ├── repetition.py ├── replace.py ├── subdomains.py └── subtraction.py ├── querys ├── bdns.py ├── doh.py └── udp.py ├── requirements.txt ├── test ├── test_auxiliars.py ├── test_mutations.py └── test_querys.py └── typodetect.py /.gitignore: -------------------------------------------------------------------------------- 1 | **.DS_Store 2 | reports/* 3 | **/__pycache__/ 4 | nosetest.xml 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 private 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 | # TypoDetect 2 | 3 | This tool gives blue teams, SOC's, researchers and companies 4 | the ability to detect the active mutations of their domains, 5 | thus preventing the use of these domains in fraudulent 6 | activities, such as phishing and smishing. 7 | 8 | For this, Typodetect allows the use of the latest available 9 | version of the TLDs (Top Level Domains) published on the 10 | IANA website, the validation of decentralized domains in 11 | Blockchain DNS and the malware reports in DoH services 12 | (DNS over HTTPS) . 13 | 14 | For the ease of the user, Typodetect delivers the report 15 | in JSON format by default, or in TXT format, depending on 16 | how the user selects and shows on the screen a summary of 17 | the mutations generated, the active domains and the reports 18 | detected with Malware or decentralized domains. 19 | 20 | --- 21 | 22 | ## Installation 23 | 24 | Clone this repository with: 25 | ```bash 26 | git clone https://github.com/Telefonica/typodetect 27 | ``` 28 | 29 | Run setup for installation: 30 | 31 | ```bash 32 | python3 pip install -r requirements.txt 33 | ``` 34 | 35 | ### Running TypoDetect 36 | 37 | Inside the TypoDetect directory: 38 | 39 | ```bash 40 | python3 typodetect.py -h 41 | ``` 42 | 43 | ```bash 44 | usage: typodetect.py [-h] [-u UPDATE] [-t N_THREADS] [-d DOH_SERVER] [-o OUTPUT] domain 45 | 46 | positional arguments: 47 | domain specify domain to process 48 | 49 | optional arguments: 50 | -h, --help show this help message and exit 51 | -u UPDATE, --update UPDATE 52 | (Y/N) for update TLD's database (default:N) 53 | -t N_THREADS, --threads N_THREADS 54 | Number of threads for processing (default:5) 55 | -d DOH_SERVER, --doh DOH_SERVER 56 | Section DoH for use: [1] ElevenPaths (default) [2] Cloudfare 57 | -o OUTPUT, --output OUTPUT 58 | JSON or TXT, options of filetype (default:JSON) 59 | ``` 60 | 61 | For a simple analysis: 62 | 63 | ```bash 64 | python3 typodetect.py 65 | ``` 66 | 67 | For update IANA database and analysis: 68 | 69 | ```bash 70 | python3 typodetect.py -u y 71 | ``` 72 | 73 | For more threads analysis: 74 | 75 | ```bash 76 | python3 typodetect.py -t 77 | ``` 78 | 79 | For a different DoH (currently only has ElevenPaths o CloudFare) 80 | 81 | ```bash 82 | python3 typodetect.py -d 2 83 | ``` 84 | 85 | For create TXT report 86 | 87 | ```bash 88 | python3 typodetect.py -o TXT 89 | ``` 90 | 91 | ### Reports 92 | 93 | Inside the reports directory, the report file is saved, 94 | by default in JSON, with the name of the analyzed 95 | domain and the date, for example: 96 | 97 | ```bash 98 | elevenpaths.com2021-01-26T18:20:10.34568.json 99 | ``` 100 | 101 | The JSON report has the following structure for each active mutation detected: 102 | 103 | ```bash 104 | { id: 105 | "report_DoH" : 106 | "domain": 107 | "A": [ip1, ip2, ...] 108 | "MX": [mx1, mx2, ...] 109 | } 110 | ``` 111 | 112 | The fields contain the following information: 113 | 114 | ```bash 115 | id: Integer id of mutation 116 | "report_DoH": "" - Domain of Descentralised DNS 117 | "Malware" - Domain reported as dangerous for DoH 118 | "Good" - Domain reported as good for DoH 119 | "domain": Mutation detected as active. 120 | "A": IP's address of A type in DNS of the mutation. 121 | "MX": IP's or CNAME of MX type in DNS of the mutation. 122 | ``` 123 | 124 | -------------------------------------------------------------------------------- /auxiliars/arguments.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ argumentos para procesar""" 4 | 5 | import argparse 6 | 7 | 8 | def arguments(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('-u', 11 | "--update", 12 | dest='update', 13 | type=str, 14 | help='(Y/N) for update TLD\'s database (default:N)', 15 | default='N') 16 | parser.add_argument('-t', 17 | "--threads", 18 | dest='n_threads', 19 | type=int, 20 | help='Number of threads for processing (default:5)', 21 | default=5) 22 | parser.add_argument('-d', 23 | "--doh", 24 | dest='doh_server', 25 | type=int, 26 | help='Section DoH for use:\n' 27 | '\t[1] ElevenPaths (default)\n' 28 | '\t[2] Cloudfare', 29 | default=1) 30 | parser.add_argument('-o', 31 | "--output", 32 | dest='output', 33 | type=str, 34 | help='JSON or TXT, options of filetype (default:JSON)', 35 | default='JSON') 36 | parser.add_argument("domain", 37 | type=str, 38 | help='specify domain to process') 39 | args = parser.parse_args() 40 | if args.domain is None: 41 | print(parser.print_usage) 42 | exit(0) 43 | else: 44 | return [args.domain, args.update, args.output, 45 | args.n_threads, args.doh_server] 46 | -------------------------------------------------------------------------------- /auxiliars/banner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | 6 | from colorama import Fore 7 | from colorama import Style 8 | from querys.udp import dns_udp 9 | from auxiliars.constants import b 10 | from auxiliars.constants import tlds_json 11 | from auxiliars.constants import separator 12 | 13 | 14 | def banner(domain): 15 | with open(tlds_json) as file: 16 | options = json.load(file) 17 | 18 | print(Fore.GREEN + Style.BRIGHT + b) 19 | print(Fore.GREEN + Style.BRIGHT + separator) 20 | print(Fore.RED + Style.BRIGHT + 21 | '[*]\tIANA Database updated: ' + options['updated'].rsplit(',')[-1]) 22 | 23 | origin = dns_udp(domain, 0) 24 | if origin != {}: 25 | print(Fore.BLUE + Style.BRIGHT + '[*] Inicial Domain: ' 26 | + origin[0]['domain']) 27 | for a_ip in origin[0]['A']: 28 | print(Fore.BLUE + Style.BRIGHT + 29 | '\t[*] Register type A: ' + a_ip) 30 | for mx_ip in origin[0]['MX']: 31 | if mx_ip != '': 32 | print(Fore.BLUE + Style.BRIGHT + 33 | '\t[*] Register type MX: ' + mx_ip) 34 | 35 | print(Fore.GREEN + Style.BRIGHT + separator) 36 | print('\n\n') 37 | else: 38 | print(Fore.BLUE + Style.BRIGHT + '[*] Dominio ' + domain 39 | + ' does not exist') 40 | 41 | -------------------------------------------------------------------------------- /auxiliars/blockchain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | 6 | from auxiliars.constants import tlds_json 7 | 8 | 9 | def blockchain(possibilities): 10 | with open(tlds_json) as file: 11 | options = json.load(file) 12 | 13 | bases = [] 14 | 15 | for possibility in possibilities: 16 | if possibility.count('.') == 1: 17 | bases.append(possibility.split('.', 1)[0]) 18 | else: 19 | for key in options['tld']: 20 | if possibility.rsplit('.', 2)[-1] in options['tld'][key]: 21 | bases.append(possibility.rsplit('.', 2)[0] 22 | + '.' + possibility.rsplit('.', 2)[1]) 23 | break 24 | elif possibility.rsplit('.', 2)[-2] in options['tld'][key]: 25 | bases.append(possibility.rsplit('.', 2)[0]) 26 | break 27 | elif key == 'updated': 28 | bases.append(possibility.rsplit('.', 2)[0] 29 | + '.' + possibility.rsplit('.', 2)[1]) 30 | 31 | bases = sorted(list(set(bases))) 32 | bdomains = [] 33 | 34 | for base in bases: 35 | for coin in options['coins']: 36 | bdomains.append(base + '.' + coin) 37 | 38 | return bdomains 39 | -------------------------------------------------------------------------------- /auxiliars/constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """Constantes generales del sistema""" 5 | 6 | import os 7 | 8 | # Directories 9 | tlds_json = os.path.dirname(os.path.abspath(__file__)) \ 10 | + os.sep + 'tlds.json' 11 | 12 | result_txt = os.path.dirname(os.path.abspath(__file__))\ 13 | + os.sep + 'result.txt' 14 | 15 | reports = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\ 16 | + os.sep + 'reports' + os.sep 17 | 18 | # Generic 19 | separator = "[*] {0} [*]".format('-' * 100) 20 | ct = "application/dns-message" 21 | dnssec = { 22 | 'elevenpaths': { 23 | 'url': 'https://doh-beta.e-paths.com/dns-query', 24 | 'malware_ip': '18.194.105.161'}, 25 | 'couldfare': { 26 | 'server': '1.1.1.3', 27 | 'malware_ip': '184.168.221.61'}} 28 | 29 | 30 | # URLs 31 | url_update = 'https://data.iana.org/TLD/tlds-alpha-by-domain.txt' 32 | url_bdns = 'https://bdns.io/r/' 33 | 34 | 35 | b = """ 36 | 37 | ___________ ________ __ __ 38 | \__ ___/__.__.______ ____\______ \ _____/ |_ ____ _____/ |_ 39 | | | < | |\____ \ / _ \| | \_/ __ \ __\/ __ \_/ ___\ __| 40 | | | \___ || |_> > <_> ) ` \ ___/| | \ ___/\ \___| | 41 | |____| / ____|| __/ \____/_______ /\___ >__| \___ >\___ >__| 42 | \/ |__| \/ \/ \/ \/ 43 | 44 | Typosquatting Detect and Analyze 45 | By ElevenPaths https://www.elevenpaths.com/ 46 | Usage: python3 ./typodetect.py 47 | 48 | """ 49 | 50 | warning = """ 51 | [*] The creation and testing process of any mutation is very slow. 52 | [*] You can go to drink a coffee or take a nap. 53 | """ 54 | 55 | -------------------------------------------------------------------------------- /auxiliars/generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Generador de mutaciones""" 4 | 5 | from mutations.replace import replace 6 | from mutations.distance import distance_levenshtein 7 | from mutations.keyboard import keyboard 8 | from mutations.countries import countries 9 | from auxiliars.blockchain import blockchain 10 | from mutations.subdomains import subdomains 11 | from mutations.change_tld import change_tld 12 | from mutations.repetition import repetition 13 | from mutations.subtraction import subtraction 14 | from mutations.integration import integration 15 | 16 | 17 | def generator(parts): 18 | possibilities = [] 19 | subposs = [] 20 | if parts['tld_2'] == '': 21 | fqdn = parts['domain'] + '.' + parts['tld'] 22 | base = parts['domain'] 23 | tlds = parts['tld'] 24 | else: 25 | fqdn = parts['domain'] + '.' + parts['tld'] + '.' + parts['tld_2'] 26 | base = parts['domain'] 27 | tlds = parts['tld'] + '.' + parts['tld_2'] 28 | 29 | possibilities = countries(fqdn, possibilities) 30 | possibilities = integration(fqdn, possibilities) 31 | possibilities = subdomains(base, tlds, possibilities) 32 | possibilities = change_tld(base, possibilities) 33 | possibilities = subtraction(base, tlds, possibilities) 34 | possibilities = repetition(base, tlds, possibilities) 35 | possibilities = keyboard(base, tlds, possibilities) 36 | possibilities = replace(base, tlds, possibilities) 37 | possibilities = distance_levenshtein(base, tlds, possibilities) 38 | 39 | deletes = [] 40 | for domain in possibilities: 41 | if domain[0] == '.' or domain[0] == '-': 42 | deletes.append(domain) 43 | for delete in deletes: 44 | possibilities.remove(delete) 45 | 46 | possibilities = sorted(list(set(possibilities))) 47 | 48 | if parts['subdomain'] != '': 49 | for poss in possibilities: 50 | subposs.append(parts['subdomain'] + '.' + poss) 51 | possibilities += subposs 52 | 53 | possibilities = possibilities + blockchain(possibilities) 54 | 55 | possibilities = sorted(list(set(possibilities))) 56 | 57 | return possibilities 58 | -------------------------------------------------------------------------------- /auxiliars/normalization.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Normalizacion de dominios""" 4 | 5 | import tld 6 | import json 7 | 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def normalization(domain): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | normalized = options['normalized'] 15 | 16 | domain_tld = tld.get_tld(domain, fail_silently=True, 17 | fix_protocol=True, as_object=True) 18 | if domain_tld is None: 19 | return normalized 20 | tlds = domain_tld.fld.split('.') 21 | tlds = tlds[-2:] 22 | 23 | for sections in list(options['tld'].keys()): 24 | if tlds[0] in options['tld'][sections]: 25 | new_tld = True 26 | break 27 | else: 28 | new_tld = False 29 | 30 | if (new_tld is False) and (tlds[0] not in ( 31 | options['tld']['inicial'] or options['tld']['countries'])): 32 | normalized['tld'] = domain_tld.tld 33 | normalized['tld_2'] = '' 34 | normalized['domain'] = domain_tld.domain 35 | normalized['subdomain'] = domain_tld.subdomain 36 | elif new_tld and (domain_tld.domain == tlds[0]) and \ 37 | (domain_tld.subdomain == ''): 38 | normalized['tld'] = tlds[1] 39 | normalized['tld_2'] = '' 40 | normalized['domain'] = domain_tld.domain 41 | normalized['subdomain'] = domain_tld.subdomain 42 | elif new_tld and (domain_tld.domain == tlds[0]) and \ 43 | (domain_tld.subdomain != '') and \ 44 | ((tlds[1] in options['tld']['inicial']) or ( 45 | tlds[1] in options['tld']['countries'])): 46 | normalized['tld'] = tlds[0] 47 | normalized['tld_2'] = tlds[1] 48 | if domain_tld.subdomain.find('.') != -1: 49 | extras = domain_tld.subdomain.rsplit('.', 1) 50 | normalized['domain'] = extras[1] 51 | normalized['subdomain'] = extras[0] 52 | else: 53 | normalized['domain'] = domain_tld.subdomain 54 | normalized['subdomain'] = '' 55 | elif new_tld and (tlds[0] in ( 56 | options['tld']['inicial'] or options['tld']['countries'])) \ 57 | and tlds[1] != '': 58 | normalized['tld'] = tlds[0] 59 | normalized['tld_2'] = tlds[1] 60 | normalized['domain'] = domain_tld.domain 61 | normalized['subdomain'] = domain_tld.subdomain 62 | else: 63 | return normalized 64 | 65 | return normalized 66 | -------------------------------------------------------------------------------- /auxiliars/screen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from colorama import Fore 7 | from colorama import Style 8 | from auxiliars.banner import banner 9 | from auxiliars.constants import separator 10 | 11 | 12 | def screen_print(origin, mutations, result, doh): 13 | os.system('cls' if os.name == 'nt' else 'clear') 14 | banner(origin) 15 | doh_server = '' 16 | if doh == 1: 17 | doh_server = 'ElevenPaths' 18 | elif doh == 2: 19 | doh_server = 'Cloudfare' 20 | print(Fore.GREEN + Style.BRIGHT + separator) 21 | print(Fore.GREEN + Style.BRIGHT + '[*] We detected ' + str(mutations) + 22 | ' possibles domains mutations of ' + origin) 23 | print(Fore.GREEN + Style.BRIGHT + '[*] Of which ' 24 | + str(len(list(result.keys()))) + 25 | ' domains resolved to an A or MX record for ' + doh_server) 26 | print(Fore.GREEN + Style.BRIGHT + separator) 27 | print('') 28 | malware = 0 29 | 30 | for threat in list(result.keys()): 31 | if result[threat]['report_DoH'] == 'Malware': 32 | print(Fore.RED + Style.NORMAL + '\t[*] Detected domain: ' 33 | + result[threat]['domain']) 34 | print(Fore.RED + Style.NORMAL + 35 | '\t\t[*] DNS over HTTPS of ElevenPaths' 36 | ' report this domain is Malware') 37 | print(Fore.RED + Style.NORMAL + separator) 38 | malware = 1 39 | elif result[threat]['report_DoH'] == '': 40 | print(Fore.YELLOW + Style.NORMAL + '\t[*] Detected domain: ' 41 | + result[threat]['domain']) 42 | for a_ip in result[threat]['A']: 43 | print(Fore.YELLOW + Style.NORMAL + 44 | '\t\t[*] Register type A: ' + a_ip) 45 | print(Fore.YELLOW + Style.NORMAL + separator) 46 | 47 | if malware == 0: 48 | print(Fore.CYAN + Style.NORMAL + separator) 49 | print(Fore.CYAN + Style.NORMAL + '[*] No mutation of the domain ' 50 | + origin + ' reported as malware was detected in ' + 51 | doh_server + '\'s DNS') 52 | print(Fore.CYAN + Style.NORMAL + separator) 53 | 54 | print(Fore.CYAN + Style.NORMAL + separator) 55 | print(Fore.CYAN + Style.NORMAL + '[*] If the report is in ' + Fore.RED 56 | + Style.BRIGHT + 'red' + Fore.CYAN + Style.NORMAL + 57 | ', it is a domain marked as malware in the DoH') 58 | print(Fore.CYAN + Style.NORMAL + '[*] If the report is in ' + Fore.YELLOW 59 | + Style.BRIGHT + 'yellow' + Fore.CYAN + Style.NORMAL + 60 | ', it is a domain detected in the Blockchain DNS') 61 | print(Fore.CYAN + Style.NORMAL + separator) 62 | -------------------------------------------------------------------------------- /auxiliars/tlds.json: -------------------------------------------------------------------------------- 1 | {"tld": { 2 | "inicial": ["com", "org", "net", "int", "edu", "gov", "mil", "arpa"], 3 | "countries": ["ac", "ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", 4 | "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", 5 | "bg", "bh", "bi", "bj", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bw", 6 | "by", "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", 7 | "cn", "co", "cr", "cu", "cv", "cw", "cx", "cy", "cz", "de", "dj", "dk", 8 | "dm", "do", "dz", "ec", "ee", "eg", "er", "es", "et", "eu", "fi", "fj", 9 | "fk", "fm", "fo", "fr", "ga", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", 10 | "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jp", 11 | "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", 12 | "ly", "ma", "mc", "md", "me", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", 13 | "my", "mz", "na", "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", 14 | "pl", "pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", 15 | "si", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "su", "sv", "sx", "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", 16 | "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", 17 | "vu", "wf", "ws", "ye", "yt", "za", "zm", "zw"], 18 | "International": ["xn--lgbbat1ad8j", "xn--y9a3aq", "xn--mgbcpq6gpa1a", 19 | "xn--54b7fta0cc", "xn--90ais", "xn--90ae", "xn--fiqs8s", "xn--fiqz9s", "xn--wgbh1c", "xn--e1a4c", "xn--qxa6a", "xn--node", 20 | "xn--qxam", "xn--j6w193g", "xn--h2brj9c", "xn--mgbbh1a71e", "xn--fpcrj9c3d", "xn--gecrj9c", "xn--s9brj9c", "xn--xkc2dl3a5ee0h", 21 | "xn--45brj9c", "xn--2scrj9c", "xn--rvc1e0am3e", "xn--45br5cyl", "xn--3hcrj9c", "xn--mgbbh1a", "xn--h2breg3eve", 22 | "xn--h2brj9c8c", "xn--mgbgu82a", "xn--mgba3a4f16a", "xn--mgbtx2b", "xn--mgbayh7gpa", "xn--80ao21a", "xn--q7ce6a", 23 | "xn--mix082f", "xn--mix891f", "xn--mgbx4cd0ab", "xn--mgbah1a3hjkrd", "xn--l1acc", "xn--mgbc0a9azcg", "xn--d1alf", 24 | "xn--mgb9awbf", "xn--mgbai9azgqp6j", "xn--ygbi2ammx", "xn--wgbl6a", "xn--p1ai", "xn--mgberp4a5d4ar", "xn--90a3ac", 25 | "xn--yfro4i67o", "xn--clchc0ea0b2g2a9gcd", "xn--3e0b707e", "xn--fzc2c9e2c", "xn--xkc2al3hye2a", "xn--mgbpl2fh", "xn--ogbpf8fl", 26 | "xn--kprw13d", "xn--kpry57d", "xn--o3cw4h", "xn--pgbs0dh", "xn--j1amh", "xn--mgbaam7a8h", "xn--mgb2ddes"], 27 | "english": ["academy", "accountant", "accountants", "active", "actor", "ads", "adult", "aero", "africa", "agency", 28 | "airforce", "amazon", "analytics", "apartments", "app", "apple", "archi", "army", "art", "associates", "attorney", 29 | "auction", "audible", "audio", "author", "auto", "autos", "aws", "baby", "band", "bank", "bar", "barefoot", "bargains", 30 | "baseball", "basketball", "beauty", "beer", "best", "bestbuy", "bet", "bible", "bid", "bike", "bingo", "bio", "biz", 31 | "black", "blackfriday", "blockbuster", "blog", "blue", "boo", "book", "boots", "bot", "boutique", "box", "broadway", 32 | "broker", "build", "builders", "business", "buy", "buzz", "cab", "cafe", "call", "cam", "camera", "camp", "cancerresearch", 33 | "capital", "car", "cards", "care", "career", "careers", "cars", "case", "cash", "casino", "catering", "catholic", "center", 34 | "cern", "ceo", "cfd", "channel", "chat", "cheap", "christmas", "church", "cipriani", "circle", "city", "claims", "cleaning", 35 | "click", "clinic", "clothing", "cloud", "club", "coach", "codes", "coffee", "college", "community", "company", "compare", 36 | "computer", "condos", "construction", "consulting", "contact", "contractors", "cooking", "cool", "coop", "country", 37 | "coupon", "coupons", "courses", "credit", "creditcard", "cruise", "cricket", "cruises", "dad", "dance", "data", "date", 38 | "dating", "day", "deal", "deals", "degree", "delivery", "democrat", "dental", "dentist", "design", "dev", "diamonds", "diet", 39 | "digital", "direct", "directory", "discount", "diy", "docs", "doctor", "dog", "domains", "dot", "download", "drive", 40 | "duck", "earth", "eat", "eco", "education", "email", "energy", "engineer", "engineering", "edeka", "enterprises", "equipment", 41 | "esq", "estate", "events", "exchange", "expert", "exposed", "express", "fail", "faith", "family", "fan", "fans", "farm", 42 | "fashion", "fast", "feedback", "film", "final", "finance", "financial", "fire", "fish", "fishing", "fit", "fitness", 43 | "flights", "florist", "flowers", "fly", "foo", "food", "foodnetwork", "football", "forsale", "forum", "foundation", "free", 44 | "frontdoor", "fun", "fund", "furniture", "futbol", "fyi", "gallery", "game", "games", "garden", "gay", "gdn", "gift", 45 | "gifts", "gives", "glass", "global", "gold", "golf", "google", "gop", "graphics", "green", "gripe", "grocery", "group", 46 | "guide", "guitars", "guru", "hair", "hangout", "health", "healthcare", "help", "here", "hiphop", "hiv", "hockey", 47 | "holdings", "holiday", "homegoods", "homes", "homesense", "horse", "hospital", "host", "hosting", "hot", "hotels", 48 | "house", "how", "ice", "icu", "industries", "info", "ing", "ink", "institute", "insurance", "insure", "international", 49 | "investments", "jewelry", "jobs", "joy", "kim", "kitchen", "land", "lat", "law", "lawyer", "lease", "legal", "lgbt", "life", 50 | "lifeinsurance", "lighting", "like", "limited", "limo", "link", "live", "living", "loan", "loans", "locker", "lol", "lotto", 51 | "love", "ltd", "luxury", "makeup", "management", "map", "market", "marketing", "markets", "mba", "med", "media", "meet", 52 | "meme", "memorial", "men", "menu", "mint", "mobi", "mobile", "mobily", "moe", "mom", "money", "monster", "mortgage", 53 | "motorcycles", "mov", "movie", "museum", "music", "name", "navy", "network", "new", "news", "ngo", "ninja", "now", "ntt", 54 | "observer", "off", "one", "ong", "onl", "online", "ooo", "open", "organic", "origins", "page", "partners", "parts", "party", 55 | "pay", "pet", "pharmacy", "phone", "photo", "photography", "photos", "physio", "pics", "pictures", "pid", "pin", "pink", 56 | "pizza", "place", "plumbing", "plus", "poker", "porn", "post", "press", "prime", "pro", "productions", "prof", "promo", 57 | "properties", "property", "protection", "pub", "qpon", "racing", "radio", "read", "realestate", "realtor", "realty", "recipes", 58 | "red", "rehab", "reit", "rent", "rentals", "repair", "report", "republican", "rest", "restaurant", "review", "reviews", "rich", 59 | "rip", "rocks", "rodeo", "room", "rugby", "run", "safe", "sale", "save", "sbi", "scholarships", "school", "science", "search", 60 | "secure", "security", "select", "services", "sex", "sexy", "shoes", "shop", "shopping", "show", "showtime", "silk", "singles", 61 | "site", "ski", "skin", "sky", "sling", "smile", "soccer", "social", "software", "solar", "solutions", "song", "space", "spot", 62 | "spreadbetting", "storage", "store", "stream", "studio", "study", "style", "sucks", "supplies", "supply", "support", "surf", 63 | "surgery", "systems", "talk", "tattoo", "tax", "taxi", "team", "tech", "technology", "tel", "tennis", "theater", "theatre", 64 | "tickets", "tips", "tires", "today", "tools", "top", "tours", "town", "toys", "trade", "trading", "training", "travel", 65 | "travelersinsurance", "trust", "tube", "tunes", "uconnect", "university", "vacations", "ventures", "vet", "video", "villas", 66 | "vip", "vision", "vodka", "vote", "voting", "voyage", "wang", "watch", "watches", "weather", "webcam", "website", "wed", 67 | "wedding", "whoswho", "wiki", "win", "wine", "winners", "work", "works", "world", "wow", "wtf", "xxx", "xyz", "yachts", 68 | "yoga", "you", "zero", "zone"], 69 | "Chinese": ["ren", "shouji", "tushu", "wanggou", "weibo", "xihuan", "xin"], 70 | "French": ["arte", "clinique", "luxe", "maison", "moi", "rsvp", "sarl"], 71 | "German": ["berlin", "epost", "gmbh", "haus", "immobilien", "jetzt", "kaufen", "kinder", "reise", "reisen", "schule", 72 | "versicherung"], 73 | "Hindi": ["desi", "See also Desi", "shiksha"], 74 | "Italian": ["casa", "immo", "moda", "voto"], 75 | "Portuguese": ["bom", "passagens"], 76 | "Spanish": ["abogado", "futbol", "gratis", "hoteles", "juegos", "ltda", "soy", "tienda", "uno", "viajes", "vuelos"], 77 | "Africa": ["africa", "capetown", "durban", "joburg"], 78 | "Asia": ["abudhabi", "arab", "asia", "doha", "dubai", "krd", "kyoto", "nagoya", "okinawa", "osaka", "ryukyu", "taipei", 79 | "tatar", "tokyo", "yokohama"], 80 | "Europe": ["alsace", "amsterdam", "bar", "bcn", "barcelona", "bayern", "berlin", 81 | "brussels", "budapest", "bzh", "cat", "cologne", "corsica", "cymru", "eus", "frl", "gal", "gent", "hamburg", 82 | "helsinki", "irish", "ist", "istanbul", "koeln", "london", "madrid", "moscow", "nrw", "paris", "ruhr", "saarland", "scot", 83 | "stockholm", "swiss", "tirol", "vlaanderen", "wales", "wien", "zuerich"], 84 | "North America": ["boston", "miami", "nyc", "quebec", "vegas"], 85 | "Oceania": ["kiwi", "melbourne", "sydney"], 86 | "South America": ["lat", "rio"], 87 | "updated": ["aaa", "aarp", "abarth", "abb", "abbott", "abbvie", "abc", "able", "accenture", "aco", "adac", "aeg", "aetna", 88 | "afamilycompany", "afl", "agakhan", "aig", "aigo", "airbus", "airtel", "akdn", "alfaromeo", "alibaba", "alipay", "allfinanz", 89 | "allstate", "ally", "alstom", "americanexpress", "americanfamily", "amex", "amfam", "amica", "android", "anquan", "anz", "aol", "aquarelle", "aramco", "asda", "athleta", "audi", "auspost", "avianca", "axa", "azure", "baidu", "banamex", "bananarepublic", "barclaycard", "barclays", "bauhaus", "bbc", "bbt", "bbva", "bcg", "beats", "bentley", "bharti", "bing", "bloomberg", "bms", "bmw", "bnpparibas", "boats", "boehringer", "bofa", "bond", "booking", "bosch", "bostik", "bradesco", "bridgestone", "brother", "bugatti", "bv", "cal", "calvinklein", "canon", "capitalone", "caravan", "caseih", "cba", "cbn", "cbre", "cbs", "ceb", "cfa", "chanel", "charity", "chase", "chintai", "chrome", "cisco", "citadel", "citi", "citic", "cityeats", "clubmed", "comcast", "commbank", "comsec", "cookingchannel", "cpa", "creditunion", "crown", "crs", "csc", "cuisinella", "cyou", "dabur", "datsun", "dclk", "dds", "dealer", "dell", "deloitte", "delta", "dhl", "discover", "dish", "dnp", "dtv", "dunlop", "dupont", "dvag", "dvr", "emerck", "epson", "ericsson", "erni", "esurance", "etisalat", "eurovision", "extraspace", "fage", "fairwinds", "farmers", "fedex", "ferrari", "ferrero", "fiat", "fidelity", "fido", "firestone", "firmdale", "flickr", "flir", "ford", "forex", "fox", "fresenius", "frogans", "frontier", "ftr", "fujitsu", "fujixerox", "gallo", "gallup", "gap", "gb", "gbiz", "gea", "genting", "george", "ggee", "giving", "glade", "gle", "globo", "gmail", "gmo", "gmx", "godaddy", "goldpoint", "goo", "goodyear", "goog", "got", "grainger", "guardian", "gucci", "guge", "hbo", "hdfc", "hdfcbank", "hermes", "hgtv", "hisamitsu", "hitachi", "hkt", "homedepot", "honda", "hotmail", "hsbc", "hughes", "hyatt", "hyundai", "ibm", "icbc", "ieee", "ifm", "ikano", "imamat", "imdb", "inc", "infiniti", "intel", "intuit", "ipiranga", "ismaili", "itau", "itv", "iveco", "jaguar", "java", "jcb", "jcp", "jeep", "jio", "jll", "jmp", "jnj", "jot", "jpmorgan", "jprs", "juniper", "kddi", "kerryhotels", "kerrylogistics", "kerryproperties", "kfh", "kia", "kindle", "komatsu", "kosher", "kpmg", "kpn", "kred", "kuokgroup", "lacaixa", "lamborghini", "lamer", "lancaster", "lancia", "landrover", "lanxess", "lasalle", "latino", "latrobe", "lds", "leclerc", "lefrak", "lego", "lexus", "lidl", "lifestyle", "lilly", "lincoln", "linde", "lipsy", "lixil", "llc", "llp", "locus", "loft", "lotte", "lpl", "lplfinancial", "lundbeck", "lupin", "macys", "maif", "man", "mango", "marriott", "marshalls", "maserati", "mattel", "mckinsey", "merckmsd", "metlife", "microsoft", "mini", "mit", "mitsubishi", "mlb", "mls", "mma", "monash", "mormon", "moto", "msd", "mtn", "mtr", "mutual", "nab", "nationwide", "natura", "nba", "nec", "netbank", "netflix", "neustar", "newholland", "next", "nextdirect", "nexus", "nfl", "nhk", "nico", "nike", "nikon", "nissan", "nissay", "nokia", "northwesternmutual", "norton", "nowruz", "nowtv", "nra", "obi", "office", "olayan", "olayangroup", "oldnavy", "ollo", "omega", "onyourside", "oracle", "orange", "otsuka", "ott", "ovh", "panasonic", "pars", "pccw", "pfizer", "phd", "philips", "pictet", "ping", "pioneer", "play", "playstation", "pnc", "pohl", "politie", "pramerica", "praxi", "prod", "progressive", "pru", "prudential", "pwc", "quest", "qvc", "raid", "redstone", "redumbrella", "reliance", "rexroth", "richardli", "ricoh", "rightathome", "ril", "rmit", "rocher", "rogers", "rwe", "safety", "sakura", "salon", "samsclub", "samsung", "sandvik", "sandvikcoromant", "sanofi", "sap", "sas", "saxo", "sbs", "sca", "scb", "schaeffler", "schmidt", "schwarz", "scjohnson", "scor", "seat", "seek", "sener", "ses", "seven", "sew", "sfr", "shangrila", "sharp", "shaw", "shell", "shia", "shriram", "sina", "sj", "skype", "smart", "sncf", "softbank", "sohu", "sony", "sport", "srl", "stada", "staples", "star", "statebank", "statefarm", "stc", "stcgroup", "suzuki", "swatch", "swiftcover", "symantec", "tab", "taobao", "target", "tatamotors", "tci", "tdk", "temasek", "teva", "thd", "tiaa", "tiffany", "tjmaxx", "tjx", "tkmaxx", "tmall", "toray", "toshiba", "total", "toyota", "travelchannel", "travelers", "trv", "tui", "tvs", "ubank", "ubs", "unicom", "uol", "ups", "vana", "vanguard", "verisign", "vig", "viking", "vin", "virgin", "visa", "viva", "vivo", "volkswagen", "volvo", "walmart", "walter", "weatherchannel", "weber", "weir", "williamhill", "windows", "wme", "wolterskluwer", "woodside", "wtc", "xbox", "xerox", "xfinity", "xn--11b4c3d", "xn--1ck2e1b", "xn--1qqw23a", "xn--30rr7y", "xn--3bst00m", "xn--3ds443g", "xn--3oq18vl8pn36a", "xn--3pxu8k", "xn--42c2d9a", "xn--45q11c", "xn--4gbrim", "xn--55qw42g", "xn--55qx5d", "xn--5su34j936bgsg", "xn--5tzm5g", "xn--6frz82g", "xn--6qq986b3xl", "xn--80adxhks", "xn--80aqecdr1a", "xn--80asehdb", "xn--80aswg", "xn--8y0a063a", "xn--9dbq2a", "xn--9et52u", "xn--9krt00a", "xn--b4w605ferd", "xn--bck1b9a5dre4c", "xn--c1avg", "xn--c2br7g", "xn--cck2b3b", "xn--cg4bki", "xn--czr694b", "xn--czrs0t", "xn--czru2d", "xn--d1acj3b", "xn--eckvdtc9d", "xn--efvy88h", "xn--fct429k", "xn--fhbei", "xn--fiq228c5hs", "xn--fiq64b", "xn--fjq720a", "xn--flw351e", "xn--fzys8d69uvgm", "xn--g2xx48c", "xn--gckr3f0f", "xn--gk3at1e", "xn--hxt814e", "xn--i1b6b1a6a2e", "xn--imr513n", "xn--io0a7i", "xn--j1aef", "xn--jlq61u9w7b", "xn--jvr189m", "xn--kcrx77d1x4a", "xn--kpu716f", "xn--kput3i", "xn--mgba3a3ejt", "xn--mgba7c0bbn0a", "xn--mgbaakc7dvf", "xn--mgbab2bd", "xn--mgbca7dzdo", "xn--mgbi4ecexp", "xn--mgbt3dhd", "xn--mk1bu44c", "xn--mxtq1m", "xn--ngbc5azd", "xn--ngbe9e0a", "xn--ngbrx", "xn--nqv7f", "xn--nqv7fs00ema", "xn--nyqy26a", "xn--otu796d", "xn--p1acf", "xn--pbt977c", "xn--pssy2u", "xn--q9jyb4c", "xn--qcka1pmc", "xn--rhqv96g", "xn--rovu88b", "xn--ses554g", "xn--t60b56a", "xn--tckwe", "xn--tiq49xqyj", "xn--unup4y", "xn--vermgensberater-ctb", "xn--vermgensberatung-pwb", "xn--vhquv", "xn--vuq861b", "xn--w4r85el8fhu5dnra", "xn--w4rs40l", "xn--xhq521b", "xn--zfr164b", "yahoo", "yamaxun", "yandex", "yodobashi", "youtube", "yun", "zappos", "zara", "zip", "xn--cckwcxetd", "xn--jlq480n2rg", "spa", "xn--4dbrk0ce"]}, 90 | "keyboards": { 91 | "qwerty": {"1": "2q", "2": "3wq1", "3": "4ew2", "4": "5re3", "5": "6tr4", "6": "7yt5", "7": "8uy6", "8": "9iu7", "9": "0oi8", 92 | "0": "po9", "q": "12wa", "w": "3esaq2", "e": "4rdsw3", "r": "5tfde4", "t": "6ygfr5", "y": "7uhgt6", "u": "8ijhy7", 93 | "i": "9okju8", "o": "0plki9", "p": "lo0", "a": "qwsz", "s": "edxzaw", "d": "rfcxse", "f": "tgvcdr", "g": "yhbvft", 94 | "h": "ujnbgy", "j": "ikmnhu", "k": "olmji", "l": "kop", "z": "asx", "x": "zsdc", "c": "xdfv", "v": "cfgb", "b": "vghn", 95 | "n": "bhjm", "m": "njk"}, 96 | "qwertz": {"1": "2q", "2": "3wq1", "3": "4ew2", "4": "5re3", "5": "6tr4", "6": "7zt5", "7": "8uz6", "8": "9iu7", 97 | "9": "0oi8", "0": "po9", "q": "12wa", "w": "3esaq2", "e": "4rdsw3", "r": "5tfde4", "t": "6zgfr5", "z": "7uhgt6", 98 | "u": "8ijhz7", "i": "9okju8", "o": "0plki9", "p": "lo0", "a": "qwsy", "s": "edxyaw", "d": "rfcxse", "f": "tgvcdr", 99 | "g": "zhbvft", "h": "ujnbgz", "j": "ikmnhu", "k": "olmji", "l": "kop", "y": "asx", "x": "ysdc", "c": "xdfv", "v": "cfgb", 100 | "b": "vghn", "n": "bhjm", "m": "njk"}, 101 | "azerty": {"1": "2a", "2": "3za1", "3": "4ez2", "4": "5re3", "5": "6tr4", "6": "7yt5", "7": "8uy6", "8": "9iu7", 102 | "9": "0oi8", "0": "po9", "a": "2zq1", "z": "3esqa2", "e": "4rdsz3", "r": "5tfde4", "t": "6ygfr5", "y": "7uhgt6", 103 | "u": "8ijhy7", "i": "9okju8", "o": "0plki9", "p": "lo0m", "q": "zswa", "s": "edxwqz", "d": "rfcxse", "f": "tgvcdr", 104 | "g": "yhbvft", "h": "ujnbgy", "j": "iknhu", "k": "olji", "l": "kopm", "m": "lp", "w": "sxq", "x": "wsdc", "c": "xdfv", 105 | "v": "cfgb", "b": "vghn", "n": "bhj"}}, 106 | "vowels": "aeiou", 107 | "replace": {"a": ["à", "á", "â", "ã", "ä", "å", "ɑ", "ạ", "ǎ", "ă", "ȧ", "ą", "4"], 108 | "b": ["d", "lb", "ʙ", "ɓ", "ḃ", "ḅ", "ḇ", "ƅ"], 109 | "c": ["e", "ƈ", "ċ", "ć", "ç", "č", "ĉ"], 110 | "d": ["b", "cl", "dl", "ɗ", "đ", "ď", "ɖ", "ḑ", "ḋ", "ḍ", "ḏ", "ḓ"], 111 | "e": ["c", "é", "è", "ê", "ë", "ē", "ĕ", "ě", "ė", "ẹ", "ę", "ȩ", "ɇ", "ḛ", "3"], 112 | "f": ["ƒ", "ḟ"], "g": ["q", "ɢ", "ɡ", "ġ", "ğ", "ǵ", "ģ", "ĝ", "ǧ", "ǥ", "6"], 113 | "h": ["lh", "ĥ", "ȟ", "ħ", "ɦ", "ḧ", "ḩ", "ⱨ", "ḣ", "ḥ", "ḫ", "ẖ"], 114 | "i": ["1", "l", "í", "ì", "ï", "ı", "ɩ", "ǐ", "ĭ", "ỉ", "ị", "ɨ", "ȋ", "ī"], 115 | "j": ["ʝ", "ɉ"], "k": ["lk", "ik", "lc", "ḳ", "ḵ", "ⱪ", "ķ"], 116 | "l": ["1", "i", "ɫ", "ł"], "m": ["n", "nn", "rn", "rr", "ṁ", "ṃ", "ᴍ", "ɱ", "ḿ"], 117 | "n": ["m", "r", "ń", "ṅ", "ṇ", "ṉ", "ñ", "ņ", "ǹ", "ň", "ꞑ"], 118 | "o": ["0", "ȯ", "ọ", "ỏ", "ơ", "ó", "ö"], "p": ["ƿ", "ƥ", "ṕ", "ṗ"], 119 | "q": ["g", "ʠ"], "r": ["ʀ", "ɼ", "ɽ", "ŕ", "ŗ", "ř", "ɍ", "ɾ", "ȓ", "ȑ", "ṙ", "ṛ", "ṟ"], 120 | "s": ["ʂ", "ś", "ṣ", "ṡ", "ș", "ŝ", "š"], "t": ["ţ", "ŧ", "ṫ", "ṭ", "ț", "ƫ"], 121 | "u": ["ᴜ", "ǔ", "ŭ", "ü", "ʉ", "ù", "ú", "û", "ũ", "ū", "ų", "ư", "ů", "ű", "ȕ", "ȗ", "ụ"], 122 | "v": ["ṿ", "ⱱ", "ᶌ", "ṽ", "ⱴ"], "w": ["vv", "ŵ", "ẁ", "ẃ", "ẅ", "ⱳ", "ẇ", "ẉ", "ẘ"], 123 | "x": [], "y": ["ʏ", "ý", "ÿ", "ŷ", "ƴ", "ȳ", "ɏ", "ỿ", "ẏ", "ỵ"], 124 | "z": ["ʐ", "ż", "ź", "ᴢ", "ƶ", "ẓ", "ẕ", "ⱬ"], 125 | "-": ["_"], "_": ["-"]}, 126 | "letters": "abcdefghijklmnopqrstuvwxyz", 127 | "coins": ["bit", "emc", "coin", "lib", "bazar", "bbs", "chan", "cyb", "dyn", "geek", "gopher", "indy", "libre", 128 | "neo", "null", "o", "oss", "oz", "parody", "pirate", "ku", "te", "ti", "uu"], 129 | "mutates": ["www-", "ww-", "www", "ww"], 130 | "normalized": {"domain": "", "tld": "", "tld_2": "", "subdomain": ""}, "update": "", "updated": "# Version 2021021100, Last Updated Thu Feb 11 07:07:01 2021 UTC"} -------------------------------------------------------------------------------- /auxiliars/update.py: -------------------------------------------------------------------------------- 1 | """Script para actualizar los TLD""" 2 | import json 3 | import urllib.request 4 | 5 | from colorama import Fore 6 | from colorama import Style 7 | from auxiliars.constants import tlds_json 8 | from auxiliars.constants import separator 9 | from auxiliars.constants import url_update 10 | 11 | 12 | def updating(): 13 | with open(tlds_json) as file: 14 | options = json.load(file) 15 | try: 16 | for new_tld in urllib.request.urlopen(url_update).readlines(): 17 | new_tld = new_tld.decode('utf-8').strip('\n') 18 | if new_tld == options["updated"]: 19 | print(Fore.GREEN + Style.BRIGHT + separator) 20 | print('[*] TLD DataBase is update') 21 | print(Fore.GREEN + Style.BRIGHT + separator) 22 | break 23 | elif 'Last Updated ' in new_tld: 24 | options['updated'] = new_tld 25 | else: 26 | i = 0 27 | for sections in list(options['tld'].keys()): 28 | if new_tld.lower() not in options['tld'][sections]: 29 | i += 1 30 | if i == len(list(options['tld'].keys())): 31 | options['tld']['updated'].append(new_tld.lower()) 32 | 33 | new_options = json.dumps(options, ensure_ascii=False) 34 | with open(tlds_json, 'w') as file: 35 | file.write(new_options) 36 | 37 | except: 38 | print(Fore.RED + Style.BRIGHT + '[*] Update TLDś DataBase failed.') 39 | 40 | -------------------------------------------------------------------------------- /auxiliars/worker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Process Threat""" 4 | 5 | import json 6 | import threading 7 | 8 | from atpbar import flush 9 | from atpbar import atpbar 10 | from querys.doh import dns_doh 11 | from querys.udp import dns_udp 12 | from querys.bdns import dns_bdns 13 | from auxiliars.constants import tlds_json 14 | 15 | 16 | def worker(possibilities, start, end, thread, result, doh_server): 17 | with open(tlds_json) as file: 18 | options = json.load(file) 19 | 20 | availables = [] 21 | name = 'thread {}'.format(thread) 22 | 23 | for threat in atpbar(range(start, end), name=name): 24 | if possibilities[threat].rsplit('.')[-1] in options['coins']: 25 | update = dns_bdns(possibilities[threat], threat) 26 | elif doh_server == 2: 27 | update = dns_udp(possibilities[threat], threat) 28 | else: 29 | update = dns_doh(possibilities[threat], threat) 30 | 31 | if update != {}: 32 | result.update(update) 33 | threat += 1 34 | else: 35 | availables.append(possibilities[threat]) 36 | 37 | return result 38 | 39 | 40 | def process(n_threads, possibilities, doh_server): 41 | sections = len(possibilities) // n_threads 42 | starts = [] 43 | ends = [] 44 | start = 0 45 | end = sections 46 | result = {} 47 | threads = [] 48 | 49 | for i in range(n_threads): 50 | starts.append(start) 51 | ends.append(end) 52 | start += sections 53 | end += sections 54 | 55 | for i in range(len(starts)): 56 | t = threading.Thread(target=worker, args=(possibilities, starts[i], 57 | ends[i], i, result, 58 | doh_server,)) 59 | threads.append(t) 60 | t.start() 61 | 62 | for t in threads: 63 | t.join() 64 | 65 | flush() 66 | 67 | return result 68 | -------------------------------------------------------------------------------- /files/json_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import json 6 | from datetime import datetime 7 | 8 | from auxiliars.constants import reports 9 | 10 | 11 | def files_json(result, domain): 12 | results_json = json.dumps(result, ensure_ascii=False) 13 | if not os.path.isdir(reports): 14 | os.makedirs(reports) 15 | 16 | with open(reports + domain + 17 | datetime.utcnow().isoformat() + '.json', 'w') as file: 18 | file.write(results_json) 19 | -------------------------------------------------------------------------------- /files/txt_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """Script for create txt file""" 4 | 5 | import os 6 | 7 | from querys.udp import dns_udp 8 | from auxiliars.constants import b 9 | from auxiliars.constants import reports 10 | from auxiliars.constants import separator 11 | 12 | 13 | def files_txt(result, domain, mutations): 14 | if not os.path.isdir(reports): 15 | os.makedirs(reports) 16 | 17 | with open(reports + domain + '.txt', 'w') as file: 18 | file.write(b) 19 | file.write('\n\n') 20 | file.write('[*] We detected ' + str(mutations) + 21 | ' possibles domains mutations of ' + domain + '\n') 22 | file.write('[*] Of which ' + str(len(list(result.keys()))) + 23 | ' domains resolved to an A or MX record' + '\n') 24 | file.write(separator + '\n\n') 25 | 26 | origin = dns_udp(domain, 0) 27 | if origin != {}: 28 | file.write('[*] Inicial Domain: ' + origin[0]['domain'] + '\n') 29 | for a_ip in origin[0]['A']: 30 | file.write('\t[*] Register type A: ' + a_ip + '\n') 31 | for mx_ip in origin[0]['MX']: 32 | if mx_ip != '': 33 | file.write('\t[*] Register type MX: ' + mx_ip + '\n') 34 | 35 | file.write(separator + '\n\n') 36 | 37 | for threat in list(result.keys()): 38 | file.write('[*] Detected domain: ' + 39 | result[threat]['domain'] + '\n') 40 | if result[threat]['report_DoH'] == 'Malware': 41 | file.write('\t[*] DNS over HTTPS of ElevenPaths report this' 42 | ' domain is Malware' + '\n') 43 | else: 44 | for a_ip in result[threat]['A']: 45 | file.write('\t[*] Register type A: ' + a_ip + '\n') 46 | for mx_ip in result[threat]['MX']: 47 | if mx_ip != '': 48 | file.write('\t[*] Register type MX: ' + mx_ip + '\n') 49 | file.write(separator + '\n') 50 | -------------------------------------------------------------------------------- /mutations/adictions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ reduce letters """ 4 | 5 | import json 6 | 7 | from auxiliars.constants import tlds_json 8 | 9 | 10 | def adictions(base, tlds, possibilities): 11 | with open(tlds_json) as file: 12 | options = json.load(file) 13 | 14 | for mut in options['mutates']: 15 | possibilities.append(mut + base + '.' + tlds) 16 | 17 | if tlds.find('.') == -1: 18 | possibilities.append(mut + base + '-' + tlds + '.' + tlds) 19 | for key in options['tld'].keys(): 20 | for tld in options['tld'][key]: 21 | possibilities.append(mut + base + '-' + tlds + '.' + tld) 22 | else: 23 | modtlds = tlds.replace('.', '-') 24 | possibilities.append(mut + base + '-' + modtlds + '.' + tlds) 25 | for key in options['tld'].keys(): 26 | for tld in options['tld'][key]: 27 | possibilities.append( 28 | mut + base + '-' + modtlds + '.' + tld) 29 | 30 | return possibilities 31 | -------------------------------------------------------------------------------- /mutations/change_tld.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Changing TLD""" 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def change_tld(base, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for tlds in atpbar(list(options['tld'].keys()), name="Change TLD: "): 16 | for change in options['tld'][tlds]: 17 | possibilities.append(base + '.' + change) 18 | if tlds == 'inicial': 19 | for tld2 in options['tld']['countries']: 20 | possibilities.append(base + '.' + change + '.' + tld2) 21 | 22 | return possibilities 23 | -------------------------------------------------------------------------------- /mutations/countries.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Mutations of countries """ 4 | 5 | import json 6 | 7 | from auxiliars.constants import tlds_json 8 | 9 | 10 | def countries(base, possibilities): 11 | with open(tlds_json) as file: 12 | options = json.load(file) 13 | 14 | part = base.rsplit('.', 1) 15 | 16 | if part[1] in options['tld']['countries']: 17 | for country in options['tld']['countries']: 18 | possibilities.append(part[0] + '.' + country) 19 | else: 20 | for country in options['tld']['countries']: 21 | possibilities.append(part[0] + '.' + part[1] + '.' + country) 22 | 23 | return possibilities 24 | -------------------------------------------------------------------------------- /mutations/distance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ mutations levenshtein's kind """ 4 | 5 | import json 6 | import Levenshtein 7 | 8 | from atpbar import atpbar 9 | from auxiliars.constants import tlds_json 10 | 11 | 12 | def distance_levenshtein(base, tlds, possibilities): 13 | with open(tlds_json) as file: 14 | options = json.load(file) 15 | 16 | for i in atpbar(range(0, len(base)), name='Create Levenshtein words: '): 17 | if base[i].isalpha(): 18 | for letter in options['letters']: 19 | if Levenshtein.distance(base, 20 | base[:i] + letter + base[i + 1:]) == 1: 21 | possibilities.append(base[:i] + letter + base[i + 1:] 22 | + "." + tlds) 23 | 24 | for letter in options['letters']: 25 | if Levenshtein.distance(base, base + letter) == 1: 26 | possibilities.append(base + letter + '.' + tlds) 27 | 28 | return possibilities 29 | -------------------------------------------------------------------------------- /mutations/integration.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ integration of domain and tld""" 4 | 5 | import json 6 | 7 | from auxiliars.constants import tlds_json 8 | 9 | 10 | def integration(base, possibilities): 11 | with open(tlds_json) as file: 12 | options = json.load(file) 13 | 14 | domain_int = base.replace('.', '') 15 | 16 | for tld in options['tld']['inicial']: 17 | possibilities.append(domain_int + '.' + tld) 18 | for tld2 in options['tld']['countries']: 19 | possibilities.append(domain_int + '.' + tld + '.' + tld2) 20 | 21 | return possibilities 22 | -------------------------------------------------------------------------------- /mutations/keyboard.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ typosquatting with differents keyboards """ 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def keyboard(base, tlds, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for i in atpbar(range(0, len(base)), name='Proximity of keyboard: '): 16 | for keys in options['keyboards']: 17 | if base[i] in options['keyboards'][keys]: 18 | for c in options['keyboards'][keys][base[i]]: 19 | possibilities.append( 20 | base[:i] + c + base[i] + base[i + 1:] + '.' + tlds) 21 | possibilities.append( 22 | base[:i] + base[i] + c + base[i + 1:] + '.' + tlds) 23 | possibilities.append( 24 | base[:i] + c + base[i + 1:] + '.' + tlds) 25 | for tld in options['tld']['inicial']: 26 | possibilities.append( 27 | base[:i] + c + base[i] + base[i + 1:] + '.' + tld) 28 | possibilities.append( 29 | base[:i] + base[i] + c + base[i + 1:] + '.' + tld) 30 | possibilities.append( 31 | base[:i] + c + base[i + 1:] + '.' + tld) 32 | 33 | for tld2 in options['tld']['countries']: 34 | possibilities.append( 35 | base[:i] + c + base[i] + 36 | base[i + 1:] + '.' + tld + '.' + tld2) 37 | possibilities.append( 38 | base[:i] + base[i] + c + 39 | base[i + 1:] + '.' + tld + '.' + tld2) 40 | possibilities.append( 41 | base[:i] + c + base[i + 1:] 42 | + '.' + tld + '.' + tld2) 43 | 44 | return possibilities 45 | -------------------------------------------------------------------------------- /mutations/repetition.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ repeating letters """ 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def repetition(base, tlds, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for i in atpbar(range(0, len(base)), name='Repetitions letters: '): 16 | possibilities.append(base[:i] + base[i] + base[i] 17 | + base[i + 1:] + '.' + tlds) 18 | 19 | for tld in options['tld']['inicial']: 20 | possibilities.append(base[:i] + base[i] 21 | + base[i] + base[i + 1:] + '.' + tld) 22 | for tld2 in options['tld']['countries']: 23 | possibilities.append(base[:i] + base[i] + base[i] 24 | + base[i + 1:] + '.' + tld + '.' + tld2) 25 | 26 | return possibilities 27 | -------------------------------------------------------------------------------- /mutations/replace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ replace letters """ 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def replace(base, tlds, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for i in atpbar(range(0, len(base)), name='Replace letters: '): 16 | if base[i].isalpha(): 17 | for change in options['replace'][base[i]]: 18 | possibilities.append( 19 | base[:i] + change + base[i + 1:] + '.' + tlds) 20 | 21 | for tld in options['tld']['inicial']: 22 | possibilities.append(base[:i] + change + 23 | base[i + 1:] + '.' + tld) 24 | for tld2 in options['tld']['countries']: 25 | possibilities.append(base[:i] + change + 26 | base[i + 1:] + '.' + tld 27 | + '.' + tld2) 28 | 29 | return possibilities 30 | -------------------------------------------------------------------------------- /mutations/subdomains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ creating subdomains""" 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def subdomains(base, tlds, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for i in atpbar(range(0, len(base)), name='Creating subdomains: '): 16 | new_sub = base[:i] + '.' + base[i:] 17 | new_div = base[:i] + '-' + base[i:] 18 | 19 | possibilities.append(new_sub + '.' + tlds) 20 | possibilities.append(new_sub + '.' + tlds) 21 | 22 | for tld in options['tld']['inicial']: 23 | possibilities.append(new_sub + '.' + tld) 24 | possibilities.append(new_div + '.' + tld) 25 | for tld2 in options['tld']['countries']: 26 | possibilities.append(new_sub + '.' + tld + '.' + tld2) 27 | possibilities.append(new_div + '.' + tld + '.' + tld2) 28 | 29 | return possibilities 30 | -------------------------------------------------------------------------------- /mutations/subtraction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Subtraction letters """ 4 | 5 | import json 6 | 7 | from atpbar import atpbar 8 | from auxiliars.constants import tlds_json 9 | 10 | 11 | def subtraction(base, tlds, possibilities): 12 | with open(tlds_json) as file: 13 | options = json.load(file) 14 | 15 | for i in atpbar(range(0, len(base)), name='Subtraction letters: '): 16 | possibilities.append(base[:i] + base[i + 1:] + '.' + tlds) 17 | 18 | for tld in options['tld']['inicial']: 19 | possibilities.append(base[:i] + base[i + 1:] + '.' + tld) 20 | for tld2 in options['tld']['countries']: 21 | possibilities.append(base[:i] + base[i + 1:] + '.' + 22 | tld + '.' + tld2) 23 | 24 | return possibilities 25 | -------------------------------------------------------------------------------- /querys/bdns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Validacion de dominios con Blockchain - DNS""" 4 | 5 | import urllib3 6 | import requests 7 | 8 | from auxiliars.constants import url_bdns 9 | 10 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 11 | 12 | 13 | def dns_bdns(domain, threat): 14 | detected = {} 15 | try: 16 | resp = requests.get(url_bdns + domain, verify=False) 17 | except requests.RequestException: 18 | return detected 19 | 20 | if resp.status_code == 200: 21 | detected[threat] = {} 22 | detected[threat]['report_DoH'] = '' 23 | detected[threat]['domain'] = domain 24 | detected[threat]['A'] = [resp.text] 25 | detected[threat]['MX'] = '' 26 | else: 27 | return detected 28 | 29 | return detected 30 | -------------------------------------------------------------------------------- /querys/doh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Validacion de dominios con DoH""" 4 | 5 | import base64 6 | import requests 7 | import dns.message as doh 8 | 9 | from auxiliars.constants import ct 10 | from auxiliars.constants import dnssec 11 | 12 | 13 | def dns_doh(domain, threat): 14 | detected = {} 15 | message = doh.make_query(domain, 'A') 16 | dns_req = base64.urlsafe_b64encode(message.to_wire()).\ 17 | decode("UTF8").rstrip("=") 18 | 19 | try: 20 | resp = requests.get( 21 | dnssec['elevenpaths']['url'], params={"dns": dns_req}, 22 | headers={"Content-type": ct}) 23 | except requests.RequestException: 24 | return detected 25 | 26 | if ct not in resp.headers["Content-Type"]: 27 | detected = {} 28 | return detected 29 | 30 | ips = [] 31 | answers = [] 32 | for response in doh.from_wire(resp.content).answer: 33 | answers = response.to_text().split("\n") 34 | 35 | for answer in answers: 36 | output = answer.split() 37 | ips.append(output[len(output) - 1]) 38 | 39 | if dnssec['elevenpaths']['malware_ip'] in ips: 40 | detected[threat] = {} 41 | detected[threat]['report_DoH'] = 'Malware' 42 | detected[threat]['domain'] = domain 43 | detected[threat]['A'] = '' 44 | detected[threat]['MX'] = '' 45 | elif not ips: 46 | detected = () 47 | else: 48 | detected[threat] = {} 49 | detected[threat]['report_DoH'] = 'Good' 50 | detected[threat]['domain'] = domain 51 | detected[threat]['A'] = ips 52 | 53 | mess_mx = doh.make_query(domain, 'MX') 54 | dns_mx = base64.urlsafe_b64encode(mess_mx.to_wire()).\ 55 | decode("UTF8").rstrip("=") 56 | try: 57 | res_mx = requests.get( 58 | dnssec['elevenpaths']['url'], params={"dns": dns_mx}, 59 | headers={"Content-type": ct}) 60 | except requests.RequestException: 61 | detected[threat]['MX'] = '' 62 | return detected 63 | 64 | if ct not in res_mx.headers["Content-Type"]: 65 | detected[threat]['MX'] = '' 66 | return detected 67 | 68 | detected[threat]['MX'] = [] 69 | ans = [] 70 | for response in doh.from_wire(res_mx.content).answer: 71 | ans = response.to_text().split("\n") 72 | 73 | for ans_mx in ans: 74 | output = ans_mx.split() 75 | detected[threat]['MX'].append(output[len(output) - 1]) 76 | 77 | return detected 78 | -------------------------------------------------------------------------------- /querys/udp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ Validacion de dominios con tradicional""" 4 | 5 | import dns.resolver as dns 6 | 7 | from auxiliars.constants import dnssec 8 | 9 | 10 | def dns_udp(domain, threat): 11 | detected = {} 12 | server = dns.Resolver(configure=False) 13 | server.timeout = 10.0 14 | server.lifetime = 8.0 15 | server.nameservers = [dnssec['couldfare']['server']] 16 | 17 | try: 18 | a_response = server.query(domain, 'A', tcp=True) 19 | ips = [] 20 | mxs = [] 21 | for ip in a_response: 22 | if ip.address == dnssec['couldfare']['malware_ip']: 23 | detected[threat] = {} 24 | detected[threat]['report_DoH'] = 'Malware' 25 | ips.append(ip.to_text()) 26 | else: 27 | detected[threat] = {} 28 | detected[threat]['report_DoH'] = 'Good' 29 | ips.append(ip.to_text()) 30 | detected[threat]['domain'] = domain 31 | detected[threat]['A'] = ips 32 | 33 | try: 34 | mx_response = server.query(domain, 'MX', tcp=True) 35 | for mx in mx_response: 36 | mxs.append(mx.to_text().split(' ')[1]) 37 | detected[threat]['MX'] = mxs 38 | except: 39 | detected[threat]['MX'] = [''] 40 | 41 | except: 42 | pass 43 | 44 | return detected 45 | 46 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | atpbar 2 | colorama 3 | tld 4 | python-levenshtein 5 | dnspython3 6 | requests_mock 7 | nose -------------------------------------------------------------------------------- /test/test_auxiliars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | 6 | from io import StringIO 7 | from unittest.mock import patch 8 | 9 | from auxiliars.screen import screen_print 10 | from auxiliars.generator import generator 11 | from auxiliars.blockchain import blockchain 12 | from auxiliars.normalization import normalization 13 | 14 | 15 | class TestTypoDetect(unittest.TestCase): 16 | maxDiff = None 17 | 18 | def setUp(self): 19 | self.parts = {} 20 | self.domain = 'elevenpaths.com' 21 | self.stdout = 'sys.stdout' 22 | self.possibilities = [] 23 | 24 | def test_normalization(self): 25 | domain = [self.domain, 'lab.elevenpaths.com', 26 | 'elevenpaths.tech', 'lab.elevenpaths.tech', 27 | 'elevenpaths.com.bb', 'lab.elevenpaths.edu.bb', 28 | 'elevenpaths.gratis.es', 'lab.elevenpaths.gratis.es', 29 | 'elevenpaths.dk', 'elevenpaths', 30 | 'csa.lab.elevenpaths.team', 'csa.lab.elevenpaths.team.co'] 31 | result = [{'domain': 'elevenpaths', 'tld': 'com', 32 | 'tld_2': '', 'subdomain': ''}, 33 | {'domain': 'elevenpaths', 'tld': 'com', 34 | 'tld_2': '', 'subdomain': 'lab'}, 35 | {'domain': 'elevenpaths', 'tld': 'tech', 36 | 'tld_2': '', 'subdomain': ''}, 37 | {'domain': 'elevenpaths', 'tld': 'tech', 38 | 'tld_2': '', 'subdomain': 'lab'}, 39 | {'domain': 'elevenpaths', 'tld': 'com', 40 | 'tld_2': 'bb', 'subdomain': ''}, 41 | {'domain': 'elevenpaths', 'tld': 'edu', 42 | 'tld_2': 'bb', 'subdomain': 'lab'}, 43 | {'domain': 'elevenpaths', 'tld': 'gratis', 44 | 'tld_2': 'es', 'subdomain': ''}, 45 | {'domain': 'elevenpaths', 'tld': 'gratis', 46 | 'tld_2': 'es', 'subdomain': 'lab'}, 47 | {'domain': 'elevenpaths', 'tld': 'dk', 48 | 'tld_2': '', 'subdomain': ''}, 49 | {'domain': '', 'tld': '', 'tld_2': '', 'subdomain': ''}, 50 | {'domain': 'elevenpaths', 'tld': 'team', 51 | 'tld_2': '', 'subdomain': 'csa.lab'}, 52 | {'domain': 'elevenpaths', 'tld': 'team', 53 | 'tld_2': 'co', 'subdomain': 'csa.lab'} 54 | ] 55 | 56 | for dom in domain: 57 | self.assertEqual(normalization(dom), result[domain.index(dom)]) 58 | 59 | def test_generator(self): 60 | parts = {'domain': 'elevenpaths', 'tld': 'com', 61 | 'tld_2': '', 'subdomain': ''} 62 | result = ['3elevenpaths.arpa', '3elevenpaths.arpa.ac', 63 | '3elevenpaths.arpa.ad', '3elevenpaths.arpa.ae', 64 | '3elevenpaths.arpa.af', '3elevenpaths.arpa.ag', 65 | '3elevenpaths.arpa.ai', '3elevenpaths.arpa.al', 66 | '3elevenpaths.arpa.am', '3elevenpaths.arpa.ao'] 67 | 68 | resp = generator(parts) 69 | 70 | print('Genero ' + str(len(resp)) + ' mutaciones') 71 | self.assertEqual(resp[0:10], result) 72 | 73 | def test_blockchain(self): 74 | possibilities = [self.domain, 'lab.elevenpaths.com', 75 | 'elevenpaths.com.bb', 'lab.elevenpaths.edu.bb', 76 | 'csa.lab.elevenpaths.team', 77 | 'csa.lab.elevenpaths.team.co'] 78 | result = ['csa.lab.elevenpaths.bit', 'csa.lab.elevenpaths.emc', 79 | 'csa.lab.elevenpaths.coin', 'csa.lab.elevenpaths.lib', 80 | 'csa.lab.elevenpaths.bazar', 'csa.lab.elevenpaths.bbs', 81 | 'csa.lab.elevenpaths.chan', 'csa.lab.elevenpaths.cyb', 82 | 'csa.lab.elevenpaths.dyn', 'csa.lab.elevenpaths.geek', 83 | 'csa.lab.elevenpaths.gopher', 'csa.lab.elevenpaths.indy', 84 | 'csa.lab.elevenpaths.libre', 'csa.lab.elevenpaths.neo', 85 | 'csa.lab.elevenpaths.null', 'csa.lab.elevenpaths.o', 86 | 'csa.lab.elevenpaths.oss', 'csa.lab.elevenpaths.oz', 87 | 'csa.lab.elevenpaths.parody', 'csa.lab.elevenpaths.pirate', 88 | 'csa.lab.elevenpaths.ku', 'csa.lab.elevenpaths.te', 89 | 'csa.lab.elevenpaths.ti', 'csa.lab.elevenpaths.uu', 90 | 'csa.lab.elevenpaths.team.bit', 91 | 'csa.lab.elevenpaths.team.emc', 92 | 'csa.lab.elevenpaths.team.coin', 93 | 'csa.lab.elevenpaths.team.lib', 94 | 'csa.lab.elevenpaths.team.bazar', 95 | 'csa.lab.elevenpaths.team.bbs', 96 | 'csa.lab.elevenpaths.team.chan', 97 | 'csa.lab.elevenpaths.team.cyb', 98 | 'csa.lab.elevenpaths.team.dyn', 99 | 'csa.lab.elevenpaths.team.geek', 100 | 'csa.lab.elevenpaths.team.gopher', 101 | 'csa.lab.elevenpaths.team.indy', 102 | 'csa.lab.elevenpaths.team.libre', 103 | 'csa.lab.elevenpaths.team.neo', 104 | 'csa.lab.elevenpaths.team.null', 105 | 'csa.lab.elevenpaths.team.o', 106 | 'csa.lab.elevenpaths.team.oss', 107 | 'csa.lab.elevenpaths.team.oz', 108 | 'csa.lab.elevenpaths.team.parody', 109 | 'csa.lab.elevenpaths.team.pirate', 110 | 'csa.lab.elevenpaths.team.ku', 111 | 'csa.lab.elevenpaths.team.te', 112 | 'csa.lab.elevenpaths.team.ti', 113 | 'csa.lab.elevenpaths.team.uu', 114 | 'elevenpaths.bit', 'elevenpaths.emc', 'elevenpaths.coin', 115 | 'elevenpaths.lib', 'elevenpaths.bazar', 'elevenpaths.bbs', 116 | 'elevenpaths.chan', 'elevenpaths.cyb', 'elevenpaths.dyn', 117 | 'elevenpaths.geek', 'elevenpaths.gopher', 118 | 'elevenpaths.indy', 'elevenpaths.libre', 119 | 'elevenpaths.neo', 'elevenpaths.null', 'elevenpaths.o', 120 | 'elevenpaths.oss', 'elevenpaths.oz', 'elevenpaths.parody', 121 | 'elevenpaths.pirate', 'elevenpaths.ku', 'elevenpaths.te', 122 | 'elevenpaths.ti', 'elevenpaths.uu', 'lab.elevenpaths.bit', 123 | 'lab.elevenpaths.emc', 'lab.elevenpaths.coin', 124 | 'lab.elevenpaths.lib', 'lab.elevenpaths.bazar', 125 | 'lab.elevenpaths.bbs', 'lab.elevenpaths.chan', 126 | 'lab.elevenpaths.cyb', 'lab.elevenpaths.dyn', 127 | 'lab.elevenpaths.geek', 'lab.elevenpaths.gopher', 128 | 'lab.elevenpaths.indy', 'lab.elevenpaths.libre', 129 | 'lab.elevenpaths.neo', 'lab.elevenpaths.null', 130 | 'lab.elevenpaths.o', 'lab.elevenpaths.oss', 131 | 'lab.elevenpaths.oz', 'lab.elevenpaths.parody', 132 | 'lab.elevenpaths.pirate', 'lab.elevenpaths.ku', 133 | 'lab.elevenpaths.te', 'lab.elevenpaths.ti', 134 | 'lab.elevenpaths.uu'] 135 | 136 | self.assertEqual(blockchain(possibilities), result) 137 | 138 | def test_screen_print(self): 139 | mutations = 3 140 | 141 | result = { 142 | 0: { 143 | 'report_DoH': 'Good', 144 | 'domain': 'elevenpaths.com', 145 | 'A': ['52.212.36.140'], 146 | 'MX': ['elevenpaths-com.mail.protection.outlook.com.']}, 147 | 1: { 148 | 'report_DoH': 'Malware', 149 | 'domain': 'northnovacable.ca', 150 | 'A': '', 151 | 'MX': ''}, 152 | 2: { 153 | 'report_DoH': '', 154 | 'domain': 'eagletv.coin', 155 | 'A': ['192.243.100.192'], 156 | 'MX': ''}} 157 | 158 | out = "\x1b[32m\x1b[1m\n\n___________ ________ " \ 159 | " __ __ " \ 160 | " \n\__ ___/__.__.______ ____\______ \ _____/ |_ __" \ 161 | "__ _____/ |_" \ 162 | " \n | | < | |\____ \ / _ \| | \_/ __ \ __\/ _" \ 163 | "_ \_/ ___\ __|" \ 164 | "\n | | \___ || |_> > <_> ) ` \ ___/| | \ _" \ 165 | "__/\ \___| |" \ 166 | " \n |____| / ____|| __/ \____/_______ /\___ >__| \_" \ 167 | "__ >\___ >__|" \ 168 | " \n \/ |__| \/ \/ " \ 169 | " \/ \/ " \ 170 | "\n\nTyposquatting Detect and Analyze" \ 171 | "\nBy ElevenPaths https://www.elevenpaths.com/" \ 172 | "\nUsage: python3 ./typodetect.py" \ 173 | "\n\n\n" \ 174 | "\x1b[32m\x1b[1m[*] ---------------------------------------" \ 175 | "-----------------------------------------------------------" \ 176 | "-- [*]" \ 177 | "\n\x1b[31m\x1b[1m[*] IANA Database updated: Last " \ 178 | "Updated Tue Jan 19 07:07:01 2021 UTC" \ 179 | "\n\x1b[34m\x1b[1m[*] Inicial Domain: elevenpaths.com" \ 180 | "\n\x1b[34m\x1b[1m\t[*] Register type A: 52.212.36.140" \ 181 | "\n\x1b[34m\x1b[1m\t[*] Register type MX: elevenpaths-com." \ 182 | "mail.protection.outlook.com." \ 183 | "\n\x1b[32m\x1b[1m[*] -------------------------------------" \ 184 | "----------------------------------------------------------" \ 185 | "----- [*]" \ 186 | "\n\n\n\n\x1b[32m\x1b[1m[*] ---------------------------------" \ 187 | "------------------------------------------------------------" \ 188 | "------- [*]" \ 189 | "\n\x1b[32m\x1b[1m[*] We detected 3 possibles domains mutation" \ 190 | "s of elevenpaths.com" \ 191 | "\n\x1b[32m\x1b[1m[*] Of which 3 domains resolved to an A or" \ 192 | " MX record for ElevenPaths" \ 193 | "\n\x1b[32m\x1b[1m[*] ----------------------------------------" \ 194 | "------------------------------------------------------------" \ 195 | " [*]" \ 196 | "\n" \ 197 | "\n\x1b[31m\x1b[22m\t[*] Detected domain: northnovacable.ca" \ 198 | "\n\x1b[31m\x1b[22m\t\t[*] DNS over HTTPS of ElevenPaths" \ 199 | " report this domain is Malware" \ 200 | "\n\x1b[31m\x1b[22m[*] --------------------------------------" \ 201 | "------------------------------------------------------------" \ 202 | "-- [*]" \ 203 | "\n\x1b[33m\x1b[22m\t[*] Detected domain: eagletv.coin" \ 204 | "\n\x1b[33m\x1b[22m\t\t[*] Register type A: 192.243.100.192" \ 205 | "\n\x1b[33m\x1b[22m[*] --------------------------------------" \ 206 | "-------------------------------------------------------------" \ 207 | "- [*]" \ 208 | "\n\x1b[36m\x1b[22m[*] -------------------------------------" \ 209 | "-----------------------------------------------------------" \ 210 | "---- [*]" \ 211 | "\n\x1b[36m\x1b[22m[*] If the report is in " \ 212 | "\x1b[31m\x1b[1mred\x1b[36m\x1b[22m, it is a domain marked as" \ 213 | " malware in the DoH" \ 214 | "\n\x1b[36m\x1b[22m[*] If the report is in " \ 215 | "\x1b[33m\x1b[1myellow\x1b[36m\x1b[22m, it is a domain" \ 216 | " detected in the Blockchain DNS" \ 217 | "\n\x1b[36m\x1b[22m[*] ----------------------------------" \ 218 | "------------------------------------------------------" \ 219 | "------------ [*]\n" 220 | 221 | with patch(self.stdout, new=StringIO()) as screen_out: 222 | screen_print(self.domain, mutations, result, 1) 223 | self.assertEqual(screen_out.getvalue(), out) 224 | 225 | 226 | if __name__ == "__main__": 227 | unittest.main() 228 | -------------------------------------------------------------------------------- /test/test_mutations.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | 6 | from mutations.replace import replace 7 | from mutations.keyboard import keyboard 8 | from mutations.adictions import adictions 9 | from mutations.countries import countries 10 | from mutations.subdomains import subdomains 11 | from mutations.change_tld import change_tld 12 | from mutations.repetition import repetition 13 | from mutations.subtraction import subtraction 14 | from mutations.integration import integration 15 | from mutations.distance import distance_levenshtein 16 | 17 | 18 | class TestTypoDetect(unittest.TestCase): 19 | maxDiff = None 20 | 21 | def setUp(self): 22 | self.base = '' 23 | self.possibilities = [] 24 | 25 | def test_countries(self): 26 | base = ['elevenpaths.com', 'elevenpaths.co', 'elevenpaths.tech.bs'] 27 | possibilities = [] 28 | result = [['elevenpaths.com.ac', 'elevenpaths.com.ad', 29 | 'elevenpaths.com.ae', 'elevenpaths.com.af', 30 | 'elevenpaths.com.ag', 'elevenpaths.com.ai', 31 | 'elevenpaths.com.al', 'elevenpaths.com.am', 32 | 'elevenpaths.com.ao', 'elevenpaths.com.aq', 33 | 'elevenpaths.com.ar', 'elevenpaths.com.as', 34 | 'elevenpaths.com.at', 'elevenpaths.com.au', 35 | 'elevenpaths.com.aw', 'elevenpaths.com.ax', 36 | 'elevenpaths.com.az', 'elevenpaths.com.ba', 37 | 'elevenpaths.com.bb', 'elevenpaths.com.bd', 38 | 'elevenpaths.com.be', 'elevenpaths.com.bf', 39 | 'elevenpaths.com.bg', 'elevenpaths.com.bh', 40 | 'elevenpaths.com.bi', 'elevenpaths.com.bj', 41 | 'elevenpaths.com.bm', 'elevenpaths.com.bn', 42 | 'elevenpaths.com.bo', 'elevenpaths.com.bq', 43 | 'elevenpaths.com.br', 'elevenpaths.com.bs', 44 | 'elevenpaths.com.bt', 'elevenpaths.com.bw', 45 | 'elevenpaths.com.by', 'elevenpaths.com.bz', 46 | 'elevenpaths.com.ca', 'elevenpaths.com.cc', 47 | 'elevenpaths.com.cd', 'elevenpaths.com.cf', 48 | 'elevenpaths.com.cg', 'elevenpaths.com.ch', 49 | 'elevenpaths.com.ci', 'elevenpaths.com.ck', 50 | 'elevenpaths.com.cl', 'elevenpaths.com.cm', 51 | 'elevenpaths.com.cn', 'elevenpaths.com.co', 52 | 'elevenpaths.com.cr', 'elevenpaths.com.cu', 53 | 'elevenpaths.com.cv', 'elevenpaths.com.cw', 54 | 'elevenpaths.com.cx', 'elevenpaths.com.cy', 55 | 'elevenpaths.com.cz', 'elevenpaths.com.de', 56 | 'elevenpaths.com.dj', 'elevenpaths.com.dk', 57 | 'elevenpaths.com.dm', 'elevenpaths.com.do', 58 | 'elevenpaths.com.dz', 'elevenpaths.com.ec', 59 | 'elevenpaths.com.ee', 'elevenpaths.com.eg', 60 | 'elevenpaths.com.er', 'elevenpaths.com.es', 61 | 'elevenpaths.com.et', 'elevenpaths.com.eu', 62 | 'elevenpaths.com.fi', 'elevenpaths.com.fj', 63 | 'elevenpaths.com.fk', 'elevenpaths.com.fm', 64 | 'elevenpaths.com.fo', 'elevenpaths.com.fr', 65 | 'elevenpaths.com.ga', 'elevenpaths.com.gd', 66 | 'elevenpaths.com.ge', 'elevenpaths.com.gf', 67 | 'elevenpaths.com.gg', 'elevenpaths.com.gh', 68 | 'elevenpaths.com.gi', 'elevenpaths.com.gl', 69 | 'elevenpaths.com.gm', 'elevenpaths.com.gn', 70 | 'elevenpaths.com.gp', 'elevenpaths.com.gq', 71 | 'elevenpaths.com.gr', 'elevenpaths.com.gs', 72 | 'elevenpaths.com.gt', 'elevenpaths.com.gu', 73 | 'elevenpaths.com.gw', 'elevenpaths.com.gy', 74 | 'elevenpaths.com.hk', 'elevenpaths.com.hm', 75 | 'elevenpaths.com.hn', 'elevenpaths.com.hr', 76 | 'elevenpaths.com.ht', 'elevenpaths.com.hu', 77 | 'elevenpaths.com.id', 'elevenpaths.com.ie'], 78 | ['elevenpaths.ac', 'elevenpaths.ad', 79 | 'elevenpaths.ae', 'elevenpaths.af', 80 | 'elevenpaths.ag', 'elevenpaths.ai', 81 | 'elevenpaths.al', 'elevenpaths.am', 82 | 'elevenpaths.ao', 'elevenpaths.aq', 83 | 'elevenpaths.ar', 'elevenpaths.as', 84 | 'elevenpaths.at', 'elevenpaths.au', 85 | 'elevenpaths.aw', 'elevenpaths.ax', 86 | 'elevenpaths.az', 'elevenpaths.ba', 87 | 'elevenpaths.bb', 'elevenpaths.bd', 88 | 'elevenpaths.be', 'elevenpaths.bf', 89 | 'elevenpaths.bg', 'elevenpaths.bh', 90 | 'elevenpaths.bi', 'elevenpaths.bj', 91 | 'elevenpaths.bm', 'elevenpaths.bn', 92 | 'elevenpaths.bo', 'elevenpaths.bq', 93 | 'elevenpaths.br', 'elevenpaths.bs', 94 | 'elevenpaths.bt', 'elevenpaths.bw', 95 | 'elevenpaths.by', 'elevenpaths.bz', 96 | 'elevenpaths.ca', 'elevenpaths.cc', 97 | 'elevenpaths.cd', 'elevenpaths.cf', 98 | 'elevenpaths.cg', 'elevenpaths.ch', 99 | 'elevenpaths.ci', 'elevenpaths.ck', 100 | 'elevenpaths.cl', 'elevenpaths.cm', 101 | 'elevenpaths.cn', 'elevenpaths.co', 102 | 'elevenpaths.cr', 'elevenpaths.cu', 103 | 'elevenpaths.cv', 'elevenpaths.cw', 104 | 'elevenpaths.cx', 'elevenpaths.cy', 105 | 'elevenpaths.cz', 'elevenpaths.de', 106 | 'elevenpaths.dj', 'elevenpaths.dk', 107 | 'elevenpaths.dm', 'elevenpaths.do', 108 | 'elevenpaths.dz', 'elevenpaths.ec', 109 | 'elevenpaths.ee', 'elevenpaths.eg', 110 | 'elevenpaths.er', 'elevenpaths.es', 111 | 'elevenpaths.et', 'elevenpaths.eu', 112 | 'elevenpaths.fi', 'elevenpaths.fj', 113 | 'elevenpaths.fk', 'elevenpaths.fm', 114 | 'elevenpaths.fo', 'elevenpaths.fr', 115 | 'elevenpaths.ga', 'elevenpaths.gd', 116 | 'elevenpaths.ge', 'elevenpaths.gf', 117 | 'elevenpaths.gg', 'elevenpaths.gh', 118 | 'elevenpaths.gi', 'elevenpaths.gl', 119 | 'elevenpaths.gm', 'elevenpaths.gn', 120 | 'elevenpaths.gp', 'elevenpaths.gq', 121 | 'elevenpaths.gr', 'elevenpaths.gs', 122 | 'elevenpaths.gt', 'elevenpaths.gu', 123 | 'elevenpaths.gw', 'elevenpaths.gy', 124 | 'elevenpaths.hk', 'elevenpaths.hm', 125 | 'elevenpaths.hn', 'elevenpaths.hr', 126 | 'elevenpaths.ht', 'elevenpaths.hu', 127 | 'elevenpaths.id', 'elevenpaths.ie'], 128 | ['elevenpaths.tech.ac', 'elevenpaths.tech.ad', 129 | 'elevenpaths.tech.ae', 'elevenpaths.tech.af', 130 | 'elevenpaths.tech.ag', 'elevenpaths.tech.ai', 131 | 'elevenpaths.tech.al', 'elevenpaths.tech.am', 132 | 'elevenpaths.tech.ao', 'elevenpaths.tech.aq', 133 | 'elevenpaths.tech.ar', 'elevenpaths.tech.as', 134 | 'elevenpaths.tech.at', 'elevenpaths.tech.au', 135 | 'elevenpaths.tech.aw', 'elevenpaths.tech.ax', 136 | 'elevenpaths.tech.az', 'elevenpaths.tech.ba', 137 | 'elevenpaths.tech.bb', 'elevenpaths.tech.bd', 138 | 'elevenpaths.tech.be', 'elevenpaths.tech.bf', 139 | 'elevenpaths.tech.bg', 'elevenpaths.tech.bh', 140 | 'elevenpaths.tech.bi', 'elevenpaths.tech.bj', 141 | 'elevenpaths.tech.bm', 'elevenpaths.tech.bn', 142 | 'elevenpaths.tech.bo', 'elevenpaths.tech.bq', 143 | 'elevenpaths.tech.br', 'elevenpaths.tech.bs', 144 | 'elevenpaths.tech.bt', 'elevenpaths.tech.bw', 145 | 'elevenpaths.tech.by', 'elevenpaths.tech.bz', 146 | 'elevenpaths.tech.ca', 'elevenpaths.tech.cc', 147 | 'elevenpaths.tech.cd', 'elevenpaths.tech.cf', 148 | 'elevenpaths.tech.cg', 'elevenpaths.tech.ch', 149 | 'elevenpaths.tech.ci', 'elevenpaths.tech.ck', 150 | 'elevenpaths.tech.cl', 'elevenpaths.tech.cm', 151 | 'elevenpaths.tech.cn', 'elevenpaths.tech.co', 152 | 'elevenpaths.tech.cr', 'elevenpaths.tech.cu', 153 | 'elevenpaths.tech.cv', 'elevenpaths.tech.cw', 154 | 'elevenpaths.tech.cx', 'elevenpaths.tech.cy', 155 | 'elevenpaths.tech.cz', 'elevenpaths.tech.de', 156 | 'elevenpaths.tech.dj', 'elevenpaths.tech.dk', 157 | 'elevenpaths.tech.dm', 'elevenpaths.tech.do', 158 | 'elevenpaths.tech.dz', 'elevenpaths.tech.ec', 159 | 'elevenpaths.tech.ee', 'elevenpaths.tech.eg', 160 | 'elevenpaths.tech.er', 'elevenpaths.tech.es', 161 | 'elevenpaths.tech.et', 'elevenpaths.tech.eu', 162 | 'elevenpaths.tech.fi', 'elevenpaths.tech.fj', 163 | 'elevenpaths.tech.fk', 'elevenpaths.tech.fm', 164 | 'elevenpaths.tech.fo', 'elevenpaths.tech.fr', 165 | 'elevenpaths.tech.ga', 'elevenpaths.tech.gd', 166 | 'elevenpaths.tech.ge', 'elevenpaths.tech.gf', 167 | 'elevenpaths.tech.gg', 'elevenpaths.tech.gh', 168 | 'elevenpaths.tech.gi', 'elevenpaths.tech.gl', 169 | 'elevenpaths.tech.gm', 'elevenpaths.tech.gn', 170 | 'elevenpaths.tech.gp', 'elevenpaths.tech.gq', 171 | 'elevenpaths.tech.gr', 'elevenpaths.tech.gs', 172 | 'elevenpaths.tech.gt', 'elevenpaths.tech.gu', 173 | 'elevenpaths.tech.gw', 'elevenpaths.tech.gy', 174 | 'elevenpaths.tech.hk', 'elevenpaths.tech.hm', 175 | 'elevenpaths.tech.hn', 'elevenpaths.tech.hr', 176 | 'elevenpaths.tech.ht', 'elevenpaths.tech.hu', 177 | 'elevenpaths.tech.id', 'elevenpaths.tech.ie'] 178 | ] 179 | 180 | for b in base: 181 | self.assertEqual(countries(b, possibilities)[0:100], 182 | result[base.index(b)]) 183 | possibilities = [] 184 | 185 | def test_integrartion(self): 186 | base = ['elevenpaths.com', 'elevenpaths.tech.bs'] 187 | possibilities = [] 188 | result = [['elevenpathscom.com', 'elevenpathscom.com.ac', 189 | 'elevenpathscom.com.ad', 'elevenpathscom.com.ae', 190 | 'elevenpathscom.com.af', 'elevenpathscom.com.ag', 191 | 'elevenpathscom.com.ai', 'elevenpathscom.com.al', 192 | 'elevenpathscom.com.am', 'elevenpathscom.com.ao', 193 | 'elevenpathscom.com.aq', 'elevenpathscom.com.ar', 194 | 'elevenpathscom.com.as', 'elevenpathscom.com.at', 195 | 'elevenpathscom.com.au', 'elevenpathscom.com.aw', 196 | 'elevenpathscom.com.ax', 'elevenpathscom.com.az', 197 | 'elevenpathscom.com.ba', 'elevenpathscom.com.bb', 198 | 'elevenpathscom.com.bd', 'elevenpathscom.com.be', 199 | 'elevenpathscom.com.bf', 'elevenpathscom.com.bg', 200 | 'elevenpathscom.com.bh', 'elevenpathscom.com.bi', 201 | 'elevenpathscom.com.bj', 'elevenpathscom.com.bm', 202 | 'elevenpathscom.com.bn', 'elevenpathscom.com.bo', 203 | 'elevenpathscom.com.bq', 'elevenpathscom.com.br', 204 | 'elevenpathscom.com.bs', 'elevenpathscom.com.bt', 205 | 'elevenpathscom.com.bw', 'elevenpathscom.com.by', 206 | 'elevenpathscom.com.bz', 'elevenpathscom.com.ca', 207 | 'elevenpathscom.com.cc', 'elevenpathscom.com.cd', 208 | 'elevenpathscom.com.cf', 'elevenpathscom.com.cg', 209 | 'elevenpathscom.com.ch', 'elevenpathscom.com.ci', 210 | 'elevenpathscom.com.ck', 'elevenpathscom.com.cl', 211 | 'elevenpathscom.com.cm', 'elevenpathscom.com.cn', 212 | 'elevenpathscom.com.co', 'elevenpathscom.com.cr', 213 | 'elevenpathscom.com.cu', 'elevenpathscom.com.cv', 214 | 'elevenpathscom.com.cw', 'elevenpathscom.com.cx', 215 | 'elevenpathscom.com.cy', 'elevenpathscom.com.cz', 216 | 'elevenpathscom.com.de', 'elevenpathscom.com.dj', 217 | 'elevenpathscom.com.dk', 'elevenpathscom.com.dm', 218 | 'elevenpathscom.com.do', 'elevenpathscom.com.dz', 219 | 'elevenpathscom.com.ec', 'elevenpathscom.com.ee', 220 | 'elevenpathscom.com.eg', 'elevenpathscom.com.er', 221 | 'elevenpathscom.com.es', 'elevenpathscom.com.et', 222 | 'elevenpathscom.com.eu', 'elevenpathscom.com.fi', 223 | 'elevenpathscom.com.fj', 'elevenpathscom.com.fk', 224 | 'elevenpathscom.com.fm', 'elevenpathscom.com.fo', 225 | 'elevenpathscom.com.fr', 'elevenpathscom.com.ga', 226 | 'elevenpathscom.com.gd', 'elevenpathscom.com.ge', 227 | 'elevenpathscom.com.gf', 'elevenpathscom.com.gg', 228 | 'elevenpathscom.com.gh', 'elevenpathscom.com.gi', 229 | 'elevenpathscom.com.gl', 'elevenpathscom.com.gm', 230 | 'elevenpathscom.com.gn', 'elevenpathscom.com.gp', 231 | 'elevenpathscom.com.gq', 'elevenpathscom.com.gr', 232 | 'elevenpathscom.com.gs', 'elevenpathscom.com.gt', 233 | 'elevenpathscom.com.gu', 'elevenpathscom.com.gw', 234 | 'elevenpathscom.com.gy', 'elevenpathscom.com.hk', 235 | 'elevenpathscom.com.hm', 'elevenpathscom.com.hn', 236 | 'elevenpathscom.com.hr', 'elevenpathscom.com.ht', 237 | 'elevenpathscom.com.hu', 'elevenpathscom.com.id'], 238 | ['elevenpathstechbs.com', 'elevenpathstechbs.com.ac', 239 | 'elevenpathstechbs.com.ad', 'elevenpathstechbs.com.ae', 240 | 'elevenpathstechbs.com.af', 'elevenpathstechbs.com.ag', 241 | 'elevenpathstechbs.com.ai', 'elevenpathstechbs.com.al', 242 | 'elevenpathstechbs.com.am', 'elevenpathstechbs.com.ao', 243 | 'elevenpathstechbs.com.aq', 'elevenpathstechbs.com.ar', 244 | 'elevenpathstechbs.com.as', 'elevenpathstechbs.com.at', 245 | 'elevenpathstechbs.com.au', 'elevenpathstechbs.com.aw', 246 | 'elevenpathstechbs.com.ax', 'elevenpathstechbs.com.az', 247 | 'elevenpathstechbs.com.ba', 'elevenpathstechbs.com.bb', 248 | 'elevenpathstechbs.com.bd', 'elevenpathstechbs.com.be', 249 | 'elevenpathstechbs.com.bf', 'elevenpathstechbs.com.bg', 250 | 'elevenpathstechbs.com.bh', 'elevenpathstechbs.com.bi', 251 | 'elevenpathstechbs.com.bj', 'elevenpathstechbs.com.bm', 252 | 'elevenpathstechbs.com.bn', 'elevenpathstechbs.com.bo', 253 | 'elevenpathstechbs.com.bq', 'elevenpathstechbs.com.br', 254 | 'elevenpathstechbs.com.bs', 'elevenpathstechbs.com.bt', 255 | 'elevenpathstechbs.com.bw', 'elevenpathstechbs.com.by', 256 | 'elevenpathstechbs.com.bz', 'elevenpathstechbs.com.ca', 257 | 'elevenpathstechbs.com.cc', 'elevenpathstechbs.com.cd', 258 | 'elevenpathstechbs.com.cf', 'elevenpathstechbs.com.cg', 259 | 'elevenpathstechbs.com.ch', 'elevenpathstechbs.com.ci', 260 | 'elevenpathstechbs.com.ck', 'elevenpathstechbs.com.cl', 261 | 'elevenpathstechbs.com.cm', 'elevenpathstechbs.com.cn', 262 | 'elevenpathstechbs.com.co', 'elevenpathstechbs.com.cr', 263 | 'elevenpathstechbs.com.cu', 'elevenpathstechbs.com.cv', 264 | 'elevenpathstechbs.com.cw', 'elevenpathstechbs.com.cx', 265 | 'elevenpathstechbs.com.cy', 'elevenpathstechbs.com.cz', 266 | 'elevenpathstechbs.com.de', 'elevenpathstechbs.com.dj', 267 | 'elevenpathstechbs.com.dk', 'elevenpathstechbs.com.dm', 268 | 'elevenpathstechbs.com.do', 'elevenpathstechbs.com.dz', 269 | 'elevenpathstechbs.com.ec', 'elevenpathstechbs.com.ee', 270 | 'elevenpathstechbs.com.eg', 'elevenpathstechbs.com.er', 271 | 'elevenpathstechbs.com.es', 'elevenpathstechbs.com.et', 272 | 'elevenpathstechbs.com.eu', 'elevenpathstechbs.com.fi', 273 | 'elevenpathstechbs.com.fj', 'elevenpathstechbs.com.fk', 274 | 'elevenpathstechbs.com.fm', 'elevenpathstechbs.com.fo', 275 | 'elevenpathstechbs.com.fr', 'elevenpathstechbs.com.ga', 276 | 'elevenpathstechbs.com.gd', 'elevenpathstechbs.com.ge', 277 | 'elevenpathstechbs.com.gf', 'elevenpathstechbs.com.gg', 278 | 'elevenpathstechbs.com.gh', 'elevenpathstechbs.com.gi', 279 | 'elevenpathstechbs.com.gl', 'elevenpathstechbs.com.gm', 280 | 'elevenpathstechbs.com.gn', 'elevenpathstechbs.com.gp', 281 | 'elevenpathstechbs.com.gq', 'elevenpathstechbs.com.gr', 282 | 'elevenpathstechbs.com.gs', 'elevenpathstechbs.com.gt', 283 | 'elevenpathstechbs.com.gu', 'elevenpathstechbs.com.gw', 284 | 'elevenpathstechbs.com.gy', 'elevenpathstechbs.com.hk', 285 | 'elevenpathstechbs.com.hm', 'elevenpathstechbs.com.hn', 286 | 'elevenpathstechbs.com.hr', 'elevenpathstechbs.com.ht', 287 | 'elevenpathstechbs.com.hu', 'elevenpathstechbs.com.id']] 288 | 289 | for b in base: 290 | self.assertEqual(integration(b, possibilities)[0:100], 291 | result[base.index(b)]) 292 | possibilities = [] 293 | 294 | def test_subdomains(self): 295 | base = 'elevenpaths' 296 | tlds = 'com' 297 | result = ['.elevenpaths.com', '.elevenpaths.com', '.elevenpaths.com', 298 | '-elevenpaths.com', '.elevenpaths.com.ac', 299 | '-elevenpaths.com.ac', '.elevenpaths.com.ad', 300 | '-elevenpaths.com.ad', '.elevenpaths.com.ae', 301 | '-elevenpaths.com.ae', '.elevenpaths.com.af', 302 | '-elevenpaths.com.af', '.elevenpaths.com.ag', 303 | '-elevenpaths.com.ag', '.elevenpaths.com.ai', 304 | '-elevenpaths.com.ai', '.elevenpaths.com.al', 305 | '-elevenpaths.com.al', '.elevenpaths.com.am', 306 | '-elevenpaths.com.am', '.elevenpaths.com.ao', 307 | '-elevenpaths.com.ao', '.elevenpaths.com.aq', 308 | '-elevenpaths.com.aq', '.elevenpaths.com.ar', 309 | '-elevenpaths.com.ar', '.elevenpaths.com.as', 310 | '-elevenpaths.com.as', '.elevenpaths.com.at', 311 | '-elevenpaths.com.at', '.elevenpaths.com.au', 312 | '-elevenpaths.com.au', '.elevenpaths.com.aw', 313 | '-elevenpaths.com.aw', '.elevenpaths.com.ax', 314 | '-elevenpaths.com.ax', '.elevenpaths.com.az', 315 | '-elevenpaths.com.az', '.elevenpaths.com.ba', 316 | '-elevenpaths.com.ba', '.elevenpaths.com.bb', 317 | '-elevenpaths.com.bb', '.elevenpaths.com.bd', 318 | '-elevenpaths.com.bd', '.elevenpaths.com.be', 319 | '-elevenpaths.com.be', '.elevenpaths.com.bf', 320 | '-elevenpaths.com.bf', '.elevenpaths.com.bg', 321 | '-elevenpaths.com.bg', '.elevenpaths.com.bh', 322 | '-elevenpaths.com.bh', '.elevenpaths.com.bi', 323 | '-elevenpaths.com.bi', '.elevenpaths.com.bj', 324 | '-elevenpaths.com.bj', '.elevenpaths.com.bm', 325 | '-elevenpaths.com.bm', '.elevenpaths.com.bn', 326 | '-elevenpaths.com.bn', '.elevenpaths.com.bo', 327 | '-elevenpaths.com.bo', '.elevenpaths.com.bq', 328 | '-elevenpaths.com.bq', '.elevenpaths.com.br', 329 | '-elevenpaths.com.br', '.elevenpaths.com.bs', 330 | '-elevenpaths.com.bs', '.elevenpaths.com.bt', 331 | '-elevenpaths.com.bt', '.elevenpaths.com.bw', 332 | '-elevenpaths.com.bw', '.elevenpaths.com.by', 333 | '-elevenpaths.com.by', '.elevenpaths.com.bz', 334 | '-elevenpaths.com.bz', '.elevenpaths.com.ca', 335 | '-elevenpaths.com.ca', '.elevenpaths.com.cc', 336 | '-elevenpaths.com.cc', '.elevenpaths.com.cd', 337 | '-elevenpaths.com.cd', '.elevenpaths.com.cf', 338 | '-elevenpaths.com.cf', '.elevenpaths.com.cg', 339 | '-elevenpaths.com.cg', '.elevenpaths.com.ch', 340 | '-elevenpaths.com.ch', '.elevenpaths.com.ci', 341 | '-elevenpaths.com.ci', '.elevenpaths.com.ck', 342 | '-elevenpaths.com.ck', '.elevenpaths.com.cl', 343 | '-elevenpaths.com.cl', '.elevenpaths.com.cm', 344 | '-elevenpaths.com.cm', '.elevenpaths.com.cn', 345 | '-elevenpaths.com.cn', '.elevenpaths.com.co', 346 | '-elevenpaths.com.co'] 347 | 348 | self.assertEqual(subdomains(base, tlds, self.possibilities)[0:100], 349 | result) 350 | 351 | def test_change_tld(self): 352 | base = 'elevenpaths' 353 | result = ['elevenpaths.com', 'elevenpaths.com.ac', 354 | 'elevenpaths.com.ad', 'elevenpaths.com.ae', 355 | 'elevenpaths.com.af', 'elevenpaths.com.ag', 356 | 'elevenpaths.com.ai', 'elevenpaths.com.al', 357 | 'elevenpaths.com.am', 'elevenpaths.com.ao', 358 | 'elevenpaths.com.aq', 'elevenpaths.com.ar', 359 | 'elevenpaths.com.as', 'elevenpaths.com.at', 360 | 'elevenpaths.com.au', 'elevenpaths.com.aw', 361 | 'elevenpaths.com.ax', 'elevenpaths.com.az', 362 | 'elevenpaths.com.ba', 'elevenpaths.com.bb', 363 | 'elevenpaths.com.bd', 'elevenpaths.com.be', 364 | 'elevenpaths.com.bf', 'elevenpaths.com.bg', 365 | 'elevenpaths.com.bh', 'elevenpaths.com.bi', 366 | 'elevenpaths.com.bj', 'elevenpaths.com.bm', 367 | 'elevenpaths.com.bn', 'elevenpaths.com.bo', 368 | 'elevenpaths.com.bq', 'elevenpaths.com.br', 369 | 'elevenpaths.com.bs', 'elevenpaths.com.bt', 370 | 'elevenpaths.com.bw', 'elevenpaths.com.by', 371 | 'elevenpaths.com.bz', 'elevenpaths.com.ca', 372 | 'elevenpaths.com.cc', 'elevenpaths.com.cd', 373 | 'elevenpaths.com.cf', 'elevenpaths.com.cg', 374 | 'elevenpaths.com.ch', 'elevenpaths.com.ci', 375 | 'elevenpaths.com.ck', 'elevenpaths.com.cl', 376 | 'elevenpaths.com.cm', 'elevenpaths.com.cn', 377 | 'elevenpaths.com.co', 'elevenpaths.com.cr', 378 | 'elevenpaths.com.cu', 'elevenpaths.com.cv', 379 | 'elevenpaths.com.cw', 'elevenpaths.com.cx', 380 | 'elevenpaths.com.cy', 'elevenpaths.com.cz', 381 | 'elevenpaths.com.de', 'elevenpaths.com.dj', 382 | 'elevenpaths.com.dk', 'elevenpaths.com.dm', 383 | 'elevenpaths.com.do', 'elevenpaths.com.dz', 384 | 'elevenpaths.com.ec', 'elevenpaths.com.ee', 385 | 'elevenpaths.com.eg', 'elevenpaths.com.er', 386 | 'elevenpaths.com.es', 'elevenpaths.com.et', 387 | 'elevenpaths.com.eu', 'elevenpaths.com.fi', 388 | 'elevenpaths.com.fj', 'elevenpaths.com.fk', 389 | 'elevenpaths.com.fm', 'elevenpaths.com.fo', 390 | 'elevenpaths.com.fr', 'elevenpaths.com.ga', 391 | 'elevenpaths.com.gd', 'elevenpaths.com.ge', 392 | 'elevenpaths.com.gf', 'elevenpaths.com.gg', 393 | 'elevenpaths.com.gh', 'elevenpaths.com.gi', 394 | 'elevenpaths.com.gl', 'elevenpaths.com.gm', 395 | 'elevenpaths.com.gn', 'elevenpaths.com.gp', 396 | 'elevenpaths.com.gq', 'elevenpaths.com.gr', 397 | 'elevenpaths.com.gs', 'elevenpaths.com.gt', 398 | 'elevenpaths.com.gu', 'elevenpaths.com.gw', 399 | 'elevenpaths.com.gy', 'elevenpaths.com.hk', 400 | 'elevenpaths.com.hm', 'elevenpaths.com.hn', 401 | 'elevenpaths.com.hr', 'elevenpaths.com.ht', 402 | 'elevenpaths.com.hu', 'elevenpaths.com.id'] 403 | 404 | self.assertEqual(change_tld(base, self.possibilities)[0:100], result) 405 | 406 | def test_subtraction(self): 407 | base = 'elevenpaths' 408 | tlds = 'com' 409 | result = ['levenpaths.com', 'levenpaths.com', 'levenpaths.com.ac', 410 | 'levenpaths.com.ad', 'levenpaths.com.ae', 411 | 'levenpaths.com.af', 'levenpaths.com.ag', 412 | 'levenpaths.com.ai', 'levenpaths.com.al', 413 | 'levenpaths.com.am', 'levenpaths.com.ao', 414 | 'levenpaths.com.aq', 'levenpaths.com.ar', 415 | 'levenpaths.com.as', 'levenpaths.com.at', 416 | 'levenpaths.com.au', 'levenpaths.com.aw', 417 | 'levenpaths.com.ax', 'levenpaths.com.az', 418 | 'levenpaths.com.ba', 'levenpaths.com.bb', 419 | 'levenpaths.com.bd', 'levenpaths.com.be', 420 | 'levenpaths.com.bf', 'levenpaths.com.bg', 421 | 'levenpaths.com.bh', 'levenpaths.com.bi', 422 | 'levenpaths.com.bj', 'levenpaths.com.bm', 423 | 'levenpaths.com.bn', 'levenpaths.com.bo', 424 | 'levenpaths.com.bq', 'levenpaths.com.br', 425 | 'levenpaths.com.bs', 'levenpaths.com.bt', 426 | 'levenpaths.com.bw', 'levenpaths.com.by', 427 | 'levenpaths.com.bz', 'levenpaths.com.ca', 428 | 'levenpaths.com.cc', 'levenpaths.com.cd', 429 | 'levenpaths.com.cf', 'levenpaths.com.cg', 430 | 'levenpaths.com.ch', 'levenpaths.com.ci', 431 | 'levenpaths.com.ck', 'levenpaths.com.cl', 432 | 'levenpaths.com.cm', 'levenpaths.com.cn', 433 | 'levenpaths.com.co', 'levenpaths.com.cr', 434 | 'levenpaths.com.cu', 'levenpaths.com.cv', 435 | 'levenpaths.com.cw', 'levenpaths.com.cx', 436 | 'levenpaths.com.cy', 'levenpaths.com.cz', 437 | 'levenpaths.com.de', 'levenpaths.com.dj', 438 | 'levenpaths.com.dk', 'levenpaths.com.dm', 439 | 'levenpaths.com.do', 'levenpaths.com.dz', 440 | 'levenpaths.com.ec', 'levenpaths.com.ee', 441 | 'levenpaths.com.eg', 'levenpaths.com.er', 442 | 'levenpaths.com.es', 'levenpaths.com.et', 443 | 'levenpaths.com.eu', 'levenpaths.com.fi', 444 | 'levenpaths.com.fj', 'levenpaths.com.fk', 445 | 'levenpaths.com.fm', 'levenpaths.com.fo', 446 | 'levenpaths.com.fr', 'levenpaths.com.ga', 447 | 'levenpaths.com.gd', 'levenpaths.com.ge', 448 | 'levenpaths.com.gf', 'levenpaths.com.gg', 449 | 'levenpaths.com.gh', 'levenpaths.com.gi', 450 | 'levenpaths.com.gl', 'levenpaths.com.gm', 451 | 'levenpaths.com.gn', 'levenpaths.com.gp', 452 | 'levenpaths.com.gq', 'levenpaths.com.gr', 453 | 'levenpaths.com.gs', 'levenpaths.com.gt', 454 | 'levenpaths.com.gu', 'levenpaths.com.gw', 455 | 'levenpaths.com.gy', 'levenpaths.com.hk', 456 | 'levenpaths.com.hm', 'levenpaths.com.hn', 457 | 'levenpaths.com.hr', 'levenpaths.com.ht', 458 | 'levenpaths.com.hu'] 459 | 460 | self.assertEqual(subtraction(base, tlds, self.possibilities)[0:100], 461 | result) 462 | 463 | def test_adictions(self): 464 | base = 'elevenpaths' 465 | tlds = 'com.co' 466 | result = ['www-elevenpaths.com', 'www-elevenpaths-com.com', 467 | 'www-elevenpaths-com.com', 'www-elevenpaths-com.org', 468 | 'www-elevenpaths-com.net', 'www-elevenpaths-com.int', 469 | 'www-elevenpaths-com.edu', 'www-elevenpaths-com.gov', 470 | 'www-elevenpaths-com.mil', 'www-elevenpaths-com.arpa', 471 | 'www-elevenpaths-com.ac', 'www-elevenpaths-com.ad', 472 | 'www-elevenpaths-com.ae', 'www-elevenpaths-com.af', 473 | 'www-elevenpaths-com.ag', 'www-elevenpaths-com.ai', 474 | 'www-elevenpaths-com.al', 'www-elevenpaths-com.am', 475 | 'www-elevenpaths-com.ao', 'www-elevenpaths-com.aq', 476 | 'www-elevenpaths-com.ar', 'www-elevenpaths-com.as', 477 | 'www-elevenpaths-com.at', 'www-elevenpaths-com.au', 478 | 'www-elevenpaths-com.aw', 'www-elevenpaths-com.ax', 479 | 'www-elevenpaths-com.az', 'www-elevenpaths-com.ba', 480 | 'www-elevenpaths-com.bb', 'www-elevenpaths-com.bd', 481 | 'www-elevenpaths-com.be', 'www-elevenpaths-com.bf', 482 | 'www-elevenpaths-com.bg', 'www-elevenpaths-com.bh', 483 | 'www-elevenpaths-com.bi', 'www-elevenpaths-com.bj', 484 | 'www-elevenpaths-com.bm', 'www-elevenpaths-com.bn', 485 | 'www-elevenpaths-com.bo', 'www-elevenpaths-com.bq', 486 | 'www-elevenpaths-com.br', 'www-elevenpaths-com.bs', 487 | 'www-elevenpaths-com.bt', 'www-elevenpaths-com.bw', 488 | 'www-elevenpaths-com.by', 'www-elevenpaths-com.bz', 489 | 'www-elevenpaths-com.ca', 'www-elevenpaths-com.cc', 490 | 'www-elevenpaths-com.cd', 'www-elevenpaths-com.cf', 491 | 'www-elevenpaths-com.cg', 'www-elevenpaths-com.ch', 492 | 'www-elevenpaths-com.ci', 'www-elevenpaths-com.ck', 493 | 'www-elevenpaths-com.cl', 'www-elevenpaths-com.cm', 494 | 'www-elevenpaths-com.cn', 'www-elevenpaths-com.co', 495 | 'www-elevenpaths-com.cr', 'www-elevenpaths-com.cu', 496 | 'www-elevenpaths-com.cv', 'www-elevenpaths-com.cw', 497 | 'www-elevenpaths-com.cx', 'www-elevenpaths-com.cy', 498 | 'www-elevenpaths-com.cz', 'www-elevenpaths-com.de', 499 | 'www-elevenpaths-com.dj', 'www-elevenpaths-com.dk', 500 | 'www-elevenpaths-com.dm', 'www-elevenpaths-com.do', 501 | 'www-elevenpaths-com.dz', 'www-elevenpaths-com.ec', 502 | 'www-elevenpaths-com.ee', 'www-elevenpaths-com.eg', 503 | 'www-elevenpaths-com.er', 'www-elevenpaths-com.es', 504 | 'www-elevenpaths-com.et', 'www-elevenpaths-com.eu', 505 | 'www-elevenpaths-com.fi', 'www-elevenpaths-com.fj', 506 | 'www-elevenpaths-com.fk', 'www-elevenpaths-com.fm', 507 | 'www-elevenpaths-com.fo', 'www-elevenpaths-com.fr', 508 | 'www-elevenpaths-com.ga', 'www-elevenpaths-com.gd', 509 | 'www-elevenpaths-com.ge', 'www-elevenpaths-com.gf', 510 | 'www-elevenpaths-com.gg', 'www-elevenpaths-com.gh', 511 | 'www-elevenpaths-com.gi', 'www-elevenpaths-com.gl', 512 | 'www-elevenpaths-com.gm', 'www-elevenpaths-com.gn', 513 | 'www-elevenpaths-com.gp', 'www-elevenpaths-com.gq', 514 | 'www-elevenpaths-com.gr', 'www-elevenpaths-com.gs', 515 | 'www-elevenpaths-com.gt', 'www-elevenpaths-com.gu'] 516 | 517 | self.assertEqual(adictions(base, tlds, self.possibilities)[0:100], 518 | result) 519 | 520 | def test_repetition(self): 521 | base = 'elevenpaths' 522 | tlds = 'com' 523 | result = ['eelevenpaths.com', 'eelevenpaths.com', 524 | 'eelevenpaths.com.ac', 'eelevenpaths.com.ad', 525 | 'eelevenpaths.com.ae', 'eelevenpaths.com.af', 526 | 'eelevenpaths.com.ag', 'eelevenpaths.com.ai', 527 | 'eelevenpaths.com.al', 'eelevenpaths.com.am', 528 | 'eelevenpaths.com.ao', 'eelevenpaths.com.aq', 529 | 'eelevenpaths.com.ar', 'eelevenpaths.com.as', 530 | 'eelevenpaths.com.at', 'eelevenpaths.com.au', 531 | 'eelevenpaths.com.aw', 'eelevenpaths.com.ax', 532 | 'eelevenpaths.com.az', 'eelevenpaths.com.ba', 533 | 'eelevenpaths.com.bb', 'eelevenpaths.com.bd', 534 | 'eelevenpaths.com.be', 'eelevenpaths.com.bf', 535 | 'eelevenpaths.com.bg', 'eelevenpaths.com.bh', 536 | 'eelevenpaths.com.bi', 'eelevenpaths.com.bj', 537 | 'eelevenpaths.com.bm', 'eelevenpaths.com.bn', 538 | 'eelevenpaths.com.bo', 'eelevenpaths.com.bq', 539 | 'eelevenpaths.com.br', 'eelevenpaths.com.bs', 540 | 'eelevenpaths.com.bt', 'eelevenpaths.com.bw', 541 | 'eelevenpaths.com.by', 'eelevenpaths.com.bz', 542 | 'eelevenpaths.com.ca', 'eelevenpaths.com.cc', 543 | 'eelevenpaths.com.cd', 'eelevenpaths.com.cf', 544 | 'eelevenpaths.com.cg', 'eelevenpaths.com.ch', 545 | 'eelevenpaths.com.ci', 'eelevenpaths.com.ck', 546 | 'eelevenpaths.com.cl', 'eelevenpaths.com.cm', 547 | 'eelevenpaths.com.cn', 'eelevenpaths.com.co', 548 | 'eelevenpaths.com.cr', 'eelevenpaths.com.cu', 549 | 'eelevenpaths.com.cv', 'eelevenpaths.com.cw', 550 | 'eelevenpaths.com.cx', 'eelevenpaths.com.cy', 551 | 'eelevenpaths.com.cz', 'eelevenpaths.com.de', 552 | 'eelevenpaths.com.dj', 'eelevenpaths.com.dk', 553 | 'eelevenpaths.com.dm', 'eelevenpaths.com.do', 554 | 'eelevenpaths.com.dz', 'eelevenpaths.com.ec', 555 | 'eelevenpaths.com.ee', 'eelevenpaths.com.eg', 556 | 'eelevenpaths.com.er', 'eelevenpaths.com.es', 557 | 'eelevenpaths.com.et', 'eelevenpaths.com.eu', 558 | 'eelevenpaths.com.fi', 'eelevenpaths.com.fj', 559 | 'eelevenpaths.com.fk', 'eelevenpaths.com.fm', 560 | 'eelevenpaths.com.fo', 'eelevenpaths.com.fr', 561 | 'eelevenpaths.com.ga', 'eelevenpaths.com.gd', 562 | 'eelevenpaths.com.ge', 'eelevenpaths.com.gf', 563 | 'eelevenpaths.com.gg', 'eelevenpaths.com.gh', 564 | 'eelevenpaths.com.gi', 'eelevenpaths.com.gl', 565 | 'eelevenpaths.com.gm', 'eelevenpaths.com.gn', 566 | 'eelevenpaths.com.gp', 'eelevenpaths.com.gq', 567 | 'eelevenpaths.com.gr', 'eelevenpaths.com.gs', 568 | 'eelevenpaths.com.gt', 'eelevenpaths.com.gu', 569 | 'eelevenpaths.com.gw', 'eelevenpaths.com.gy', 570 | 'eelevenpaths.com.hk', 'eelevenpaths.com.hm', 571 | 'eelevenpaths.com.hn', 'eelevenpaths.com.hr', 572 | 'eelevenpaths.com.ht', 'eelevenpaths.com.hu'] 573 | 574 | self.assertEqual(repetition(base, tlds, self.possibilities)[0:100], 575 | result) 576 | 577 | def test_keyboard(self): 578 | base = 'elevenpaths' 579 | tlds = 'com' 580 | result = ['4elevenpaths.com', 'e4levenpaths.com', '4levenpaths.com', 581 | '4elevenpaths.com', 'e4levenpaths.com', '4levenpaths.com', 582 | '4elevenpaths.com.ac', 'e4levenpaths.com.ac', 583 | '4levenpaths.com.ac', '4elevenpaths.com.ad', 584 | 'e4levenpaths.com.ad', '4levenpaths.com.ad', 585 | '4elevenpaths.com.ae', 'e4levenpaths.com.ae', 586 | '4levenpaths.com.ae', '4elevenpaths.com.af', 587 | 'e4levenpaths.com.af', '4levenpaths.com.af', 588 | '4elevenpaths.com.ag', 'e4levenpaths.com.ag', 589 | '4levenpaths.com.ag', '4elevenpaths.com.ai', 590 | 'e4levenpaths.com.ai', '4levenpaths.com.ai', 591 | '4elevenpaths.com.al', 'e4levenpaths.com.al', 592 | '4levenpaths.com.al', '4elevenpaths.com.am', 593 | 'e4levenpaths.com.am', '4levenpaths.com.am', 594 | '4elevenpaths.com.ao', 'e4levenpaths.com.ao', 595 | '4levenpaths.com.ao', '4elevenpaths.com.aq', 596 | 'e4levenpaths.com.aq', '4levenpaths.com.aq', 597 | '4elevenpaths.com.ar', 'e4levenpaths.com.ar', 598 | '4levenpaths.com.ar', '4elevenpaths.com.as', 599 | 'e4levenpaths.com.as', '4levenpaths.com.as', 600 | '4elevenpaths.com.at', 'e4levenpaths.com.at', 601 | '4levenpaths.com.at', '4elevenpaths.com.au', 602 | 'e4levenpaths.com.au', '4levenpaths.com.au', 603 | '4elevenpaths.com.aw', 'e4levenpaths.com.aw', 604 | '4levenpaths.com.aw', '4elevenpaths.com.ax', 605 | 'e4levenpaths.com.ax', '4levenpaths.com.ax', 606 | '4elevenpaths.com.az', 'e4levenpaths.com.az', 607 | '4levenpaths.com.az', '4elevenpaths.com.ba', 608 | 'e4levenpaths.com.ba', '4levenpaths.com.ba', 609 | '4elevenpaths.com.bb', 'e4levenpaths.com.bb', 610 | '4levenpaths.com.bb', '4elevenpaths.com.bd', 611 | 'e4levenpaths.com.bd', '4levenpaths.com.bd', 612 | '4elevenpaths.com.be', 'e4levenpaths.com.be', 613 | '4levenpaths.com.be', '4elevenpaths.com.bf', 614 | 'e4levenpaths.com.bf', '4levenpaths.com.bf', 615 | '4elevenpaths.com.bg', 'e4levenpaths.com.bg', 616 | '4levenpaths.com.bg', '4elevenpaths.com.bh', 617 | 'e4levenpaths.com.bh', '4levenpaths.com.bh', 618 | '4elevenpaths.com.bi', 'e4levenpaths.com.bi', 619 | '4levenpaths.com.bi', '4elevenpaths.com.bj', 620 | 'e4levenpaths.com.bj', '4levenpaths.com.bj', 621 | '4elevenpaths.com.bm', 'e4levenpaths.com.bm', 622 | '4levenpaths.com.bm', '4elevenpaths.com.bn', 623 | 'e4levenpaths.com.bn', '4levenpaths.com.bn', 624 | '4elevenpaths.com.bo', 'e4levenpaths.com.bo', 625 | '4levenpaths.com.bo', '4elevenpaths.com.bq', 626 | 'e4levenpaths.com.bq', '4levenpaths.com.bq', 627 | '4elevenpaths.com.br', 'e4levenpaths.com.br', 628 | '4levenpaths.com.br', '4elevenpaths.com.bs'] 629 | 630 | self.assertEqual(keyboard(base, tlds, self.possibilities)[0:100], 631 | result) 632 | 633 | def test_replace(self): 634 | base = 'elevenpaths' 635 | tlds = 'com' 636 | result = ['clevenpaths.com', 'clevenpaths.com', 'clevenpaths.com.ac', 637 | 'clevenpaths.com.ad', 'clevenpaths.com.ae', 638 | 'clevenpaths.com.af', 'clevenpaths.com.ag', 639 | 'clevenpaths.com.ai', 'clevenpaths.com.al', 640 | 'clevenpaths.com.am', 'clevenpaths.com.ao', 641 | 'clevenpaths.com.aq', 'clevenpaths.com.ar', 642 | 'clevenpaths.com.as', 'clevenpaths.com.at', 643 | 'clevenpaths.com.au', 'clevenpaths.com.aw', 644 | 'clevenpaths.com.ax', 'clevenpaths.com.az', 645 | 'clevenpaths.com.ba', 'clevenpaths.com.bb', 646 | 'clevenpaths.com.bd', 'clevenpaths.com.be', 647 | 'clevenpaths.com.bf', 'clevenpaths.com.bg', 648 | 'clevenpaths.com.bh', 'clevenpaths.com.bi', 649 | 'clevenpaths.com.bj', 'clevenpaths.com.bm', 650 | 'clevenpaths.com.bn', 'clevenpaths.com.bo', 651 | 'clevenpaths.com.bq', 'clevenpaths.com.br', 652 | 'clevenpaths.com.bs', 'clevenpaths.com.bt', 653 | 'clevenpaths.com.bw', 'clevenpaths.com.by', 654 | 'clevenpaths.com.bz', 'clevenpaths.com.ca', 655 | 'clevenpaths.com.cc', 'clevenpaths.com.cd', 656 | 'clevenpaths.com.cf', 'clevenpaths.com.cg', 657 | 'clevenpaths.com.ch', 'clevenpaths.com.ci', 658 | 'clevenpaths.com.ck', 'clevenpaths.com.cl', 659 | 'clevenpaths.com.cm', 'clevenpaths.com.cn', 660 | 'clevenpaths.com.co', 'clevenpaths.com.cr', 661 | 'clevenpaths.com.cu', 'clevenpaths.com.cv', 662 | 'clevenpaths.com.cw', 'clevenpaths.com.cx', 663 | 'clevenpaths.com.cy', 'clevenpaths.com.cz', 664 | 'clevenpaths.com.de', 'clevenpaths.com.dj', 665 | 'clevenpaths.com.dk', 'clevenpaths.com.dm', 666 | 'clevenpaths.com.do', 'clevenpaths.com.dz', 667 | 'clevenpaths.com.ec', 'clevenpaths.com.ee', 668 | 'clevenpaths.com.eg', 'clevenpaths.com.er', 669 | 'clevenpaths.com.es', 'clevenpaths.com.et', 670 | 'clevenpaths.com.eu', 'clevenpaths.com.fi', 671 | 'clevenpaths.com.fj', 'clevenpaths.com.fk', 672 | 'clevenpaths.com.fm', 'clevenpaths.com.fo', 673 | 'clevenpaths.com.fr', 'clevenpaths.com.ga', 674 | 'clevenpaths.com.gd', 'clevenpaths.com.ge', 675 | 'clevenpaths.com.gf', 'clevenpaths.com.gg', 676 | 'clevenpaths.com.gh', 'clevenpaths.com.gi', 677 | 'clevenpaths.com.gl', 'clevenpaths.com.gm', 678 | 'clevenpaths.com.gn', 'clevenpaths.com.gp', 679 | 'clevenpaths.com.gq', 'clevenpaths.com.gr', 680 | 'clevenpaths.com.gs', 'clevenpaths.com.gt', 681 | 'clevenpaths.com.gu', 'clevenpaths.com.gw', 682 | 'clevenpaths.com.gy', 'clevenpaths.com.hk', 683 | 'clevenpaths.com.hm', 'clevenpaths.com.hn', 684 | 'clevenpaths.com.hr', 'clevenpaths.com.ht', 685 | 'clevenpaths.com.hu'] 686 | 687 | self.assertEqual(replace(base, tlds, self.possibilities)[0:100], 688 | result) 689 | 690 | def test_levenshtein(self): 691 | base = 'elevenpaths' 692 | tlds = 'com' 693 | result = ['alevenpaths.com', 'blevenpaths.com', 'clevenpaths.com', 694 | 'dlevenpaths.com', 'flevenpaths.com', 'glevenpaths.com', 695 | 'hlevenpaths.com', 'ilevenpaths.com', 'jlevenpaths.com', 696 | 'klevenpaths.com', 'llevenpaths.com', 'mlevenpaths.com', 697 | 'nlevenpaths.com', 'olevenpaths.com', 'plevenpaths.com', 698 | 'qlevenpaths.com', 'rlevenpaths.com', 'slevenpaths.com', 699 | 'tlevenpaths.com', 'ulevenpaths.com', 'vlevenpaths.com', 700 | 'wlevenpaths.com', 'xlevenpaths.com', 'ylevenpaths.com', 701 | 'zlevenpaths.com', 'eaevenpaths.com', 'ebevenpaths.com', 702 | 'ecevenpaths.com', 'edevenpaths.com', 'eeevenpaths.com', 703 | 'efevenpaths.com', 'egevenpaths.com', 'ehevenpaths.com', 704 | 'eievenpaths.com', 'ejevenpaths.com', 'ekevenpaths.com', 705 | 'emevenpaths.com', 'enevenpaths.com', 'eoevenpaths.com', 706 | 'epevenpaths.com', 'eqevenpaths.com', 'erevenpaths.com', 707 | 'esevenpaths.com', 'etevenpaths.com', 'euevenpaths.com', 708 | 'evevenpaths.com', 'ewevenpaths.com', 'exevenpaths.com', 709 | 'eyevenpaths.com', 'ezevenpaths.com', 'elavenpaths.com', 710 | 'elbvenpaths.com', 'elcvenpaths.com', 'eldvenpaths.com', 711 | 'elfvenpaths.com', 'elgvenpaths.com', 'elhvenpaths.com', 712 | 'elivenpaths.com', 'eljvenpaths.com', 'elkvenpaths.com', 713 | 'ellvenpaths.com', 'elmvenpaths.com', 'elnvenpaths.com', 714 | 'elovenpaths.com', 'elpvenpaths.com', 'elqvenpaths.com', 715 | 'elrvenpaths.com', 'elsvenpaths.com', 'eltvenpaths.com', 716 | 'eluvenpaths.com', 'elvvenpaths.com', 'elwvenpaths.com', 717 | 'elxvenpaths.com', 'elyvenpaths.com', 'elzvenpaths.com', 718 | 'eleaenpaths.com', 'elebenpaths.com', 'elecenpaths.com', 719 | 'eledenpaths.com', 'eleeenpaths.com', 'elefenpaths.com', 720 | 'elegenpaths.com', 'elehenpaths.com', 'eleienpaths.com', 721 | 'elejenpaths.com', 'elekenpaths.com', 'elelenpaths.com', 722 | 'elemenpaths.com', 'elenenpaths.com', 'eleoenpaths.com', 723 | 'elepenpaths.com', 'eleqenpaths.com', 'elerenpaths.com', 724 | 'elesenpaths.com', 'eletenpaths.com', 'eleuenpaths.com', 725 | 'elewenpaths.com', 'elexenpaths.com', 'eleyenpaths.com', 726 | 'elezenpaths.com'] 727 | 728 | self.assertEqual(distance_levenshtein(base, tlds, self.possibilities)[0:100], 729 | result) 730 | 731 | 732 | if __name__ == "__main__": 733 | unittest.main() 734 | -------------------------------------------------------------------------------- /test/test_querys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import unittest 5 | 6 | from querys.doh import dns_doh 7 | from querys.udp import dns_udp 8 | from querys.bdns import dns_bdns 9 | 10 | 11 | class TestTypoDetect(unittest.TestCase): 12 | maxDiff = None 13 | 14 | def setUp(self): 15 | self.domain = 'elevenpaths.com' 16 | self.threat = 0 17 | 18 | def test_dns_doh(self): 19 | domain = ['northnovacable.ca', 'telefonica.com'] 20 | result = [{ 21 | 0: { 22 | 'report_DoH': 'Malware', 23 | 'domain': 'northnovacable.ca', 24 | 'A': '', 25 | 'MX': ''}}, { 26 | 1: { 27 | 'report_DoH': 'Good', 28 | 'domain': 'telefonica.com', 29 | 'A': ['212.170.36.79'], 30 | 'MX': ['telefonicacorp.mail.protection.outlook.com.']}}] 31 | 32 | for d in domain: 33 | self.assertDictEqual(dns_doh(d, domain.index(d)), 34 | result[domain.index(d)]) 35 | 36 | def test_dns_udp(self): 37 | result = { 38 | 0: { 39 | 'report_DoH': 'Good', 40 | 'domain': self.domain, 41 | 'A': ['52.212.36.140'], 42 | 'MX': ['elevenpaths-com.mail.protection.outlook.com.']}} 43 | 44 | self.assertDictEqual(dns_udp(self.domain, self.threat), result) 45 | 46 | def test_dns_bdns(self): 47 | domain = ['eagletv.coin', self.domain] 48 | result = [{ 49 | 0: { 50 | 'report_DoH': '', 51 | 'domain': 'eagletv.coin', 52 | 'A': ['192.243.100.192'], 53 | 'MX': ''}}, {}] 54 | 55 | for d in domain: 56 | self.assertEqual(dns_bdns(d, self.threat), result[domain.index(d)]) 57 | 58 | 59 | if __name__ == "__main__": 60 | unittest.main() 61 | -------------------------------------------------------------------------------- /typodetect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ script principal del sistema""" 4 | 5 | import os 6 | 7 | from colorama import Fore 8 | from colorama import Style 9 | 10 | from files.txt_file import files_txt 11 | from files.json_file import files_json 12 | from auxiliars.worker import process 13 | from auxiliars.update import updating 14 | from auxiliars.screen import screen_print 15 | from auxiliars.constants import b 16 | from auxiliars.constants import warning 17 | from auxiliars.arguments import arguments 18 | from auxiliars.generator import generator 19 | from auxiliars.constants import separator 20 | from auxiliars.normalization import normalization 21 | 22 | 23 | def main(): 24 | 25 | args = arguments() 26 | if args[1].upper() == 'Y': 27 | updating() 28 | 29 | os.system('cls' if os.name == 'nt' else 'clear') 30 | print(Fore.GREEN + Style.BRIGHT + b) 31 | print(Fore.RED + Style.BRIGHT + separator) 32 | print(Fore.RED + Style.BRIGHT + warning) 33 | print(Fore.RED + Style.BRIGHT + separator) 34 | print(Fore.RESET + Style.RESET_ALL) 35 | parts = normalization(args[0]) 36 | print(Fore.GREEN + Style.BRIGHT + '[*] Creating mutations') 37 | print(Fore.GREEN + Style.BRIGHT + separator) 38 | print(Fore.RESET + Style.RESET_ALL) 39 | possibilities = generator(parts) 40 | print('\n' + Fore.GREEN + Style.BRIGHT + '[*] Testing if ' 41 | + str(len(possibilities)) + ' mutations exist') 42 | print(Fore.GREEN + Style.BRIGHT + separator) 43 | print(Fore.RESET + Style.RESET_ALL) 44 | 45 | result = process(args[3], possibilities, args[4]) 46 | 47 | i = 0 48 | while i < (len(list(result.keys()))): 49 | result[str(i)] = result.pop(list(result.keys())[0]) 50 | i += 1 51 | 52 | screen_print(args[0], len(possibilities), result, args[4]) 53 | 54 | if args[2].upper() == 'TXT': 55 | files_txt(result, args[0], len(possibilities)) 56 | else: 57 | files_json(result, args[0]) 58 | 59 | 60 | if __name__ == '__main__': 61 | main() 62 | --------------------------------------------------------------------------------