Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
m0rtem
GitHub Repository: m0rtem/CloudFail
Path: blob/master/cloudfail.py
138 views
1
#!/usr/bin/env python3
2
from __future__ import print_function
3
import argparse
4
import re
5
import sys
6
import socket
7
import binascii
8
import datetime
9
import socks
10
import requests
11
import colorama
12
import zipfile
13
import os
14
import win_inet_pton
15
import platform
16
from colorama import Fore, Style
17
from DNSDumpsterAPI import DNSDumpsterAPI
18
import dns.resolver
19
import collections
20
collections.Callable = collections.abc.Callable
21
22
23
colorama.init(Style.BRIGHT)
24
25
26
def print_out(data, end='\n'):
27
datetimestr = str(datetime.datetime.strftime(datetime.datetime.now(), '%H:%M:%S'))
28
print(Style.NORMAL + "[" + datetimestr + "] " + re.sub(' +', ' ', data) + Style.RESET_ALL,' ', end=end)
29
30
31
def ip_in_subnetwork(ip_address, subnetwork):
32
(ip_integer, version1) = ip_to_integer(ip_address)
33
(ip_lower, ip_upper, version2) = subnetwork_to_ip_range(subnetwork)
34
35
if version1 != version2:
36
raise ValueError("incompatible IP versions")
37
38
return (ip_lower <= ip_integer <= ip_upper)
39
40
41
def ip_to_integer(ip_address):
42
# try parsing the IP address first as IPv4, then as IPv6
43
for version in (socket.AF_INET, socket.AF_INET6):
44
try:
45
ip_hex = win_inet_pton.inet_pton(version, ip_address) if platform == 'Windows' else socket.inet_pton(version, ip_address)
46
ip_integer = int(binascii.hexlify(ip_hex), 16)
47
48
return ip_integer, 4 if version == socket.AF_INET else 6
49
except:
50
pass
51
52
raise ValueError("invalid IP address")
53
54
55
def subnetwork_to_ip_range(subnetwork):
56
try:
57
fragments = subnetwork.split('/')
58
network_prefix = fragments[0]
59
netmask_len = int(fragments[1])
60
61
# try parsing the subnetwork first as IPv4, then as IPv6
62
for version in (socket.AF_INET, socket.AF_INET6):
63
64
ip_len = 32 if version == socket.AF_INET else 128
65
66
try:
67
suffix_mask = (1 << (ip_len - netmask_len)) - 1
68
netmask = ((1 << ip_len) - 1) - suffix_mask
69
ip_hex = socket.inet_pton(version, network_prefix)
70
ip_lower = int(binascii.hexlify(ip_hex), 16) & netmask
71
ip_upper = ip_lower + suffix_mask
72
73
return (ip_lower,
74
ip_upper,
75
4 if version == socket.AF_INET else 6)
76
except:
77
pass
78
except:
79
pass
80
81
raise ValueError("invalid subnetwork")
82
83
84
def dnsdumpster(target):
85
print_out(Fore.CYAN + "Testing for misconfigured DNS using dnsdumpster...")
86
87
res = DNSDumpsterAPI(False).search(target)
88
89
if res['dns_records']['host']:
90
for entry in res['dns_records']['host']:
91
provider = str(entry['provider'])
92
if "Cloudflare" not in provider:
93
print_out(
94
Style.BRIGHT + Fore.WHITE + "[FOUND:HOST] " + Fore.GREEN + "{domain} {ip} {as} {provider} {country}".format(
95
**entry))
96
97
if res['dns_records']['dns']:
98
for entry in res['dns_records']['dns']:
99
provider = str(entry['provider'])
100
if "Cloudflare" not in provider:
101
print_out(
102
Style.BRIGHT + Fore.WHITE + "[FOUND:DNS] " + Fore.GREEN + "{domain} {ip} {as} {provider} {country}".format(
103
**entry))
104
105
if res['dns_records']['mx']:
106
for entry in res['dns_records']['mx']:
107
provider = str(entry['provider'])
108
if "Cloudflare" not in provider:
109
print_out(
110
Style.BRIGHT + Fore.WHITE + "[FOUND:MX] " + Fore.GREEN + "{ip} {as} {provider} {domain}".format(
111
**entry))
112
113
114
def crimeflare(target):
115
print_out(Fore.CYAN + "Scanning crimeflare database...")
116
117
with open("data/ipout", "r") as ins:
118
crimeFoundArray = []
119
for line in ins:
120
lineExploded = line.split(" ")
121
if lineExploded[1] == args.target:
122
crimeFoundArray.append(lineExploded[2])
123
else:
124
continue
125
if (len(crimeFoundArray) != 0):
126
for foundIp in crimeFoundArray:
127
print_out(Style.BRIGHT + Fore.WHITE + "[FOUND:IP] " + Fore.GREEN + "" + foundIp.strip())
128
else:
129
print_out("Did not find anything.")
130
131
132
def init(target):
133
if args.target:
134
print_out(Fore.CYAN + "Fetching initial information from: " + args.target + "...")
135
else:
136
print_out(Fore.RED + "No target set, exiting")
137
sys.exit(1)
138
139
if not os.path.isfile("data/ipout"):
140
print_out(Fore.CYAN + "No ipout file found, fetching data")
141
update()
142
print_out(Fore.CYAN + "ipout file created")
143
144
try:
145
ip = socket.gethostbyname(args.target)
146
except socket.gaierror:
147
print_out(Fore.RED + "Domain is not valid, exiting")
148
sys.exit(0)
149
150
print_out(Fore.CYAN + "Server IP: " + ip)
151
print_out(Fore.CYAN + "Testing if " + args.target + " is on the Cloudflare network...")
152
153
try:
154
ifIpIsWithin = inCloudFlare(ip)
155
156
if ifIpIsWithin:
157
print_out(Style.BRIGHT + Fore.GREEN + args.target + " is part of the Cloudflare network!")
158
else:
159
print_out(Fore.RED + args.target + " is not part of the Cloudflare network, quitting...")
160
sys.exit(0)
161
except ValueError:
162
print_out(Fore.RED + "IP address does not appear to be within Cloudflare range, shutting down..")
163
sys.exit(0)
164
165
166
def inCloudFlare(ip):
167
with open('{}/data/cf-subnet.txt'.format(os.getcwd())) as f:
168
for line in f:
169
isInNetwork = ip_in_subnetwork(ip, line)
170
if isInNetwork:
171
return True
172
return False
173
174
def check_for_wildcard(target):
175
resolver = dns.resolver.Resolver(configure=False)
176
resolver.nameservers = ['1.1.1.1', '1.0.0.1']
177
#Unsure how exactly I should test, for now simple appending to target. Don't know how to extract only domain to append *. for wildcard test
178
try:
179
#Throws exception if none found
180
answer = resolver.resolve('*.' + target)
181
#If found, ask user if continue as long until valid answer
182
choice = ''
183
while choice != 'y' and choice != 'n':
184
choice = input("A wildcard DNS entry was found. This will result in all subdomains returning an IP. Do you want to scan subdomains anyway? (y/n): ")
185
if choice == 'y':
186
return False
187
else:
188
return True
189
except:
190
#Return False to not return if no wildcard was found
191
return False
192
193
def subdomain_scan(target, subdomains):
194
i = 0
195
c = 0
196
if check_for_wildcard(target):
197
#If has wildcard or input N, return
198
print_out(Fore.CYAN + "Scanning finished...")
199
return
200
201
if subdomains:
202
subdomainsList = subdomains
203
else:
204
subdomainsList = "subdomains.txt"
205
try:
206
with open("data/" + subdomainsList, "r") as wordlist:
207
numOfLines = len(open("data/subdomains.txt").readlines())
208
numOfLinesInt = numOfLines
209
numOfLines = str(numOfLines)
210
print_out(Fore.CYAN + "Scanning " + numOfLines + " subdomains (" + subdomainsList + "), please wait...")
211
for word in wordlist:
212
c += 1
213
if (c % int((float(numOfLinesInt) / 100.0))) == 0:
214
print_out(Fore.CYAN + str(round((c / float(numOfLinesInt)) * 100.0, 2)) + "% complete", '\r')
215
216
subdomain = "{}.{}".format(word.strip(), target)
217
try:
218
target_http = requests.get("http://" + subdomain)
219
target_http = str(target_http.status_code)
220
ip = socket.gethostbyname(subdomain)
221
ifIpIsWithin = inCloudFlare(ip)
222
223
if not ifIpIsWithin:
224
i += 1
225
print_out(
226
Style.BRIGHT + Fore.WHITE + "[FOUND:SUBDOMAIN] " + Fore.GREEN + subdomain + " IP: " + ip + " HTTP: " + target_http)
227
else:
228
print_out(
229
Style.BRIGHT + Fore.WHITE + "[FOUND:SUBDOMAIN] " + Fore.RED + subdomain + " ON CLOUDFLARE NETWORK!")
230
continue
231
232
except requests.exceptions.RequestException as e:
233
continue
234
if (i == 0):
235
print_out(Fore.CYAN + "Scanning finished, we did not find anything, sorry...")
236
else:
237
print_out(Fore.CYAN + "Scanning finished...")
238
239
except IOError:
240
print_out(Fore.RED + "Subdomains file does not exist in data directory, aborting scan...")
241
sys.exit(1)
242
243
def update():
244
print_out(Fore.CYAN + "Just checking for updates, please wait...")
245
print_out(Fore.CYAN + "Updating CloudFlare subnet...")
246
if(args.tor == False):
247
headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'}
248
r = requests.get("https://www.cloudflare.com/ips-v4", headers=headers, cookies={'__cfduid': "d7c6a0ce9257406ea38be0156aa1ea7a21490639772"}, stream=True)
249
with open('data/cf-subnet.txt', 'wb') as fd:
250
for chunk in r.iter_content(4000):
251
fd.write(chunk)
252
else:
253
print_out(Fore.RED + Style.BRIGHT+"Unable to fetch CloudFlare subnet while TOR is active")
254
print_out(Fore.CYAN + "Updating Crimeflare database...")
255
r = requests.get("https://cf.ozeliurs.com/ipout", stream=True)
256
with open('data/ipout', 'wb') as fd:
257
for chunk in r.iter_content(4000):
258
fd.write(chunk)
259
260
# END FUNCTIONS
261
262
logo = """\
263
____ _ _ _____ _ _
264
/ ___| | ___ _ _ __| | ___|_ _(_) |
265
| | | |/ _ \| | | |/ _` | |_ / _` | | |
266
| |___| | (_) | |_| | (_| | _| (_| | | |
267
\____|_|\___/ \__,_|\__,_|_| \__,_|_|_|
268
v1.0.5 by m0rtem
269
270
"""
271
272
print(Fore.RED + Style.BRIGHT + logo + Fore.RESET)
273
datestr = str(datetime.datetime.strftime(datetime.datetime.now(), '%d/%m/%Y'))
274
print_out("Initializing CloudFail - the date is: " + datestr)
275
276
parser = argparse.ArgumentParser()
277
parser.add_argument("-t", "--target", help="target url of website", type=str)
278
parser.add_argument("-T", "--tor", dest="tor", action="store_true", help="enable TOR routing")
279
parser.add_argument("-u", "--update", dest="update", action="store_true", help="update databases")
280
parser.add_argument("-s", "--subdomains", help="name of alternate subdomains list stored in the data directory", type=str)
281
parser.set_defaults(tor=False)
282
parser.set_defaults(update=False)
283
284
args = parser.parse_args()
285
286
if args.tor is True:
287
ipcheck_url = 'http://ipinfo.io/ip'
288
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 9050)
289
socket.socket = socks.socksocket
290
try:
291
tor_ip = requests.get(ipcheck_url)
292
tor_ip = str(tor_ip.text)
293
294
print_out(Fore.WHITE + Style.BRIGHT + "TOR connection established!")
295
print_out(Fore.WHITE + Style.BRIGHT + "New IP: " + tor_ip)
296
297
except requests.exceptions.RequestException as e:
298
print(e, net_exc)
299
sys.exit(0)
300
301
if args.update is True:
302
update()
303
304
try:
305
306
# Initialize CloudFail
307
init(args.target)
308
309
# Scan DNSdumpster.com
310
dnsdumpster(args.target)
311
312
# Scan Crimeflare database
313
crimeflare(args.target)
314
315
# Scan subdomains with or without TOR
316
subdomain_scan(args.target, args.subdomains)
317
318
except KeyboardInterrupt:
319
sys.exit(0)
320
321