Skip to content

Commit 83f7b2d

Browse files
author
synster
committed
Updated the scripts
1 parent a42f0d7 commit 83f7b2d

9 files changed

+480
-0
lines changed

censys_subdomain_enum.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# A script to extract domain names from related SSL/TLS certificates using Censys
2+
# You'll need Censys API ID and API Secret to be able to extract SSL/TLS certificates
3+
# Needs censys module to run. pip install censys.
4+
5+
from __future__ import print_function
6+
7+
import logging
8+
9+
logging.basicConfig(
10+
level=logging.INFO,
11+
format="%(message)s"
12+
)
13+
14+
__author__ = "Bharath(github.com/yamakira)"
15+
__version__ = "0.1"
16+
__purpose__ = "Extract subdomains for a domain from censys certificate dataset"
17+
18+
CENSYS_API_ID = ""
19+
CENSYS_API_SECRET = ""
20+
21+
import argparse
22+
import re
23+
import sys
24+
25+
try:
26+
import censys.certificates
27+
except ImportError:
28+
logging.info("\033[1;31m[!] Failed to import censys module. Run 'pip install censys'\033[1;m")
29+
sys.exit()
30+
31+
def get_certificates(domain):
32+
if not CENSYS_API_ID or not CENSYS_API_SECRET:
33+
logging.info("\033[1;31m[!] API KEY or Secret for Censys not provided.\033[1;m" \
34+
"\nYou'll have to provide them in the script")
35+
sys.exit()
36+
logging.info("[+] Extracting certificates for {} using Censys".format(domain))
37+
c = censys.certificates.CensysCertificates(CENSYS_API_ID, CENSYS_API_SECRET)
38+
search_results = c.paged_search(domain)
39+
certificates = search_results['results']
40+
if len(certificates) == 0:
41+
print("\033[1;31m[!] No matching certificates found!\033[1;m")
42+
sys.exit()
43+
return certificates
44+
45+
def get_subdomains(domain, certificates):
46+
logging.info("[+] Extracting sub-domains for {} from certificates".format(domain))
47+
subdomains = []
48+
for certificate in certificates:
49+
parsed_result = re.findall(r'(?<=CN=).*', certificate[u'parsed.subject_dn'])
50+
if len(parsed_result) > 0 and domain in parsed_result[0]: subdomains.append(parsed_result[0])
51+
return subdomains
52+
53+
def print_subdomains(subdomains):
54+
unique_subdomains = list(set(subdomains))
55+
print("\033[1;32m[+] Total unique subdomains found: {}\033[1;m".format(len(unique_subdomains)))
56+
print("[+] List of subdomains extracted:\n")
57+
for sub_domain in unique_subdomains:
58+
print(sub_domain)
59+
60+
def get_domain():
61+
if len(sys.argv) < 2:
62+
print("\n[!] Usage: python subdomain_enum_censys.py <target_domain>\n")
63+
sys.exit()
64+
else:
65+
domain = sys.argv[1]
66+
return domain
67+
68+
if __name__ == '__main__':
69+
domain = get_domain()
70+
certificates = get_certificates(domain)
71+
subdomains = get_subdomains(domain, certificates)
72+
print_subdomains(subdomains)

cheatsheet.pdf

63.7 KB
Binary file not shown.

