| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e574578 commit ae17096
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,10 @@ | |||
| 9 | 9 | ||
| 10 | 10 | from selenium import webdriver | |
| 11 | 11 | from urlparse import urlparse | |
| 12 | + from random import shuffle | ||
| 13 | + from PIL import Image | ||
| 14 | + from PIL import ImageDraw | ||
| 15 | + from PIL import ImageFont | ||
| 12 | 16 | import multiprocessing | |
| 13 | 17 | import Queue | |
| 14 | 18 | import argparse | |
@@ -19,16 +23,11 @@ | |||
| 19 | 23 | import ssl | |
| 20 | 24 | import M2Crypto | |
| 21 | 25 | import re | |
| 22 | - from random import shuffle | ||
| 23 | 26 | import time | |
| 24 | - # Lines 25-27 are out of date methods as per (http://pillow.readthedocs.org/en/latest/installation.html) | ||
| 25 | - #import Image | ||
| 26 | - #import ImageDraw | ||
| 27 | - #import ImageFont | ||
| 28 | - from PIL import Image | ||
| 29 | - from PIL import ImageDraw | ||
| 30 | - from PIL import ImageFont | ||
| 31 | 27 | import signal | |
| 28 | + import shutil | ||
| 29 | + import hashlib | ||
| 30 | + | ||
| 32 | 31 | ||
| 33 | 32 | reload(sys) | |
| 34 | 33 | sys.setdefaultencoding("utf8") | |
@@ -102,7 +101,7 @@ def parseGnmap(inFile, autodetect): | |||
| 102 | 101 | for item in fields: | |
| 103 | 102 | #Make sure we have an open port with an http type service on it | |
| 104 | 103 | if (item.find('http') != -1 or autodetect) and re.findall('\d+/open',item): | |
| 105 | - port = None | ||
| 104 | + port = None | ||
| 106 | 105 | https = False | |
| 107 | 106 | ''' | |
| 108 | 107 | nmap has a bunch of ways to list HTTP like services, for example: | |
@@ -144,7 +143,6 @@ def setupBrowserProfile(headless): | |||
| 144 | 143 | print e | |
| 145 | 144 | time.sleep(1) | |
| 146 | 145 | continue | |
| 147 | - | ||
| 148 | 146 | return browser | |
| 149 | 147 | ||
| 150 | 148 | ||
@@ -156,7 +154,7 @@ def writeImage(text, filename, fontsize=40, width=1024, height=200): | |||
| 156 | 154 | image.save(filename) | |
| 157 | 155 | ||
| 158 | 156 | ||
| 159 | - def worker(urlQueue,tout,debug,headless,doProfile,vhosts,subs,extraHosts,tryGUIOnFail): | ||
| 157 | + def worker(urlQueue, tout, debug, headless, doProfile, vhosts, subs, extraHosts, tryGUIOnFail, smartFetch): | ||
| 160 | 158 | if(debug): | |
| 161 | 159 | print '[*] Starting worker' | |
| 162 | 160 | ||
@@ -173,18 +171,20 @@ def worker(urlQueue,tout,debug,headless,doProfile,vhosts,subs,extraHosts,tryGUIO | |||
| 173 | 171 | ||
| 174 | 172 | while True: | |
| 175 | 173 | #Try to get a URL from the Queue | |
| 176 | - try: | ||
| 177 | - curUrl = urlQueue.get(timeout=tout) | ||
| 174 | + if urlQueue.qsize() > 0: | ||
| 175 | + try: | ||
| 176 | + curUrl = urlQueue.get(timeout=tout) | ||
| 177 | + except Queue.Empty: | ||
| 178 | + continue | ||
| 178 | 179 | print '[+] '+str(urlQueue.qsize())+' URLs remaining' | |
| 179 | 180 | screenshotName = urlparse(curUrl[0]).netloc.replace(":", "-") | |
| 180 | 181 | if(debug): | |
| 181 | 182 | print '[+] Got URL: '+curUrl[0] | |
| 182 | 183 | if(os.path.exists(screenshotName+".png")): | |
| 183 | 184 | if(debug): | |
| 184 | - print "[-] Screenshot already exists, skipping" | ||
| 185 | + print "[-] Screenshot already exists, skipping" | ||
| 185 | 186 | continue | |
| 186 | - | ||
| 187 | - except Queue.Empty: | ||
| 187 | + else: | ||
| 188 | 188 | if(debug): | |
| 189 | 189 | print'[-] URL queue is empty, quitting.' | |
| 190 | 190 | browser.quit() | |
@@ -204,59 +204,71 @@ def worker(urlQueue,tout,debug,headless,doProfile,vhosts,subs,extraHosts,tryGUIO | |||
| 204 | 204 | writeImage(resp.headers.get('www-authenticate','NO WWW-AUTHENTICATE HEADER'),screenshotName+".png") | |
| 205 | 205 | continue | |
| 206 | 206 | elif(resp is not None): | |
| 207 | - browser.set_window_size(1024, 768) | ||
| 208 | - browser.set_page_load_timeout((tout)) | ||
| 209 | - old_url = browser.current_url | ||
| 210 | - browser.get(curUrl[0].strip()) | ||
| 211 | - if(browser.current_url == old_url): | ||
| 212 | - print "[-] Error fetching in browser but successfully fetched with Requests: "+curUrl[0] | ||
| 213 | - if(headless): | ||
| 214 | - if(debug): | ||
| 215 | - print "[+] Trying with sslv3 instead of TLS - known phantomjs bug: "+curUrl[0] | ||
| 216 | - browser2 = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true'], executable_path="phantomjs") | ||
| 217 | - old_url = browser2.current_url | ||
| 218 | - browser2.get(curUrl[0].strip()) | ||
| 219 | - if(browser2.current_url == old_url): | ||
| 207 | + | ||
| 208 | + resp_hash = hashlib.md5(resp.text).hexdigest() | ||
| 209 | + | ||
| 210 | + if smartFetch and resp_hash in hash_basket: | ||
| 211 | + #We have this exact same page already, copy it instead of grabbing it again | ||
| 212 | + print "[+] Pre-fetch matches previously imaged service, no need to do it again!" | ||
| 213 | + shutil.copy2(hash_basket[resp_hash]+".html",screenshotName+".html") | ||
| 214 | + shutil.copy2(hash_basket[resp_hash]+".png",screenshotName+".png") | ||
| 215 | + else: | ||
| 216 | + if smartFetch: | ||
| 217 | + hash_basket[resp_hash] = screenshotName | ||
| 218 | + | ||
| 219 | + browser.set_window_size(1024, 768) | ||
| 220 | + browser.set_page_load_timeout((tout)) | ||
| 221 | + old_url = browser.current_url | ||
| 222 | + browser.get(curUrl[0].strip()) | ||
| 223 | + if(browser.current_url == old_url): | ||
| 224 | + print "[-] Error fetching in browser but successfully fetched with Requests: "+curUrl[0] | ||
| 225 | + if(headless): | ||
| 220 | 226 | if(debug): | |
| 221 | - print "[-] Didn't work with SSLv3 either..."+curUrl[0] | ||
| 222 | - browser2.close() | ||
| 223 | - else: | ||
| 224 | - print '[+] Saving: '+screenshotName | ||
| 225 | - html_source = browser2.page_source | ||
| 226 | - f = open(screenshotName+".html",'w') | ||
| 227 | - f.write(html_source) | ||
| 228 | - f.close() | ||
| 229 | - browser2.save_screenshot(screenshotName+".png") | ||
| 230 | - browser2.close() | ||
| 231 | - continue | ||
| 232 | - | ||
| 233 | - if(tryGUIOnFail and headless): | ||
| 234 | - print "[+] Attempting to fetch with FireFox: "+curUrl[0] | ||
| 235 | - browser2 = setupBrowserProfile(False) | ||
| 236 | - old_url = browser2.current_url | ||
| 237 | - browser2.get(curUrl[0].strip()) | ||
| 238 | - if(browser2.current_url == old_url): | ||
| 239 | - print "[-] Error fetching in GUI browser as well..."+curUrl[0] | ||
| 240 | - browser2.close() | ||
| 241 | - continue | ||
| 227 | + print "[+] Trying with sslv3 instead of TLS - known phantomjs bug: "+curUrl[0] | ||
| 228 | + browser2 = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true'], executable_path="phantomjs") | ||
| 229 | + old_url = browser2.current_url | ||
| 230 | + browser2.get(curUrl[0].strip()) | ||
| 231 | + if(browser2.current_url == old_url): | ||
| 232 | + if(debug): | ||
| 233 | + print "[-] Didn't work with SSLv3 either..."+curUrl[0] | ||
| 234 | + browser2.close() | ||
| 235 | + else: | ||
| 236 | + print '[+] Saving: '+screenshotName | ||
| 237 | + html_source = browser2.page_source | ||
| 238 | + f = open(screenshotName+".html",'w') | ||
| 239 | + f.write(html_source) | ||
| 240 | + f.close() | ||
| 241 | + browser2.save_screenshot(screenshotName+".png") | ||
| 242 | + browser2.close() | ||
| 243 | + continue | ||
| 244 | + | ||
| 245 | + if(tryGUIOnFail and headless): | ||
| 246 | + print "[+] Attempting to fetch with FireFox: "+curUrl[0] | ||
| 247 | + browser2 = setupBrowserProfile(False) | ||
| 248 | + old_url = browser2.current_url | ||
| 249 | + browser2.get(curUrl[0].strip()) | ||
| 250 | + if(browser2.current_url == old_url): | ||
| 251 | + print "[-] Error fetching in GUI browser as well..."+curUrl[0] | ||
| 252 | + browser2.close() | ||
| 253 | + continue | ||
| 254 | + else: | ||
| 255 | + print '[+] Saving: '+screenshotName | ||
| 256 | + html_source = browser2.page_source | ||
| 257 | + f = open(screenshotName+".html",'w') | ||
| 258 | + f.write(html_source) | ||
| 259 | + f.close() | ||
| 260 | + browser2.save_screenshot(screenshotName+".png") | ||
| 261 | + browser2.close() | ||
| 262 | + continue | ||
| 242 | 263 | else: | |
| 243 | - print '[+] Saving: '+screenshotName | ||
| 244 | - html_source = browser2.page_source | ||
| 245 | - f = open(screenshotName+".html",'w') | ||
| 246 | - f.write(html_source) | ||
| 247 | - f.close() | ||
| 248 | - browser2.save_screenshot(screenshotName+".png") | ||
| 249 | - browser2.close() | ||
| 250 | 264 | continue | |
| 251 | - else: | ||
| 252 | - continue | ||
| 253 | - | ||
| 254 | - print '[+] Saving: '+screenshotName | ||
| 255 | - html_source = browser.page_source | ||
| 256 | - f = open(screenshotName+".html",'w') | ||
| 257 | - f.write(html_source) | ||
| 258 | - f.close() | ||
| 259 | - browser.save_screenshot(screenshotName+".png") | ||
| 265 | + | ||
| 266 | + print '[+] Saving: '+screenshotName | ||
| 267 | + html_source = browser.page_source | ||
| 268 | + f = open(screenshotName+".html",'w') | ||
| 269 | + f.write(html_source) | ||
| 270 | + f.close() | ||
| 271 | + browser.save_screenshot(screenshotName+".png") | ||
| 260 | 272 | except Exception as e: | |
| 261 | 273 | print e | |
| 262 | 274 | print '[-] Something bad happened with URL: '+curUrl[0] | |
@@ -273,17 +285,13 @@ def worker(urlQueue,tout,debug,headless,doProfile,vhosts,subs,extraHosts,tryGUIO | |||
| 273 | 285 | ||
| 274 | 286 | ||
| 275 | 287 | def doGet(*args, **kwargs): | |
| 276 | - url = args[0] | ||
| 277 | - doVhosts = kwargs['vhosts'] | ||
| 278 | - urlQueue = kwargs['urlQueue'] | ||
| 279 | - subs = kwargs['subs'] | ||
| 280 | - extraHosts = kwargs['extraHosts'] | ||
| 281 | - del kwargs['extraHosts'] | ||
| 282 | - del kwargs['urlQueue'] | ||
| 283 | - del kwargs['vhosts'] | ||
| 284 | - del kwargs['subs'] | ||
| 285 | - | ||
| 286 | - kwargs['allow_redirects']=False | ||
| 288 | + url = args[0] | ||
| 289 | + doVhosts = kwargs.pop('vhosts' ,None) | ||
| 290 | + urlQueue = kwargs.pop('urlQueue' ,None) | ||
| 291 | + subs = kwargs.pop('subs' ,None) | ||
| 292 | + extraHosts = kwargs.pop('extraHosts',None) | ||
| 293 | + | ||
| 294 | + kwargs['allow_redirects'] = False | ||
| 287 | 295 | ||
| 288 | 296 | resp = requests.get(url[0],**kwargs) | |
| 289 | 297 | ||
@@ -295,10 +303,11 @@ def doGet(*args, **kwargs): | |||
| 295 | 303 | port = urlparse(url[0]).port | |
| 296 | 304 | if(port is None): | |
| 297 | 305 | port = 443 | |
| 298 | - cert = ssl.get_server_certificate((host,port),ssl_version=ssl.PROTOCOL_SSLv23) | ||
| 299 | - x509 = M2Crypto.X509.load_cert_string(cert) | ||
| 306 | + | ||
| 307 | + cert = ssl.get_server_certificate((host,port),ssl_version=ssl.PROTOCOL_SSLv23) | ||
| 308 | + x509 = M2Crypto.X509.load_cert_string(cert) | ||
| 300 | 309 | subjText = x509.get_subject().as_text() | |
| 301 | - names = re.findall("CN=([^\s]+)",subjText) | ||
| 310 | + names = re.findall("CN=([^\s]+)",subjText) | ||
| 302 | 311 | ||
| 303 | 312 | try: | |
| 304 | 313 | altNames = x509.get_ext('subjectAltName').get_value() | |
@@ -330,10 +339,7 @@ def doGet(*args, **kwargs): | |||
| 330 | 339 | extraHosts[name] = 1 | |
| 331 | 340 | urlQueue.put(['https://'+name+':'+str(port),False,url[2]]) | |
| 332 | 341 | print '[+] Added host '+name | |
| 333 | - | ||
| 334 | - | ||
| 335 | 342 | return resp | |
| 336 | - | ||
| 337 | 343 | else: | |
| 338 | 344 | return resp | |
| 339 | 345 | ||
@@ -384,6 +390,10 @@ def sslError(e): | |||
| 384 | 390 | else: | |
| 385 | 391 | return False | |
| 386 | 392 | ||
| 393 | + def signal_handler(signal, frame): | ||
| 394 | + print "[-] Ctrl-C received! Killing Thread(s)..." | ||
| 395 | + sys.exit(0) | ||
| 396 | + signal.signal(signal.SIGINT, signal_handler) | ||
| 387 | 397 | ||
| 388 | 398 | if __name__ == '__main__': | |
| 389 | 399 | parser = argparse.ArgumentParser() | |
@@ -399,6 +409,7 @@ def sslError(e): | |||
| 399 | 409 | parser.add_argument("-dB","--dns_brute",help='Specify a DNS subdomain wordlist for bruteforcing on wildcard SSL certs') | |
| 400 | 410 | parser.add_argument("-r","--retries",type=int,default=0,help='Number of retries if a URL fails or timesout') | |
| 401 | 411 | parser.add_argument("-tG","--trygui",action='store_true',default=False,help='Try to fetch the page with FireFox when headless fails') | |
| 412 | + parser.add_argument("-sF","--smartfetch",action='store_true',default=False,help='Enables smart fetching to reduce network traffic, also increases speed if certain conditions are met.') | ||
| 402 | 413 | ||
| 403 | 414 | args = parser.parse_args() | |
| 404 | 415 | ||
@@ -413,14 +424,12 @@ def sslError(e): | |||
| 413 | 424 | urls = [] | |
| 414 | 425 | for host,ports in hosts.items(): | |
| 415 | 426 | for port in ports: | |
| 416 | - url='' | ||
| 427 | + url = '' | ||
| 417 | 428 | if port[1] == True: | |
| 418 | 429 | url = ['https://'+host+':'+port[0],args.vhosts,args.retries] | |
| 419 | 430 | else: | |
| 420 | 431 | url = ['http://'+host+':'+port[0],args.vhosts,args.retries] | |
| 421 | 432 | urls.append(url) | |
| 422 | - | ||
| 423 | - | ||
| 424 | 433 | else: | |
| 425 | 434 | print 'Invalid input file - must be Nmap GNMAP' | |
| 426 | 435 | ||
@@ -437,32 +446,27 @@ def sslError(e): | |||
| 437 | 446 | ||
| 438 | 447 | #shuffle the url list | |
| 439 | 448 | shuffle(urls) | |
| 449 | + | ||
| 440 | 450 | #read in the subdomain bruteforce list if specificed | |
| 441 | 451 | subs = [] | |
| 442 | 452 | if(args.dns_brute != None): | |
| 443 | 453 | subs = open(args.dns_brute,'r').readlines() | |
| 454 | + | ||
| 444 | 455 | #Fire up the workers | |
| 445 | - urlQueue = multiprocessing.Queue() | ||
| 446 | - manager = multiprocessing.Manager() | ||
| 447 | - hostsDict = manager.dict() | ||
| 448 | - workers = [] | ||
| 456 | + urlQueue = multiprocessing.Queue() | ||
| 457 | + manager = multiprocessing.Manager() | ||
| 458 | + hostsDict = manager.dict() | ||
| 459 | + workers = [] | ||
| 460 | + hash_basket = {} | ||
| 449 | 461 | ||
| 450 | 462 | for i in range(args.workers): | |
| 451 | - p = multiprocessing.Process(target=worker, | ||
| 452 | - args=(urlQueue,args.timeout,args.verbose,args.headless,args.autodetect, args.vhosts,subs,hostsDict,args.trygui)) | ||
| 453 | - | ||
| 454 | - | ||
| 463 | + p = multiprocessing.Process(target=worker, args=(urlQueue, args.timeout, args.verbose, args.headless, args.autodetect, args.vhosts, subs, hostsDict, args.trygui, args.smartfetch)) | ||
| 455 | 464 | workers.append(p) | |
| 456 | 465 | p.start() | |
| 457 | - | ||
| 466 | + | ||
| 458 | 467 | for url in urls: | |
| 459 | 468 | urlQueue.put(url) | |
| 460 | 469 | ||
| 461 | 470 | for p in workers: | |
| 462 | - try: | ||
| 463 | - p.join() | ||
| 464 | - except KeyboardInterrupt: | ||
| 465 | - print "[-] Ctrl-C received! Sending kill to threads..." | ||
| 466 | - kill_received = True | ||
| 467 | - for p in workers: | ||
| 468 | - p.terminate() | ||
| 471 | + p.join(.001) | ||
| 472 | + | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments