8
8
from lib .core .discovered_host import *
9
9
from urllib3 .util import ssl_
10
10
11
- DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
11
+ DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) ' \
12
+ 'AppleWebKit/537.36 (KHTML, like Gecko) ' \
13
+ 'Chrome/61.0.3163.100 Safari/537.36'
12
14
13
15
_target_host = None
14
16
_ssl_wrap_socket = ssl_ .ssl_wrap_socket
17
+
18
+
15
19
def ssl_wrap_socket (sock , keyfile = None , certfile = None , cert_reqs = None ,
16
20
ca_certs = None , server_hostname = None ,
17
21
ssl_version = None , ciphers = None , ssl_context = None ,
18
22
ca_cert_dir = None ):
19
- ssl_wrap_socket_ (sock , keyfile = keyfile , certfile = certfile , cert_reqs = cert_reqs ,
20
- ca_certs = ca_certs , server_hostname = _target_host ,
21
- ssl_version = ssl_version , ciphers = ciphers , ssl_context = ssl_context ,
22
- ca_cert_dir = ca_cert_dir )
23
- ssl_ .ssl_wrap_socket = _ssl_wrap_socket
23
+ ssl_wrap_socket_ (sock , keyfile = keyfile , certfile = certfile ,
24
+ cert_reqs = cert_reqs , ca_certs = ca_certs ,
25
+ server_hostname = _target_host , ssl_version = ssl_version ,
26
+ ciphers = ciphers , ssl_context = ssl_context ,
27
+ ca_cert_dir = ca_cert_dir )
28
+
29
+ ssl_ .ssl_wrap_socket = _ssl_wrap_socket
30
+
24
31
25
32
class virtual_host_scanner (object ):
26
33
"""Virtual host scanning class
@@ -35,43 +42,52 @@ class virtual_host_scanner(object):
35
42
ignore_content_length: integer value of content length to ignore
36
43
output: folder to write output file to
37
44
"""
38
-
39
-
40
45
def __init__ (self , target , wordlist , ** kwargs ):
41
46
self .target = target
42
47
self .wordlist = wordlist
43
48
self .base_host = kwargs .get ('base_host' )
44
49
self .rate_limit = int (kwargs .get ('rate_limit' , 0 ))
45
50
self .port = int (kwargs .get ('port' , 80 ))
46
51
self .real_port = int (kwargs .get ('real_port' , 80 ))
47
- self .ignore_content_length = int (kwargs .get ('ignore_content_length' , 0 ))
48
52
self .ssl = kwargs .get ('ssl' , False )
49
53
self .fuzzy_logic = kwargs .get ('fuzzy_logic' , False )
50
- self .add_waf_bypass_headers = kwargs .get ('add_waf_bypass_headers' , False )
51
54
self .unique_depth = int (kwargs .get ('unique_depth' , 1 ))
52
55
self .ignore_http_codes = kwargs .get ('ignore_http_codes' , '404' )
53
56
self .first_hit = kwargs .get ('first_hit' )
54
57
58
+ self .ignore_content_length = int (
59
+ kwargs .get ('ignore_content_length' , 0 )
60
+ )
61
+
62
+ self .add_waf_bypass_headers = kwargs .get (
63
+ 'add_waf_bypass_headers' ,
64
+ False
65
+ )
66
+
55
67
# this can be made redundant in future with better exceptions
56
- self .completed_scan = False
57
-
58
- # this is maintained until likely-matches is refactored to use new class
68
+ self .completed_scan = False
69
+
70
+ # this is maintained until likely-matches is refactored to use
71
+ # new class
59
72
self .results = []
60
-
61
- # store associated data for discovered hosts in array for oN, oJ, etc'
73
+
74
+ # store associated data for discovered hosts
75
+ # in array for oN, oJ, etc'
62
76
self .hosts = []
63
77
64
78
# available user-agents
65
- self .user_agents = list (kwargs .get ('user_agents' )) or [DEFAULT_USER_AGENT ]
79
+ self .user_agents = list (kwargs .get ('user_agents' )) \
80
+ or [DEFAULT_USER_AGENT ]
66
81
67
82
@property
68
83
def ignore_http_codes (self ):
69
84
return self ._ignore_http_codes
70
85
71
86
@ignore_http_codes .setter
72
87
def ignore_http_codes (self , codes ):
73
- self ._ignore_http_codes = [int (code ) for code in codes .replace (' ' , '' ).split (',' )]
74
-
88
+ self ._ignore_http_codes = [
89
+ int (code ) for code in codes .replace (' ' , '' ).split (',' )
90
+ ]
75
91
76
92
def scan (self ):
77
93
if not self .base_host :
@@ -83,9 +99,14 @@ def scan(self):
83
99
for virtual_host in self .wordlist :
84
100
hostname = virtual_host .replace ('%s' , self .base_host )
85
101
102
+ if self .real_port == 80 :
103
+ host_header = hostname
104
+ else :
105
+ host_header = '{}:{}' .format (hostname , self .real_port )
106
+
86
107
headers = {
87
108
'User-Agent' : random .choice (self .user_agents ),
88
- 'Host' : hostname if self . real_port == 80 else '{}:{}' . format ( hostname , self . real_port ) ,
109
+ 'Host' : host_header ,
89
110
'Accept' : '*/*'
90
111
}
91
112
@@ -96,8 +117,13 @@ def scan(self):
96
117
'X-Remote-IP' : '127.0.0.1' ,
97
118
'X-Remote-Addr' : '127.0.0.1'
98
119
})
99
-
100
- dest_url = '{}://{}:{}/' .format ('https' if self .ssl else 'http' , self .target , self .port )
120
+
121
+ dest_url = '{}://{}:{}/' .format (
122
+ 'https' if self .ssl else 'http' ,
123
+ self .target ,
124
+ self .port
125
+ )
126
+
101
127
_target_host = hostname
102
128
103
129
try :
@@ -108,7 +134,9 @@ def scan(self):
108
134
if res .status_code in self .ignore_http_codes :
109
135
continue
110
136
111
- if self .ignore_content_length > 0 and self .ignore_content_length == int (res .headers .get ('content-length' )):
137
+ response_length = int (res .headers .get ('content-length' , 0 ))
138
+ if self .ignore_content_length and \
139
+ self .ignore_content_length == response_length :
112
140
continue
113
141
114
142
# hash the page results to aid in identifing unique content
@@ -119,49 +147,59 @@ def scan(self):
119
147
# add url and hash into array for likely matches
120
148
self .results .append (hostname + ',' + page_hash )
121
149
122
- if len (self .hosts ) == 2 and self .first_hit :
150
+ if len (self .hosts ) >= 1 and self .first_hit :
123
151
break
124
152
125
- #rate limit the connection, if the int is 0 it is ignored
153
+ # rate limit the connection, if the int is 0 it is ignored
126
154
time .sleep (self .rate_limit )
127
155
128
- self .completed_scan = True
129
-
156
+ self .completed_scan = True
130
157
131
158
def likely_matches (self ):
132
159
if self .completed_scan is False :
133
- print ("[!] Likely matches cannot be printed as a scan has not yet been run." )
134
- return
160
+ print ("[!] Likely matches cannot be printed "
161
+ "as a scan has not yet been run." )
162
+ return
135
163
136
164
# segment results from previous scan into usable results
137
- segmented_data = {}
165
+ segmented_data = {}
138
166
for item in self .results :
139
167
result = item .split ("," )
140
168
segmented_data [result [0 ]] = result [1 ]
141
169
142
- dataframe = pd .DataFrame ([[key , value ] for key , value in segmented_data .items ()], columns = ["key_col" , "val_col" ])
143
- segmented_data = dataframe .groupby ("val_col" ).filter (lambda x : len (x ) <= self .unique_depth )
144
- matches = ((segmented_data ["key_col" ].values ).tolist ())
170
+ dataframe = pd .DataFrame ([
171
+ [key , value ] for key , value in segmented_data .items ()],
172
+ columns = ["key_col" , "val_col" ]
173
+ )
145
174
146
- return matches
175
+ segmented_data = dataframe .groupby ("val_col" ).filter (
176
+ lambda x : len (x ) <= self .unique_depth
177
+ )
178
+
179
+ return segmented_data ["key_col" ].values .tolist ()
147
180
148
181
def create_host (self , response , hostname , page_hash ):
149
182
"""
150
183
Creates a host using the responce and the hash.
151
184
Prints current result in real time.
152
185
"""
153
- output = '[#] Found: {} (code: {}, length: {}, hash: {})\n ' .format (hostname , response .status_code ,
154
- response .headers .get ('content-length' ), page_hash )
186
+ output = '[#] Found: {} (code: {}, length: {}, hash: {})\n ' .format (
187
+ hostname ,
188
+ response .status_code ,
189
+ response .headers .get ('content-length' ),
190
+ page_hash
191
+ )
192
+
155
193
host = discovered_host ()
156
194
host .hostname = hostname
157
195
host .response_code = response .status_code
158
196
host .hash = page_hash
159
- host .content = response .content
197
+ host .contnet = response .content
160
198
161
199
for key , val in response .headers .items ():
162
200
output += ' {}: {}\n ' .format (key , val )
163
201
host .keys .append ('{}: {}' .format (key , val ))
164
202
165
203
print (output )
166
204
167
- return host
205
+ return host
0 commit comments