cloudflare_subdomain_enum.py

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# Created using Metafidv2 by Matthew Bryant (mandatory)
4+
# Unauthorized use is stricly prohibited, please contact [email protected] with questions/comments.
5+
from __future__ import print_function
6+
import requests
7+
import getpass
8+
import json
9+
import time
10+
import csv
11+
import sys
12+
import os
13+
from bs4 import BeautifulSoup
14+
15+
class cloudflare_enum:
16+
def __init__( self ):
17+
# Master list of headers to be used in each connection
18+
self.global_headers = {
19+
}
20+
self.verbose = True
21+
22+
self.s = requests.Session()
23+
self.s.headers.update( self.global_headers )
24+
self.atok = ''
25+
26+
def log_in( self, username, password ):
27+
parse_dict = {}
28+
29+
r = self.s.get('https://www.cloudflare.com/', )
30+
31+
new_headers = {
32+
'Referer': 'https://www.cloudflare.com/',
33+
}
34+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
35+
r = self.s.get('https://www.cloudflare.com/a/login', )
36+
parse_dict[ 'security_token_0' ] = self.find_between_r( r.text, '"security_token":"', '"}};</script>' ) # http://xkcd.com/292/
37+
38+
post_data = {
39+
'email': username,
40+
'password': password,
41+
'security_token': parse_dict[ 'security_token_0' ],
42+
}
43+
new_headers = {
44+
'Referer': 'https://www.cloudflare.com/a/login',
45+
'Content-Type': 'application/x-www-form-urlencoded',
46+
}
47+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
48+
r = self.s.post('https://www.cloudflare.com/a/login', data=post_data)
49+
self.atok = self.find_between_r( r.text, 'window.bootstrap = {"atok":"', '","locale":"' ) # http://xkcd.com/292/
50+
51+
def get_domain_dns( self, domain ):
52+
parse_dict = {}
53+
post_data = {
54+
"betas": [],
55+
"created_on": "2015-08-24T00:27:16.048Z",
56+
"development_mode": False,
57+
"jump_start": True,
58+
"meta": {},
59+
"modified_on": 'null',
60+
"name": domain,
61+
"owner": {},
62+
"paused": False,
63+
"status": "initializing",
64+
"type": "full"
65+
}
66+
67+
new_headers = {
68+
'Content-Type': 'application/json; charset=UTF-8',
69+
'X-Requested-With': 'XMLHttpRequest',
70+
'Referer': 'https://www.cloudflare.com/a/add-site',
71+
'Pragma': 'no-cache',
72+
'Cache-Control': 'no-cache',
73+
'X-ATOK': self.atok,
74+
}
75+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
76+
r = self.s.post('https://www.cloudflare.com/api/v4/zones', data=json.dumps( post_data ))
77+
data = json.loads( r.text )
78+
success = data['success']
79+
if not success:
80+
print( r.text )
81+
return False
82+
83+
request_id = data['result']['id']
84+
time.sleep( 60 )
85+
86+
get_data = {
87+
'per_page': '100',
88+
'direction': 'asc',
89+
'page': '1',
90+
'order': 'type',
91+
}
92+
new_headers = {
93+
'X-Requested-With': 'XMLHttpRequest',
94+
'Referer': 'https://www.cloudflare.com/a/setup/' + domain + '/step/2',
95+
'X-ATOK': self.atok,
96+
}
97+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
98+
r = self.s.get('https://www.cloudflare.com/api/v4/zones/' + request_id + '/dns_records', params=get_data)
99+
return_data = json.loads( r.text )
100+
101+
new_headers = {
102+
'X-Requested-With': 'XMLHttpRequest',
103+
'Referer': 'https://www.cloudflare.com/a/setup/' + domain + '/step/2',
104+
'X-ATOK': self.atok,
105+
}
106+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
107+
r = self.s.delete('https://www.cloudflare.com/api/v4/zones/' + request_id, )
108+
109+
get_data = {
110+
'status': 'initializing,pending',
111+
'per_page': '50',
112+
'page': '1',
113+
}
114+
new_headers = {
115+
'X-Requested-With': 'XMLHttpRequest',
116+
'Referer': 'https://www.cloudflare.com/a/add-site',
117+
'X-ATOK': self.atok,
118+
}
119+
self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) )
120+
r = self.s.get('https://www.cloudflare.com/api/v4/zones', params=get_data)
121+
122+
return return_data['result']
123+
124+
def get_spreadsheet( self, domain ):
125+
dns_data = self.get_domain_dns( domain )
126+
if dns_data:
127+
filename = domain.replace( ".", "_" ) + ".csv"
128+
129+
with open( filename, 'wb' ) as csvfile:
130+
dns_writer = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
131+
dns_writer.writerow( [ "name", "type", "content" ] )
132+
for record in dns_data:
133+
dns_writer.writerow( [ record["name"], record["type"], record["content"] ] )
134+
135+
self.statusmsg( "Spreadsheet created at " + os.getcwd() + "/" + filename )
136+
137+
def print_banner( self ):
138+
if self.verbose:
139+
print("""
140+
141+
`..--------..`
142+
.-:///::------::///:.`
143+
`-//:-.`````````````.-://:.` ` `
144+
.://-.```````````````````.-://-` : `- .
145+
`-//:.........................-://. /. -: `:` ``
146+
`://--------:::://////:::--------://-::.::`:- .:.
147+
``.---..` `///::::::///////////////////:::::::///::::::--:.`.-.
148+
.://::::///::///::///////////////////////////:::///:-----::--:-` `
149+
`:/:-...--:://////////////////////////////////////////----------.--.`
150+
`:/:..-:://////////////////////////////////////////////-----------.````
151+
.//-::////////////////////////////////////:::::////////-...--------...`
152+
-/////////////////////////////////////////////::::----:. `.-::::::-..``
153+
``.--:////////////////////////////////////////////////::-..```-///::::///:-`
154+
`.:///::::://////////////////////////////////////:::::::::::::::-----......-:/:.
155+
`-//:-----::::://///////////////////////////////:///////////////////:-::::---..-//:`
156+
`:/:---://+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//+++//::--//:
157+
`//:-/+oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++oooo+//://.
158+
:///ossssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssosssssso+//:
159+
`//+sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss+/-
160+
`//+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++++/.
161+
``````````````````````````````````````````````````````````````````````````````````````
162+
Cloudflare DNS Enumeration Tool v1.3
163+
Created by mandatory
164+
Modified by yamakira
165+
""" )
166+
167+
def pprint( self, input_dict ):
168+
print( json.dumps(input_dict, sort_keys=True, indent=4, separators=(',', ': ')) )
169+
170+
def statusmsg( self, msg ):
171+
if self.verbose:
172+
print( "[ STATUS ] " + msg )
173+
174+
def errormsg( self, msg ):
175+
if self.verbose:
176+
print( "[ ERROR ] " + msg )
177+
178+
def successmsg( self, msg ):
179+
if self.verbose:
180+
print( "[ SUCCESS ] " + msg )
181+
182+
def find_between_r( self, s, first, last ):
183+
try:
184+
start = s.rindex( first ) + len( first )
185+
end = s.rindex( last, start )
186+
return s[start:end]
187+
except ValueError:
188+
return ""
189+
190+
def find_between( s, first, last ):
191+
try:
192+
start = s.index( first ) + len( first )
193+
end = s.index( last, start )
194+
return s[start:end]
195+
except ValueError:
196+
return ""
197+
198+
def get_cookie_from_file( self, cookie_file ):
199+
return_dict = {}
200+
with open( cookie_file ) as tmp:
201+
data = tmp.readlines()
202+
tmp_data = []
203+
for i, item in enumerate(data):
204+
if " " in data[i]:
205+
pew = data[i].split( " " )
206+
return_dict[ pew[5] ] = pew[6]
207+
208+
return return_dict
209+
210+
def get_creds(self):
211+
username = sys.argv[1]
212+
password = getpass.getpass('Provide your cloudflare password:')
213+
return username,password
214+
215+
if __name__ == "__main__":
216+
if len( sys.argv ) < 2:
217+
print( "Usage: " + sys.argv[0] + " [email protected] domain.com" )
218+
else:
219+
cloud = cloudflare_enum()
220+
username,password = cloud.get_creds()
221+
cloud.print_banner()
222+
cloud.log_in(username,password)
223+
cloud.get_spreadsheet(sys.argv[2])

