├── .gitignore ├── README.md ├── dnp.py ├── requirements.txt ├── rules ├── predictor-default.cfg ├── predictor-simple.cfg └── regular.cfg └── showcase.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea 3 | *.iml 4 | sortcfg.py 5 | *.pyc 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dnp — domain name predictor 2 | [![Python 2&3](https://img.shields.io/badge/python-2.7&3.4-brightgreen.svg)](https://www.python.org/) 3 | 4 | 5 | 6 | > 一个简单的现代化公司域名使用规律预测及生成工具 7 | > 8 | > A simple modernized enterprise domain name predictor and generator 9 | 10 | 11 | 12 | ## Snapshot 13 | 14 | ![](showcase.png) 15 | 16 | 17 | 18 | ## Q&A 19 | 20 | - 什么叫 "**现代化**" 公司? 21 | 22 | 我个人主观判断上的不成熟定义,就是公司整体 IT 基础设施和架构设计完善,会使用微服务、协同开发、自动化测试、自动化打包发布、自动化部署、自动化日志收集和自动化运维监控等多项 "现代化" 的技术解决高并发等较大体量业务问题的公司; 23 | 24 | 这些公司或组织团体一般有较多业务,以互联网领域、近些年新成立的公司居多,域名命名及分配使用比较规范。 25 | 26 | 27 | 28 | - 什么是**域名预测**? 29 | 30 | 简答来讲就是基于 "现代化" 公司比较规范的域名使用规律已经使用的新技术架构,在已知某个域名后,预测该域名可能有哪些变体形式的域名。 31 | 32 | 举一个简单的例子: 33 | 34 | 已知 A 公司有一个域名 `shoot.A.com`,那么对应的接口服务域名可能是 `api.shoot.A.com`、 `shoot.restful-api.A.com`、 `shoot-api.A.com` 等; 35 | 36 | 测试、预发等不同环境的域名可能是 37 | 38 | `shoot-api.test.A.com` 、 `test.api.shoot.A.com` 、 `pre.shoot-api.A.com` 等; 39 | 40 | 对应的不同环境的管理监控域名可能是 `shoot-monitor.dev.A.com` 、`shoot-dev-monitor.A.com` 、`st1.shoot-dashboard.A.com` 等; 41 | 42 | 对应不同负载代理的域名可能是 `shoot-api.corp.A.com` 、 `api.shoot.internal.A.com` 等; 43 | 44 | 对应的后端 api 服务生产环境的域名可能是 `backend-api.prod.shoot.A.com`、 `backend-api-prod.shoot.A.com`等。 45 | 46 | 当然,在缺少域名前缀,仅知道域名为 `A.com` 时,也可以按照此规律直接进行预测。 47 | 48 | 49 | 50 | - 为什么要写这个工具? 51 | 52 | 随着对许多 "现代化" 业务的接触和实际渗透测试,我发现在域名的探测这个很小的领域中,现有的子域名爆破、第三方服务接口查询都不能很好的覆盖到 **域名预测** 这个概念。 53 | 54 | 这样当你得到 `shoot.A.com` 域名后,很可能会遗漏上面举例中的相关重要域名,导致 "**灯下黑**"。 55 | 56 | 57 | 58 | - 这个工具可以干什么? 59 | 60 | 按照配置文件和生成规则来完成上述的**域名预测**,生成完整的域名字典。 61 | 62 | 目前一个域名在 `simple` 规则下大概生成 **6w—7w** 左右个域名,在 `default` 规则下生成 **26w—29w** 个域名。 63 | 64 | 生成完域名后可以用支持完整域名验证的工具去验证域名是否存在,比如使用 [ksubdomain](https://github.com/knownsec/ksubdomain) 命令 `subdomain -f predictor-domains.txt -verify` 。 65 | 66 | 67 | 68 | ## Download 69 | 70 | ``` 71 | git clone https://www.github.com/landgrey/domainNamePredictor.git 72 | cd domainNamePredictor/ 73 | pip install -r requirements.txt 74 | chmod +x dnp.py 75 | python dnp.py 76 | ``` 77 | 78 | 79 | 80 | ## Usage 81 | 82 | ``` 83 | python dnp.py -d A.com 84 | python dnp.py -f A.com-domains.txt -m simple 85 | python dnp.py -d demo.A.com -m simple -o /tmp/predictor-a.com.txt 86 | ``` 87 | 88 | ## 相似项目 89 | https://github.com/codingo/DNSCewl 90 | 91 | https://github.com/infosec-au/altdns 92 | 93 | https://github.com/Josue87/gotator 94 | 95 | https://github.com/bp0lr/dmut 96 | 97 | https://github.com/ProjectAnte/dnsgen 98 | 99 | -------------------------------------------------------------------------------- /dnp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | # A simple modernized enterprise domain name predictor and generator 4 | # 5 | # Build By LandGrey 6 | # 7 | 8 | import os 9 | import sys 10 | import time 11 | import argparse 12 | import itertools 13 | from tld import get_tld 14 | try: 15 | import ConfigParser 16 | except ImportError as e: 17 | import configparser as ConfigParser 18 | 19 | 20 | def guess_main_domain(name): 21 | tld = get_tld(name, fix_protocol=True) 22 | top_domain = name[:-len(tld) - 1].split(".")[-1] + "." + tld 23 | return top_domain 24 | 25 | 26 | def unique(seq, idfun=None): 27 | if idfun is None: 28 | def idfun(x): return x 29 | seen = {} 30 | results = [] 31 | for item in seq: 32 | marker = idfun(item) 33 | if marker in seen: 34 | continue 35 | seen[marker] = 1 36 | results.append(item) 37 | return results 38 | 39 | 40 | def awesome_factory(join_string, elements, mix_join=None): 41 | element_number = 3 if len(elements) >= 3 else 2 42 | for length in range(2, element_number + 1): 43 | for x in itertools.combinations(elements, length): 44 | for y in itertools.product(*x): 45 | for z in itertools.permutations(y): 46 | yield join_string.join(z) 47 | if mix_join and len(z) >= 3: 48 | yield join_string.join(z[:-1]) + mix_join + z[-1] 49 | yield z[0] + mix_join + join_string.join(z[1:]) 50 | 51 | 52 | def read_all_domain_names(content): 53 | init_domain_names = [] 54 | 55 | if os.path.isfile(content): 56 | with open(content, 'r') as f: 57 | for name in f.readlines(): 58 | name = name.strip() 59 | if name: 60 | init_domain_names.append(name) 61 | 62 | return init_domain_names 63 | 64 | 65 | def get_configuration(mode): 66 | config_dict = { 67 | 'environment': [], 68 | 'version': [], 69 | 'role': [], 70 | 'technology': [], 71 | 'service': [], 72 | 'monitor': [], 73 | 'time': [], 74 | 'space': [], 75 | 'area': [], 76 | 'proxy': [], 77 | 'number': [], 78 | 'application': [] 79 | } 80 | regular_path = os.path.join(current_dir, "rules", "regular.cfg") 81 | 82 | if mode: 83 | cfg_path = os.path.join(current_dir, "rules", "predictor-{}.cfg".format(mode)) 84 | else: 85 | cfg_path = os.path.join(current_dir, "rules", "predictor-default.cfg") 86 | 87 | for cfg in [regular_path, cfg_path]: 88 | try: 89 | config = ConfigParser.ConfigParser(allow_no_value=True) 90 | config.optionxform = str 91 | config.read(cfg) 92 | for s in config.sections(): 93 | for o in config.options(s): 94 | config_dict[s].append(o) 95 | except Exception as e: 96 | exit("[-] parse config file: {} error".format(cfg)) 97 | return config_dict 98 | 99 | 100 | def name_filter(name, original_domain, domain_prefix): 101 | js_chunk = [] 102 | if "-" in name: 103 | for v1 in name.split("."): 104 | for v2 in v1.split("-"): 105 | js_chunk.append(v2) 106 | else: 107 | js_chunk = name.split(".") 108 | 109 | name_length = len(name) 110 | js_chunk_length = len(js_chunk) 111 | 112 | if js_chunk_length >= 3: 113 | # drop aa.bb.cc/aa-bb-cc/aa-bb.cc/aa.bb-cc too short name 114 | if name_length <= (js_chunk_length * 2 + js_chunk_length - 1): 115 | return None 116 | # drop aaaaaa-bbbbbb-cccccc too long name 117 | if name.count("-") >= js_chunk_length - 1 and name_length >= (js_chunk_length * 6 + js_chunk_length - 1): 118 | return None 119 | # drop aaaaaaaa./-bbbbbbbb./-cccccccc too long name 120 | if name_length >= (js_chunk_length * 8 + js_chunk_length - 1): 121 | return None 122 | 123 | if domain_prefix: 124 | if domain_prefix in js_chunk: 125 | if len(js_chunk) <= 3: 126 | return name + "." + original_domain[len(domain_prefix) + 1:] 127 | else: 128 | return name + "." + original_domain 129 | else: 130 | return name + "." + original_domain 131 | return None 132 | 133 | 134 | def get_main_domain_similar_domain_names(main_domain_name, config): 135 | results = [] 136 | 137 | environment = config['environment'] 138 | role = config['role'] 139 | technology = config['technology'] 140 | service = config['service'] 141 | proxy = config['proxy'] 142 | version = config['version'] 143 | monitor = config['monitor'] 144 | time = config['time'] 145 | space = config['space'] 146 | area = config['area'] 147 | application = config['application'] 148 | 149 | small_lists = [environment, role, technology, service, monitor, proxy] 150 | all_lists = small_lists[:] 151 | for ex in [version, time, space, area, application]: 152 | all_lists.append(ex) 153 | 154 | for one_lists in all_lists: 155 | for item in one_lists: 156 | results.append(item + "." + main_domain_name) 157 | 158 | for js in [".", "-"]: 159 | for name in awesome_factory(js, small_lists): 160 | nf = name_filter(name, main_domain_name, None) 161 | if nf: 162 | results.append(nf) 163 | 164 | for name in awesome_factory("-", small_lists, mix_join="."): 165 | nf = name_filter(name, main_domain_name, None) 166 | if nf: 167 | results.append(nf) 168 | 169 | return results 170 | 171 | 172 | def get_normal_domain_similar_domain_names(domain_name, config): 173 | results = [] 174 | 175 | environment = config['environment'] 176 | role = config['role'] 177 | technology = config['technology'] 178 | service = config['service'] 179 | monitor = config['monitor'] 180 | proxy = config['proxy'] 181 | 182 | prefix = domain_name.split(".")[0] 183 | small_lists = [[prefix], environment, role, technology, service, monitor, proxy] 184 | 185 | for js in [".", "-"]: 186 | for name in awesome_factory(js, small_lists): 187 | nf = name_filter(name, domain_name, prefix) 188 | if nf: 189 | results.append(nf) 190 | 191 | for name in awesome_factory("-", small_lists, mix_join="."): 192 | nf = name_filter(name, domain_name, prefix) 193 | if nf: 194 | results.append(nf) 195 | 196 | return results 197 | 198 | 199 | def get_single_similar_domain_names(original_domain, predictor_mode): 200 | config = get_configuration(mode=predictor_mode) 201 | main_domain = guess_main_domain(original_domain) 202 | is_main_domain = True if original_domain == main_domain else False 203 | if is_main_domain: 204 | return get_main_domain_similar_domain_names(main_domain, config) 205 | else: 206 | return get_normal_domain_similar_domain_names(original_domain, config) 207 | 208 | 209 | def printer(_predictor_mode, _output_path, _begin_time, _count): 210 | print("[+] current mode: [{0}]\n" 211 | "[+] A total of : {1:} lines\n" 212 | "[+] Store in : {2} \n" 213 | "[+] Cost : {3} seconds".format(_predictor_mode, _count, _output_path, str(time.time() - _begin_time)[:6])) 214 | 215 | 216 | if __name__ == "__main__": 217 | begin_time = time.time() 218 | ascii_banner = r''' 219 | _ _ 220 | (.)_(.) 221 | _ ( _ ) _ 222 | / \/`-----'\/ \ 223 | __\ ( ( ) ) /__ 224 | ) /\ \._./ /\ ( 225 | )_/ /|\ /|\ \_( 226 | dnp.py 227 | ''' 228 | 229 | try: 230 | current_dir = os.path.dirname(os.path.join(os.path.abspath(sys.argv[0]))).encode('utf-8').decode() 231 | except UnicodeError: 232 | try: 233 | current_dir = os.path.dirname(os.path.abspath(sys.argv[0])).decode('utf-8') 234 | except UnicodeError: 235 | current_dir = "." 236 | exit('[*] Please move dnp.py script to full ascii path, than apply it') 237 | output_path = os.path.join(current_dir, 'results') 238 | if not os.path.exists(output_path): 239 | os.mkdir(output_path) 240 | 241 | print(ascii_banner) 242 | parser = argparse.ArgumentParser() 243 | parser.add_argument('-d', dest='domain_name', default='', help='single domain name') 244 | parser.add_argument('-f', dest='file_path', default='', help='domain names file path') 245 | parser.add_argument('-m', dest='predictor_mode', default='default', choices=['default', 'simple'], help='choose predictor mode: [default, simple]') 246 | parser.add_argument('-o', '--output', dest='output', default='', help='result output path') 247 | if len(sys.argv) == 1: 248 | sys.argv.append('-h') 249 | args = parser.parse_args() 250 | 251 | input_name = args.domain_name 252 | input_file = args.file_path 253 | predictor_mode = args.predictor_mode 254 | output_path = args.output \ 255 | if args.output else os.path.join(output_path, (input_name if input_name else str(begin_time)[4:10]) + "-" + predictor_mode + ".txt") 256 | 257 | count = 0 258 | with open(output_path, 'w') as f: 259 | if input_name: 260 | for x in unique(get_single_similar_domain_names(input_name, predictor_mode)): 261 | count += 1 262 | f.write(x + "\n") 263 | else: 264 | join_results = [] 265 | for ns in read_all_domain_names(input_file): 266 | join_results.extend(get_single_similar_domain_names(ns, predictor_mode)) 267 | for x in unique(join_results): 268 | count += 1 269 | f.write(x + "\n") 270 | 271 | printer(predictor_mode, output_path, begin_time, count) 272 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | tld 2 | -------------------------------------------------------------------------------- /rules/predictor-default.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # this is predictor-default configuration file 3 | # 4 | # 5 | 6 | 7 | [environment] 8 | dev 9 | pre 10 | prepare 11 | test 12 | test1 13 | t1 14 | staging 15 | st 16 | st1 17 | prd 18 | pro 19 | prod 20 | p1 21 | pr 22 | uat 23 | fat 24 | sit 25 | 26 | 27 | [role] 28 | qa 29 | qa1 30 | qa3 31 | front 32 | frontend 33 | fe 34 | backend 35 | be 36 | 37 | 38 | [technology] 39 | api 40 | apis 41 | 42 | 43 | [service] 44 | rest 45 | restful 46 | html5 47 | h5 48 | web 49 | app 50 | apps 51 | wx 52 | weixin 53 | mobile 54 | m 55 | wap 56 | 57 | 58 | [monitor] 59 | dc 60 | admin 61 | monitor 62 | manager 63 | dashboard 64 | management 65 | 66 | 67 | [proxy] 68 | proxy 69 | corp 70 | internal 71 | cluster 72 | cluster1 73 | lb 74 | nginx 75 | ng 76 | gateway 77 | gw 78 | gy -------------------------------------------------------------------------------- /rules/predictor-simple.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # this is predictor-simple configuration file 3 | # 4 | # 5 | 6 | 7 | [environment] 8 | dev 9 | pre 10 | test 11 | t1 12 | staging 13 | st 14 | st1 15 | pro 16 | prod 17 | uat 18 | fat 19 | 20 | 21 | [role] 22 | qa 23 | fe 24 | backend 25 | be 26 | 27 | 28 | [technology] 29 | api 30 | apis 31 | 32 | 33 | [service] 34 | rest 35 | html5 36 | h5 37 | web 38 | app 39 | apps 40 | wx 41 | weixin 42 | m 43 | 44 | 45 | [monitor] 46 | monitor 47 | dashboard 48 | 49 | 50 | [proxy] 51 | proxy 52 | corp 53 | internal 54 | lb 55 | nginx 56 | gateway 57 | -------------------------------------------------------------------------------- /rules/regular.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | [time] 4 | preview 5 | previous 6 | new 7 | new1 8 | old 9 | 10 | 11 | [space] 12 | east 13 | south 14 | west 15 | north 16 | southeast 17 | northwest 18 | es 19 | nt 20 | tx 21 | tencent 22 | ali 23 | aliyun 24 | aws 25 | center 26 | 27 | 28 | [area] 29 | huadong 30 | hd 31 | huaxi 32 | hx 33 | huanan 34 | hn 35 | huabei 36 | hb 37 | japan 38 | jp 39 | hongkong 40 | hk 41 | shanghai 42 | sh 43 | beijing 44 | bj 45 | us 46 | 47 | 48 | [version] 49 | demo 50 | alpha 51 | beta 52 | stable 53 | release 54 | ga 55 | rc 56 | 57 | 58 | [number] 59 | 1 60 | 2 61 | 3 62 | 01 63 | 02 64 | 03 65 | v1 66 | v2 67 | v3 68 | 69 | 70 | [application] 71 | dc 72 | es 73 | h5 74 | mq 75 | oa 76 | uc 77 | zk 78 | api 79 | apm 80 | bbs 81 | biw 82 | bot 83 | bus 84 | cat 85 | cms 86 | crm 87 | dc1 88 | doc 89 | ec2 90 | efk 91 | elk 92 | gce 93 | git 94 | hub 95 | job 96 | jpa 97 | jwt 98 | k8s 99 | lib 100 | log 101 | mbs 102 | mgt 103 | mvc 104 | nms 105 | pan 106 | pay 107 | pod 108 | rpc 109 | scm 110 | srv 111 | sso 112 | svn 113 | tms 114 | wms 115 | www 116 | amqp 117 | apis 118 | app1 119 | apps 120 | auth 121 | avro 122 | blog 123 | boot 124 | cicd 125 | data 126 | docs 127 | file 128 | flex 129 | gocd 130 | gogs 131 | good 132 | grid 133 | guns 134 | hdfs 135 | hive 136 | kube 137 | ldap 138 | live 139 | logs 140 | mail 141 | mqtt 142 | nifi 143 | node 144 | note 145 | open 146 | pipe 147 | pods 148 | repo 149 | shop 150 | show 151 | solr 152 | team 153 | tsdb 154 | user 155 | wiki 156 | work 157 | zuul 158 | admin 159 | apiv1 160 | apiv2 161 | apiv3 162 | apiv4 163 | apiv5 164 | app01 165 | azure 166 | batch 167 | beats 168 | cacti 169 | camel 170 | chaos 171 | drone 172 | dubbo 173 | event 174 | feign 175 | flink 176 | flume 177 | geode 178 | gitea 179 | goods 180 | graph 181 | group 182 | habor 183 | hbase 184 | html5 185 | infra 186 | kafka 187 | kylin 188 | label 189 | maven 190 | mesos 191 | micro 192 | minio 193 | nacos 194 | neo4j 195 | nerve 196 | nexus 197 | node1 198 | oauth 199 | oozie 200 | redis 201 | route 202 | scala 203 | spark 204 | sqoop 205 | stack 206 | store 207 | storm 208 | webui 209 | api-v1 210 | api-v2 211 | api-v3 212 | api-v4 213 | api-v5 214 | center 215 | client 216 | consul 217 | devops 218 | docker 219 | eureka 220 | falcon 221 | galaxy 222 | github 223 | gitlab 224 | goblin 225 | gradle 226 | group1 227 | hadoop 228 | harbor 229 | influx 230 | kibana 231 | lcinga 232 | logapi 233 | logger 234 | manage 235 | mobile 236 | nagios 237 | node01 238 | oauth2 239 | office 240 | pgraph 241 | portal 242 | ribbon 243 | router 244 | scribe 245 | search 246 | server 247 | sleuth 248 | spark1 249 | splunk 250 | spring 251 | stream 252 | syslog 253 | sysmon 254 | tracer 255 | travis 256 | triton 257 | tuning 258 | web-ui 259 | weblog 260 | zabbix 261 | zipkin 262 | airflow 263 | akumuli 264 | ansible 265 | bigdata 266 | breaker 267 | brogmon 268 | catalog 269 | circuit 270 | content 271 | control 272 | datadog 273 | diagram 274 | elastic 275 | eureka1 276 | fluentd 277 | gateway 278 | gemfire 279 | grafana 280 | hystrix 281 | invoker 282 | jenkins 283 | jupyter 284 | kinesis 285 | library 286 | logging 287 | manager 288 | meeting 289 | metrics 290 | monitor 291 | netdata 292 | netflix 293 | nodered 294 | payment 295 | pushapi 296 | recruit 297 | restapi 298 | restful 299 | rsyslog 300 | service 301 | storage 302 | tracing 303 | turbine 304 | webflow 305 | activemq 306 | actuator 307 | cadvisor 308 | collectd 309 | contract 310 | dataflow 311 | elkstack 312 | exporter 313 | filebeat 314 | graphite 315 | heapster 316 | influxdb 317 | librenms 318 | logstash 319 | marathon 320 | node-red 321 | opentsdb 322 | pipeline 323 | platform 324 | push-api 325 | rabbitmq 326 | schedule 327 | searcher 328 | sentinel 329 | tracking 330 | training 331 | analytics 332 | atlassian 333 | cassandra 334 | community 335 | dashboard 336 | developer 337 | discovery 338 | dockerhub 339 | dzzoffice 340 | elk-stack 341 | hostgroup 342 | kubernete 343 | logsearch 344 | mapreduce 345 | office365 346 | openstack 347 | pagerduty 348 | serverset 349 | terraform 350 | websocket 351 | zookeeper 352 | clickhouse 353 | cloudwatch 354 | confluence 355 | dashboards 356 | datacenter 357 | dispatcher 358 | hostgroup1 359 | kube-state 360 | kubernetes 361 | management 362 | openfalcon 363 | prometheus 364 | servicelog 365 | skywalking 366 | usercenter 367 | api-gateway 368 | data-center 369 | eureka-zuul 370 | kube-status 371 | loganalysis 372 | open-falcon 373 | opentracing 374 | pushgateway 375 | recruitment 376 | restful-api 377 | service-log 378 | serviceslog 379 | system-cube 380 | user-center 381 | alertmanager 382 | apis-gateway 383 | eureka-admin 384 | grafana-kong 385 | nacos-config 386 | push-gateway 387 | rest-gateway 388 | services-log 389 | zuul-gateway 390 | consul-config 391 | elasticsearch 392 | eureka-client 393 | eureka-server 394 | node-exporter 395 | kong-dashboard 396 | kylin-dashboard 397 | restful-gateway 398 | grafana-dashboard 399 | kylin-system-cube 400 | grafana-management 401 | -------------------------------------------------------------------------------- /showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LandGrey/domainNamePredictor/b5bc60321e3f54285465a38fa8124f5500305f25/showcase.png --------------------------------------------------------------------------------