-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzScan.py
141 lines (124 loc) · 5.81 KB
/
zScan.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python3
import argparse
import json
import os
import textwrap
from contextlib import suppress
from datetime import datetime
from alive_progress import alive_bar
from dns import resolver
import signal
import sys
from rich import print, print_json
# Global variables
subdomains_found = []
scan_StartTime = datetime.now()
# We parse the required commandline arguments
parser = argparse.ArgumentParser(description='''
─▌ zScan is a Quick Subdomain Scanner created by Tzero86 ▐─
''',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent('''Scan Examples:
zScan.py -sd google.com
zScan.py -sd domain.com -o output.json
zScan.py -sd domain.com -sl custom_subdoms.txt
zScan.py -sd domain.com -sl custom_subdoms.txt -o results/test.json
'''))
parser.add_argument('-sd', '--domain', help='Single Domain to enumerate', required=True)
parser.add_argument('-dl', '--domlist', help='Custom domain file to use', required=False)
parser.add_argument('-sl', '--sublist', help='Custom subdomains file to use', required=False)
parser.add_argument('-o', '--output', help='Output file', required=False)
args = parser.parse_args()
domain = args.domain
custom_sublist = args.sublist
custom_domlist = args.domlist
output_file = args.output
# a function to clear the terminal screen
def clear_screen():
if sys.platform == 'win32':
os.system('cls')
else:
os.system('clear')
# we load the domains file and return a list with all the subdomains
def load_subdoms():
if custom_sublist:
# if the user provided a custom subdomains file, we load that file and return a list with all the subdomains
with open(custom_sublist, 'r') as f:
subdomains = f.read().splitlines()
return subdomains
else:
# if the user does not provides a custom list, we use the seclists.org subdomain list
with open('./lists/subdomains-top1million-110000.txt', 'r') as f:
filecontents = f.read()
subdoms = filecontents.splitlines()
return subdoms
# here we take care of scanning each subdomain and checking if it's alive
def scan_subdomains():
subdomains = load_subdoms()
print(f'[*] Starting to scan [cyan]{domain}[/] for valid subdomains... ')
total = len(subdomains)
print(f'[!] A total of [cyan]{total}[/] subdomains will be scanned. [bold]Please be patient![/]')
print(f'[!] You can press [bold][cyan]CRTL+C[/][/] at any time to terminate the scan and save the results.')
with alive_bar(total, spinner='dots', length=12, theme='smooth') as bar:
for subdomain in subdomains:
bar.title = f'[*] Scanning: {domain}'
bar.text(f'Testing {subdomain}.{domain}')
# we suppress the exceptions that might occur
with suppress(resolver.NXDOMAIN, resolver.NoAnswer, resolver.Timeout, resolver.NoNameservers):
# we use the dns.resolver library to check if the subdomain is alive
if resolver.resolve(f'{subdomain}.{domain}', 'A').response.answer:
# if the subdomain is alive, we add it to the list of subdomains found
subdomains_found.append(subdomain)
# we update the progress bar
bar()
save_subdomains()
# we save the subdomains found to a file
def save_subdomains():
# Output json template
output_json = {
"zScan": {
"domain_scanned": f'{domain}',
"total_subdomains_found": f'{len(subdomains_found)}',
"scan_start_date": f'{scan_StartTime}',
"scan_end_date": f'{datetime.now()}',
"subdomains_found": subdomains_found
}
}
if output_file:
# if the user provided an output file, we save the results to that file
with open(output_file, 'w') as f:
json.dump(output_json, f, indent=4)
print(f'[+] Scan Finished, showing results: ')
print_json(json.dumps(output_json, indent=4))
print(f'[+] Results saved to: [purple]{output_file}[/]')
else:
# if the user did not provide an output file, we save the results to a default file
with open(f'./results/{domain}_zScan_results.json', 'w') as f:
json.dump(output_json, f, indent=4)
print(f'[+] Scan Finished, showing results: ')
print_json(json.dumps(output_json, indent=4))
print(f'[+] Results saved to: [purple]./results/{domain}_zScan_results.json[/]')
# we handle the signals that might occur
def signal_handler(sig, frame):
print('\n\n')
print('[red][!] Terminate request received, saving scan results and exiting...[/]')
save_subdomains()
sys.exit(0)
# takes care of the start of the program and prints the banner
def start():
banner = '''[green]
███████╗███████╗ ██████╗ █████╗ ███╗ ██╗
╚══███╔╝██╔════╝██╔════╝██╔══██╗████╗ ██║
███╔╝ ███████╗██║ ███████║██╔██╗ ██║
███╔╝ ╚════██║██║ ██╔══██║██║╚██╗██║
███████╗███████║╚██████╗██║ ██║██║ ╚████║
╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝
─▌ A Quick Subdomain scanner by [purple]Tzero86[/] ▐─[/]
'''
clear_screen()
print(banner)
print('[*] Loading [bold][purple]zScan[/][/] a quick subdomain scanner, inspired by Joe Helle\'s python3 series.')
signal.signal(signal.SIGINT, signal_handler)
scan_subdomains()
if __name__ == '__main__':
start()