crtsh_enum_psql.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from __future__ import print_function
2+
3+
__author__ = 'Bharath'
4+
__version__ = "0.1.0"
5+
6+
try:
7+
import psycopg2
8+
except ImportError:
9+
raise ImportError('\n\033[33mpsycopg2 library missing. pip install psycopg2\033[1;m\n')
10+
sys.exit(1)
11+
import re
12+
import sys
13+
14+
DB_HOST = 'crt.sh'
15+
DB_NAME = 'certwatch'
16+
DB_USER = 'guest'
17+
18+
def connect_to_db(domain_name):
19+
try:
20+
conn = psycopg2.connect("dbname={0} user={1} host={2}".format(DB_NAME, DB_USER, DB_HOST))
21+
cursor = conn.cursor()
22+
cursor.execute("SELECT ci.NAME_VALUE NAME_VALUE FROM certificate_identity ci WHERE ci.NAME_TYPE = 'dNSName' AND reverse(lower(ci.NAME_VALUE)) LIKE reverse(lower('%{}'));".format(domain_name))
23+
except:
24+
print("\n\033[1;31m[!] Unable to connect to the database\n\033[1;m")
25+
return cursor
26+
27+
def get_unique_domains(cursor, domain_name):
28+
unique_domains = []
29+
for result in cursor.fetchall():
30+
matches=re.findall(r"\'(.+?)\'",str(result))
31+
for subdomain in matches:
32+
if subdomain not in unique_domains:
33+
if ".{}".format(domain_name) in subdomain:
34+
unique_domains.append(subdomain)
35+
return unique_domains
36+
37+
def print_unique_domains(unique_domains):
38+
for unique_domain in sorted(unique_domains):
39+
print(unique_domain)
40+
41+
def get_domain_name():
42+
if len(sys.argv) <= 1:
43+
print("\n\033[33mUsage: python crtsh_enum_psql.py <target_domain>\033[1;m\n")
44+
sys.exit(1)
45+
else:
46+
return sys.argv[1]
47+
48+
if __name__ == '__main__':
49+
domain_name = get_domain_name()
50+
cursor = connect_to_db(domain_name)
51+
unique_domains = get_unique_domains(cursor, domain_name)
52+
print_unique_domains(unique_domains)

crtsh_enum_psql.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
query="SELECT ci.NAME_VALUE NAME_VALUE FROM certificate_identity ci WHERE ci.NAME_TYPE = 'dNSName' AND reverse(lower(ci.NAME_VALUE)) LIKE reverse(lower('%.$1'));"
4+
5+
echo $query | \
6+
psql -t -h crt.sh -p 5432 -U guest certwatch | \
7+
sed -e 's:^ *::g' -e 's:^*\.::g' -e '/^$/d' | \
8+
sort -u | sed -e 's:*.::g'

crtsh_enum_web.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
import urllib.request
5+
import urllib.parse
6+
import re
7+
8+
9+
if len(sys.argv) == 1:
10+
print("Usage: " + sys.argv[0] + " [domain] ...")
11+
sys.exit(1)
12+
13+
for i, arg in enumerate(sys.argv, 1):
14+
domains = set()
15+
with urllib.request.urlopen('https://crt.sh/?q=' + urllib.parse.quote('%.' + arg)) as f:
16+
code = f.read().decode('utf-8')
17+
for cert, domain in re.findall('<tr>(?:\s|\S)*?href="\?id=([0-9]+?)"(?:\s|\S)*?<td>([*_a-zA-Z0-9.-]+?\.' + re.escape(arg) + ')</td>(?:\s|\S)*?</tr>', code, re.IGNORECASE):
18+
domain = domain.split('@')[-1]
19+
if not domain in domains:
20+
domains.add(domain)
21+
print(domain)

requirements.txt

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
requests==2.18.4
2+
asn1crypto==0.24.0
3+
cffi==1.11.2
4+
cryptography==2.1.4
5+
enum34==1.1.6
6+
idna==2.6
7+
ipaddress==1.0.19
8+
pycparser==2.18
9+
pyOpenSSL==17.5.0
10+
six==1.11.0
11+
censys==0.0.8
12+
psycopg2==2.7.3.2
13+
beautifulsoup4

0 commit comments

Comments
 (0)