opexxx

UATester.py

May 19th, 2014
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 29.15 KB | None | 0 0
  1. #!/usr/bin/python
  2. # coding: utf-8
  3.  
  4. # UAtester
  5. #
  6. # Chris John Riley
  7. # blog.c22.cc
  8. # contact [AT] c22 [DOT] cc
  9. # 26/09/2010
  10. # Version: 1.06 BETA
  11. #
  12. # Changelog
  13. # 0.1 --> Initial version
  14. # 0.2 --> Improved redirect handling
  15. # 0.3 --> ASCII-ART for the WIN!
  16. # 0.4 --> Output formatting (Still not happy with this)
  17. # 0.5 --> Released for limited Alpha testing
  18. # 0.6 --> Changed handling of default UA strings (no need for -d), added verbose output, single mode -s, handler for URL without HTTP://
  19. # 0.7 --> Added Android default UA string, altered -h to reflect changes to usage
  20. # 0.8 --> Expanded on user feedback to avoid confusion of results, added feedback to clarify results, expanded default user agent strings (categorized)
  21. # 0.81 --> Added TRY to handle ctrl-c quits
  22. # 0.84 --> Redo response header comparison to cover full return headers, [+] Added Headers, [-] Removed Headers, [!] Altered Headers
  23. # 0.9 --> Added Set-Cookie comparison, Full headers
  24. # 0.93 --> Added ability to select type of default UAstrings to use -d/--default --> BETA
  25. # 0.94 --> Bug fixes and code consilidation. Increase Verbose feedback. Correct issues raised in BETA testing
  26. # 0.95 --> Cookie comparison
  27. # 0.98 --> Completed Secure and HTTPonly Cookie checks, added new browser UAstrings and Dangerous UA strings -d X
  28. #      --> Added formatting changes to correct line wraps on long UA Strings, URLS, etc...
  29. #      --> Updated positioning and minor tweaks to remove unused debug code
  30. # 1.00 --> BruCON release... Codename Purple Pimp
  31. # 1.01 --> Minor display bug-fix (verbose mode only)
  32. # 1.02 --> Corrected TextWrap configuration to make Python 2.5.x compatible (removed break_on_hyphens)
  33. # 1.03 --> Altered path to interpreter, corrected --help
  34. # 1.04 --> Added file output CSV format - Simple output, requires manual sorting to match removed, added headers
  35. # 1.05 --> Corrected minor display issues with blank UA strings
  36. # 1.06 --> Minor file handling correction....
  37.        
  38. import httplib
  39. import hashlib
  40. import urllib
  41. import urllib2
  42. import getopt
  43. import sys
  44. import re
  45. import time
  46. import socket
  47. import csv
  48. import string
  49. import os
  50. from textwrap import *
  51.  
  52. socket.setdefaulttimeout(15)
  53. rechecktime = 2 # Alter this value to increase of decrease the delay between initial stability checks (default:2)
  54. rechecks = 3 # Alter this value to decrease the number of stable checks (default/max:3)
  55. debug = 0
  56. err = 0
  57. err_2 = 0
  58. uafilepresent = False
  59. csvfilepresent = False
  60. single = False
  61. verbose = False
  62. uafile = False
  63. csvfile = False
  64. default = False
  65. default_options = False
  66. default_opts = 0
  67. cookie_names_ref = []
  68. cookie_names_ua = []
  69. cookie_full_ref = []
  70. cookie_full_ua = []
  71.  
  72. logo = '''
  73.  
  74.         _/    _/  _/_/_/_/       _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/
  75.        _/    _/  _/    _/          _/    _/       _/          _/    _/       _/    _/
  76.       _/    _/  _/_/_/_/  _/_/_/  _/    _/_/_/   _/_/_/_/    _/    _/_/_/   _/_/_/_
  77.      _/    _/  _/    _/          _/    _/             _/    _/    _/       _/    _/
  78.     _/_/_/_/  _/    _/          _/    _/_/_/_/ _/_/_/_/    _/    _/_/_/_/ _/      _/ [\x1B[35;40mv1.06\x1B[0m]
  79.  
  80.                                                                 _/ User-Agent Tester \x1B[35;40m↵\x1B[0m
  81.                                                                  _/ AKA: \x1B[35;40mPurple Pimp\x1B[0m ↵
  82.                                                                    _/ ChrisJohnRiley \x1B[35;40m↵\x1B[0m
  83.                                                                       _/ blog.c22.cc \x1B[35;40m↵\x1B[0m\n'''
  84.  
  85. usage = '''
  86.  
  87.  This tool is designed to automatically check a given URL using a list of standard and non-
  88.  standard User Agent strings provided by the user (1 per line).
  89.  
  90.  The results of these checks are then reported to the user for further manual analysis where
  91.  required. Gathered data includes Response Codes, resulting URL in the case of a 30x response,
  92.  MD5 and length of response body, and select Server headers.
  93.  
  94.  Results: When in non-verbose mode, only values that do not match the initial reference connection
  95.  are reported to the user. If no results are shown for a specific useragent then all results match
  96.  the initial reference connection. If you require a full output of all checks regardless of matches
  97.  to the reference, please use the verbose setting.
  98.  
  99.     Output:  [\x1B[35;40m+\x1B[0m] Added Headers, [\x1B[35;40m-\x1B[0m] Removed Headers, [\x1B[35;40m!\x1B[0m] Altered Headers, [ ] No Change
  100.  
  101.  Usage .:
  102.            -u / --url Complete URL
  103.            -f / --file <Path to User Agent file> / If no file is provided, -d options must be present
  104.            -s / --single provide single user-agent string (may need to be contained within quotes)
  105.            -d / --default Select the UA String type(s) to check. Select 1 or more of the following \x1B[35;40m↵\x1B[0m
  106.                            catagories. (\x1B[31;40mM\x1B[0m)obile, (\x1B[31;40mD\x1B[0m)esktop, mis(\x1B[31;40mC\x1B[0m), (\x1B[31;40mT\x1B[0m)ools, (\x1B[31;40mB\x1B[0m)ots, e(\x1B[31;40mX\x1B[0m)treme [\x1B[35;40m!\x1B[0m])
  107.            
  108.         -o / --output <Path to output file> CSV formated output (FILE WILL BE OVERWRITTEN[\x1B[31;40m!\x1B[0m])
  109.         -v / --verbose results (Displays full headers for each check) >> Recommended
  110.            --debug See debug messages (This isn't the switch you're looking for)\n
  111.  
  112.  Example .:
  113.  
  114.         ./UATester.py -u www.example.com -f ./useragentlist.txt -v
  115.         ./UATester.py -u https://www.wordpress.com
  116.         ./UATester.py -u http://www.defaultserver.com -v --debug
  117.         ./UATester.py -u facebook.com -v -d MDBX
  118.         ./UATester.py -u https://www.google.com -s "MySpecialUserAgent"
  119.         ./UATester.py -u blog.c22.cc -d MC -o ./output.csv\n'''
  120.  
  121. def main():
  122.    
  123.     try:
  124.         global err
  125.         global err_2
  126.         global default
  127.         global verbose
  128.         global TextWrapper
  129.        
  130.         # Setup Text Wrappers to make output uniformed
  131.        
  132.         REFWRAP = TextWrapper(replace_whitespace=False, width=110, initial_indent="    [ ] ", subsequent_indent="               ")
  133.         TXTWRAP = TextWrapper(replace_whitespace=False, width=110, subsequent_indent="               ")
  134.         PLUSWRAP = TextWrapper(replace_whitespace=False, width=110, initial_indent="    [+] ", subsequent_indent="              ")
  135.         MINUSWRAP = TextWrapper(replace_whitespace=False, width=110, initial_indent="    [-] ", subsequent_indent="             ")
  136.         UAWRAP = TextWrapper(replace_whitespace=False, width=110, initial_indent="\n\n [>] User-Agent String : ", subsequent_indent="                         ")
  137.        
  138.         if verbose == True: print " [*] Running in Verbose mode\n"
  139.         if debug == 1: print " [*] Running in Debug mode.... God help you!\n"
  140.        
  141.         #uastring = 'Nokia7650/1.0 Symbian-QP/6.1 Nokia/2.1' # UAstring used for testing configuration
  142.         uastring = 'Mozilla/5.0' # UAstring used for initial checks
  143.        
  144.         print " [>] Performing initial request and confirming stability\n",
  145.         print " [>] Using User-Agent string", uastring, '\n'
  146.        
  147.         if csvfilepresent == True:
  148.        
  149.             if os.path.exists(csvfile):
  150.                 print " [!] Output file already exists!\n"
  151.                 exit()
  152.                    
  153.             try:
  154.                 csvoutputfile_handle = open(csvfile, 'w') # Set output CSV file
  155.                 csvoutputfile = csv.writer(csvoutputfile_handle, dialect='excel')
  156.  
  157.             except:
  158.                 print"\n [!] Failed to open/create the output file specified. ", err
  159.                 print"\n [!| Thanks for coming.. bye!"
  160.                 exit()
  161.    
  162.         opener = urllib2.build_opener(SmartRedirectHandler())
  163.         req = urllib2.Request(url)
  164.         req.add_header('User-agent', uastring)
  165.    
  166.         try: resp = opener.open(req)
  167.         except socket.timeout, err:
  168.             print " [*] Socket Timeout: ", err
  169.         except socket.error,err_2:
  170.             print " [*] Socket Error: ", err
  171.         except urllib2.HTTPError, err:
  172.             print " [*] HTTPError: ", err
  173.         except urllib2.URLError, err:
  174.                 print " [*] URLError: ", err
  175.         except ValueError, err:
  176.             print " [*] ValueError: ", err, "\n"
  177.         if err: exit();
  178.  
  179.         try: ref_resp_statuscode = resp.status
  180.         except AttributeError, err:
  181.             ref_resp_statuscode = resp.code, resp.msg
  182.      
  183.         print '    [ ] URL (ENTERED):', url
  184.         ref_url = resp.geturl()
  185.         if url != resp.geturl():
  186.             print '    [!] URL (FINAL):',
  187.             for line in TXTWRAP.wrap(resp.geturl()): print line
  188.         if url != resp.geturl(): print '    [!] Response Code:', ref_resp_statuscode[0], ref_resp_statuscode[1]
  189.         else: print '    [ ] Response Code:', ref_resp_statuscode[0], ref_resp_statuscode[1]
  190.        
  191.         ref_headers = resp.info()
  192.         ref_headers_len = len(str(ref_headers).split('\n')) -1
  193.         ref_data = resp.read()
  194.         ref_md5 = hashlib.md5(ref_data)
  195.        
  196.         if csvfilepresent == True:
  197.             csvform = map(string.strip, ref_headers.headers)
  198.             csvform.insert(0, ref_resp_statuscode)
  199.             csvform.insert(0, resp.geturl())
  200.             csvform.insert(0, uastring)
  201.             csvform.append(ref_md5.hexdigest())
  202.             csvoutputfile.writerow(csvform)
  203.        
  204.         if debug == 1: print resp.info()
  205.        
  206.         i = 0
  207.         while i < ref_headers_len:
  208.        
  209.             for line in REFWRAP.wrap(ref_headers.headers[i]): print line
  210.             i=i+1
  211.  
  212.         print '    [ ] Data (MD5):', ref_md5.hexdigest(), "\n"
  213.    
  214.         i = 0
  215.         stable = 1
  216.         while i < rechecks:
  217.             time.sleep(rechecktime) # wait X second and recheck server - See rechecktime variable
  218.             req2 = req
  219.            
  220.             try:resp_2 = opener.open(req2)
  221.             except socket.timeout, err_2:
  222.                 print " [*] Socket Timeout: ", err_2
  223.             except socket.error,err_2:
  224.                 print " [*] Socket Error: ", err_2
  225.             except urllib2.HTTPError, err_2:
  226.                 print " [*] HTTPError: ", err_2
  227.             except urllib2.URLError, err_2:
  228.                 print " [*] URLError: ", err_2
  229.             except ValueError, err_2:
  230.                 print " [*] ValueError: ", err_2, "\n"
  231.             if err_2: print ' [*] ERR ', err_2; exit();
  232.            
  233.             try: ref_resp_2_statuscode = resp.status
  234.             except AttributeError, err:
  235.                 ref_resp_2_statuscode = resp.code, resp.msg
  236.            
  237.             if debug == 1: print "\n        [Debug RESP2] :", ref_resp_2_statuscode[0], ref_resp_2_statuscode[1]
  238.            
  239.             if debug == 1: print "\n    [Debug URL] :", resp_2.geturl(); print "    [Debug URL] :", resp.geturl();
  240.             if resp_2.geturl() != ref_url:
  241.                 print "\n [!] URL Value doesn't appear stable"
  242.                 print '    [!] URL (FINAL):',
  243.                 for line in TXTWRAP.wrap(resp_2.geturl()): print line
  244.                
  245.                 stable = 0
  246.                 url_stable = 0
  247.             else:  
  248.                 print " [\x1B[31;40m"+ str(i+1) +"\x1B[0m] Pass"
  249.            
  250.             stable_check_headers = resp_2.info()
  251.             stable_check_headers_len = len(str(stable_check_headers).split('\n')) -1
  252.             stable_check_data = resp_2.read()
  253.             stable_check_md5 = hashlib.md5(stable_check_data)
  254.            
  255.             if debug == 1: print resp_2.info()
  256.  
  257.             j = 0
  258.             exclude = 0
  259.             while j < stable_check_headers_len:
  260.                 if re.search(r'expires|vtag|etag|date|time|set-cookie|x-transaction|X-Cache|Age' , stable_check_headers.headers[j], re.IGNORECASE): # Ignore commonly changing headers
  261.                     exclude = 1
  262.            
  263.                 if exclude == 0:
  264.                     if debug == 1: print "\n    [Debug] :", stable_check_headers.headers[j],; print "   [Debug] :", ref_headers.headers[j],;
  265.                     if stable_check_headers.headers[j] != ref_headers.headers[j]:
  266.                         print ' [!] Instability Detected'
  267.                         stable = 0
  268.                         print '     [!]', ref_headers.headers[j],
  269.                         print '     [!]', stable_check_headers.headers[j],
  270.                        
  271.                 if i == 2 and re.search(r'set-cookie' , stable_check_headers.headers[j], re.IGNORECASE): # On last Stable check, gather cookie info for later comparison
  272.                     ref_cookie_temp = ref_headers.headers[j].split(':',1)
  273.                     ref_cookie_temp_2 = ref_headers.headers[j].split(';')
  274.                     ref_cookie_temp = ref_cookie_temp[1].split('=',1)
  275.                     if ref_cookie_temp[0] not in cookie_names_ref:
  276.                         cookie_names_ref.append(ref_cookie_temp[0])
  277.                         cookie_full_ref.append(stable_check_headers.headers[j])
  278.                        
  279.                 if stable != 1: break; # If the responses are not stable, break while loop - No point in checking 3 times if once will do
  280.                
  281.                 j=j+1
  282.            
  283.             i = i+1
  284.            
  285.             if debug == 1: print 'Cookies', cookie_names_ref
  286.    
  287.         if stable != 1:
  288.             print "\n [!] The URL given doesn't appear to give stable responses"
  289.             print " [!] Results may vary, and should be manually confirmed\n"
  290.         else:
  291.             print "\n [>] URL appears stable. Beginning test"
  292.  
  293. #
  294. # (BUILT-IN) UA STRINGS
  295. #
  296.        
  297.         def_uastrings_desktop = [
  298.    
  299.         # Default Browsers
  300.        
  301.         "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
  302.         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0)",
  303.         "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)",
  304.         "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)",
  305.         "Mozilla/4.0 (compatible;MSIE 5.5; Windows 98)",
  306.         "Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/4.0 (.NET CLR 3.5.30729)",
  307.         "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100922 Firefox/4.0.1",
  308.         "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.9.2) Gecko/20100101 Firefox/3.6",
  309.         "Mozilla/5.0 (X11; U; SunOS sun4v; en-US; rv:1.8.1.3) Gecko/20070321 Firefox/2.0.0.3",
  310.         "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7",
  311.         "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13",
  312.         "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8",
  313.         "Opera/9.99 (Windows NT 5.1; U; pl) Presto/9.9.9",
  314.         ]
  315.    
  316.         def_uastrings_bots = [
  317.    
  318.         # Spidering bots (Goolge, MSN, etc..)
  319.        
  320.         "Googlebot/2.1 (+http://www.google.com/bot.html)",
  321.         "Googlebot-Image/1.0",
  322.         "Mediapartners-Google",
  323.         "Mozilla/2.0 (compatible; Ask Jeeves)",
  324.         "msnbot-Products/1.0 (+http://search.msn.com/msnbot.htm)",
  325.         "mmcrawler",
  326.         ]
  327.    
  328.         def_uastrings_crazy = [
  329.        
  330.         # Crazy WTF stuff (TrackBack is the local Apache uastring)
  331.        
  332.         "Windows-Media-Player/9.00.00.4503",
  333.         "Mozilla/5.0 (PLAYSTATION 3; 2.00)",
  334.         "TrackBack/1.02",
  335.         "wispr",
  336.         "",
  337.         ]
  338.        
  339.         def_uastrings_dangerous = [
  340.        
  341.         # Possible dangerous strings, use at own risk! Not run unless selected through -d X
  342.        
  343.         "<script>alert('UATester')</script>",
  344.         "'",
  345.         "' or 22=22'--",
  346.         "%0d%0a",
  347.         "../../../../../../etc/passwd",
  348.         "../../../../../boot.ini",
  349.         "VUF0ZXN0ZXIgdGhlIHBydXBsZSBwaW1wIGVkaXRpb24=", # Base64 encoded string "UAtester the pruple pimp edition"
  350.         ]
  351.    
  352.         def_uastrings_tools = [
  353.    
  354.         # Commonly used tools. Additions from the Mod_Security ruleset
  355.        
  356.         "Mozilla/4.75 (Nikto/2.01)",
  357.         "curl/7.7.2 (powerpc-apple-darwin6.0) libcurl 7.7.2 (OpenSSL 0.9.6b)",
  358.         "w3af.sourceforge.net",
  359.         "HTTrack",
  360.         "Wget 1.9cvs-stable",
  361.         "Lynx (textmode)",
  362.         ".nasl",
  363.         "paros",
  364.         "webinspect",
  365.         "brutus",
  366.         "java",
  367.         ]
  368.    
  369.         def_uastrings_mobile = [
  370.        
  371.         # Mobile devices
  372.        
  373.         "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3",
  374.         "Mozilla/5.0 (iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10",
  375.         "Mozilla/5.0 (Linux; U; Android 2.1-update1; en-at; HTC Hero Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
  376.         "jBrowser-WAP",
  377.         "Nokia7650/1.0 Symbian-QP/6.1 Nokia/2.1"
  378.         ]
  379.  
  380. # NEW CHECK SECTION
  381.        
  382.         global default
  383.         default = True
  384.         uastrings = [] # Create empty list for UAstrings
  385.        
  386.         if uafilepresent == True:
  387.             print"\n [>] Reading User-Agents from: ", uafile
  388.             default = False # prevent default strigns from running
  389.            
  390.             try:
  391.                 uastrings_file = open (uafile) # Set uastrings to file contents
  392.  
  393.             except:
  394.                 print"\n [!] Failed to read the User-Agents from the file specified"
  395.                 print"\n [!| Thanks for coming.. bye!"
  396.                 exit(1)
  397.  
  398.             uastrings = uastrings_file.readlines() # Add all file contents into list
  399.  
  400.             try:
  401.                 uastrings_file.close() # Close file
  402.             except:
  403.                 print 'Unable to close file handle... sorry'
  404.                 exit(1)
  405.    
  406.         if single == True:
  407.             print"\n [>] Using SINGLE User-Agent String specified in commandline"
  408.             print" [!] Verbose mode activated for SINGLE mode testing"
  409.             verbose = True
  410.            
  411.             default = False # prevent default strigns from running
  412.             uastrings.append(single_uastring) # Set uastrings to Single
  413.    
  414.         if default == True:
  415.             print"\n [>] Using DEFAULT User-Agent Strings"
  416.                
  417.             if default_options == True:
  418.                    
  419.                 if 'M' in default_opts.upper():
  420.                     print"\n [>] Using Mobile User-Agent Strings",
  421.                     uastrings.extend(def_uastrings_mobile)
  422.                 if 'D' in default_opts.upper():
  423.                     print"\n [>] Using Desktop User-Agent Strings",
  424.                     uastrings.extend(def_uastrings_desktop)
  425.                 if 'C' in default_opts.upper():
  426.                     print"\n [>] Using Crazy User-Agent Strings",
  427.                     uastrings.extend(def_uastrings_crazy)
  428.                 if 'T' in default_opts.upper():
  429.                     print"\n [>] Using Tool User-Agent Strings",
  430.                     uastrings.extend(def_uastrings_tools)
  431.                 if 'B' in default_opts.upper():
  432.                     print"\n [>] Using Bot User-Agent Strings",
  433.                     uastrings.extend(def_uastrings_bots)
  434.                 if 'X' in default_opts.upper():
  435.                     print"\n [>] Using Dangerous User-Agent Strings\n [>] Contine at your own risk"
  436.                     answer = raw_input("\n    [>] Press Y to accept >> ")
  437.                     if answer.upper() != 'Y':
  438.                         print"\n [>] Bam... pimp slap!\n"
  439.                         exit();
  440.                     else: print"\n [>] 00OOooh Who da' man! Well don't say you didn't ask for it!"
  441.                     uastrings.extend(def_uastrings_dangerous)
  442.            
  443.             else: uastrings.extend(def_uastrings_mobile);uastrings.extend(def_uastrings_desktop);uastrings.extend(def_uastrings_crazy);uastrings.extend(def_uastrings_tools);uastrings.extend(def_uastrings_bots)
  444.        
  445.         print "\n\n [>] Output: [+] Added Headers, [-] Removed Headers, [!] Altered Headers, [ ] No Change"
  446.        
  447.         header_printed_global = False
  448.        
  449.         for ualine in uastrings:
  450.             err = 0    
  451.             current = ualine
  452.             header_printed = False
  453.  
  454.             req = urllib2.Request(url)
  455.             req.add_header('User-agent', ualine)
  456.            
  457.             try: resp2 = opener.open(req)
  458.             except socket.timeout, err:
  459.                 print " [*] Socket Timeout: ", err
  460.             except socket.error,err_2:
  461.                 print " [*] Socket Error: ", err
  462.             except urllib2.HTTPError, err:
  463.                 print " [*] HTTPError: ", err
  464.             except urllib2.URLError, err:
  465.                 print " [*] URLError: ", err
  466.             except ValueError, err:
  467.                 print " [*] ValueError: ", err, "\n"
  468.             if err: exit();
  469.            
  470.             if ualine == "": ualine = "EMPTY USER-AGENT STRING\x1B[31;40m!\x1B[0m" # Set to inform user of empty string
  471.    
  472.             ua_check_headers = resp2.info()
  473.             ua_check_headers_len = len(str(ua_check_headers).split('\n')) -1
  474.             ua_check_data = resp2.read()
  475.             ua_check_md5 = hashlib.md5(ua_check_data)
  476.            
  477.             try: statuscode = resp2.status
  478.             except AttributeError, err:
  479.                 statuscode = resp2.code, resp2.msg
  480.            
  481.             if csvfilepresent == True:
  482.                 csvform = []
  483.                 csvform = map(string.strip, ua_check_headers.headers)
  484.                 csvform.insert(0, statuscode)
  485.                 csvform.insert(0, resp2.geturl())
  486.                 csvform.insert(0, ualine)
  487.                 csvform.append(ua_check_md5.hexdigest())
  488.                 csvoutputfile.writerow(csvform)
  489.            
  490.             if debug == 1: print resp2.info()
  491.                
  492.             if ref_url != resp2.geturl() or verbose == True:
  493.                 icon = ' '
  494.                 if ref_url != resp2.geturl(): icon = '\x1B[35;40m!\x1B[0m'
  495.                 for line in UAWRAP.wrap(ualine): print line
  496.                 print '\n'
  497.                 print '    [' + icon + '] URL (FINAL):',
  498.                 for line in TXTWRAP.wrap(resp2.geturl()): print line
  499.                 header_printed = True
  500.                 header_printed_global = True
  501.                
  502.             ua_check_statuscode = statuscode
  503.            
  504.             if ref_resp_statuscode[0] != ua_check_statuscode[0] or verbose == True:
  505.                 if header_printed == False:
  506.                     for line in UAWRAP.wrap(ualine): print line
  507.                     print '\n'
  508.                 icon = ' '
  509.                 if ref_resp_statuscode[0] != ua_check_statuscode[0]: icon = '\x1B[35;40m!\x1B[0m'
  510.                 print '    [' + icon + '] Response Code:', ua_check_statuscode[0],ua_check_statuscode[1]; match = True
  511.                 header_printed = True
  512.                 header_printed_global = True
  513.                
  514.             j = 0
  515.             exclude = 0
  516.    
  517.             while j < ua_check_headers_len:
  518.                
  519.                 if verbose == False and re.search(r'expires|vtag|date|time|x-transaction|Set-Cookie|X-Cache|Age' , ua_check_headers.headers[j], re.IGNORECASE): # Ignore commonly changing headers
  520.                     exclude = 1
  521.        
  522.                 if exclude == 0:
  523.                     ua_check_headers_match = ua_check_headers.headers[j].split(':',1)
  524.                     if debug == 1:
  525.                         if header_printed == False:
  526.                             for line in UAWRAP.wrap(ualine): print line
  527.                             print '\n'
  528.                         header_printed = True
  529.                         header_printed_global = True
  530.  
  531.                     k = 0
  532.                     while k < ref_headers_len:
  533.                         ref_headers_match = ref_headers.headers[k].split(':',1)
  534.                         if debug == 1:
  535.                             if header_printed == False:
  536.                                 for line in UAWRAP.wrap(ualine): print line
  537.                                 print '\n'
  538.                             header_printed = True
  539.                             header_printed_global = True
  540.                        
  541.                         if ua_check_headers_match[0] == ref_headers_match[0]:
  542.                             header_match = 1
  543.                             if ua_check_headers_match[1] == ref_headers_match[1]:
  544.                                 value_match = 1
  545.                                 if verbose == True:
  546.                                     if header_printed == False:
  547.                                         for line in UAWRAP.wrap(ualine): print line
  548.                                         print '\n'
  549.                                     header_printed = True
  550.                                     header_printed_global = True
  551.                                     for line in REFWRAP.wrap(ua_check_headers.headers[j]): print line
  552.                                     #print '    [ ]', ua_check_headers.headers[j],
  553.                                 break;
  554.                             else:
  555.                                 if header_printed == False:
  556.                                     for line in UAWRAP.wrap(ualine): print line
  557.                                     print '\n'
  558.                                 header_printed = True
  559.                                 header_printed_global = True
  560.                                 if re.search(r'Set-Cookie' , ua_check_headers.headers[j], re.IGNORECASE):
  561.                                     break;
  562.                                 else:
  563.                                     print '    [!]', ua_check_headers.headers[j],
  564.                                 break;
  565.                         k=k+1
  566.                        
  567.                     if k == ref_headers_len and header_match == 0:
  568.                         print '    [+]', ua_check_headers.headers[j],
  569.                
  570.                 if re.search(r'set-cookie' , ua_check_headers.headers[j], re.IGNORECASE):
  571.                     ua_cookie_temp = ua_check_headers.headers[j].split(':',1)
  572.                     ua_cookie_temp = ua_cookie_temp[1].split('=',1)
  573.                     if ua_cookie_temp[0] not in cookie_names_ua:
  574.                         cookie_names_ua.append(ua_cookie_temp[0])
  575.                         cookie_full_ua.append(ua_check_headers.headers[j])
  576.                
  577.                 j=j+1
  578.                
  579.                 if j == ua_check_headers_len:
  580.                     if debug == 1:print ' ua and ref cookies =', cookie_names_ua, cookie_names_ref
  581.                    
  582.                     l = 0
  583.                     k = 0
  584.  
  585.                     while l < len(cookie_names_ua):    
  586.                        
  587.                         cookie_name = str(cookie_names_ua[l])
  588.                         try: ref_match = cookie_names_ref.index(cookie_name)
  589.                         except: ref_match = False
  590.                        
  591.                         if cookie_names_ua[l] not in cookie_names_ref:
  592.                             if header_printed == False:
  593.                                 for line in UAWRAP.wrap(ualine): print line
  594.                                 print '\n'
  595.                                 header_printed = True
  596.                                 header_printed_global = True
  597.                                
  598.                             for line in PLUSWRAP.wrap(cookie_full_ua[l]): print line
  599.                         else:
  600.                        
  601.                             httponly = False
  602.                             httponly_ref = False
  603.                             httponly_ua = False
  604.                             secure = False
  605.                             secure_ref = False
  606.                             secure_ua = False # Reset results for next Cookie
  607.                            
  608.                             if re.search(r'httponly', cookie_full_ua[l] , re.IGNORECASE) or re.search(r'httponly', cookie_full_ref[ref_match] , re.IGNORECASE):
  609.                                 httponly = True # Mark httponly flag found
  610.                                 if re.search(r'httponly', cookie_full_ref[ref_match] , re.IGNORECASE): httponly_ref = True
  611.                                 if re.search(r'httponly', cookie_full_ua[l] , re.IGNORECASE): httponly_ua = True
  612.                            
  613.                             if re.search(r'secure', cookie_full_ua[l] , re.IGNORECASE) or re.search(r'secure', cookie_full_ref[ref_match] , re.IGNORECASE):
  614.                                 secure = True # Mark secure flag found
  615.                                 if re.search(r'secure', cookie_full_ref[ref_match] , re.IGNORECASE): secure_ref = True
  616.                                 if re.search(r'secure', cookie_full_ua[l] , re.IGNORECASE): secure_ua = True
  617.                            
  618.                             if httponly_ref != httponly_ua:
  619.                                 print '    [!]', cookie_full_ua[l],
  620.                                 if httponly_ref == False: print '        [+] HTTPonly flag set'
  621.                                 else: print '        [-] HTTPonly flag removed'
  622.                             if secure_ref != secure_ua:
  623.                                 print '    [!]', cookie_full_ua[l],
  624.                                 if secure_ref == False: print '        [+] Secure flag set'
  625.                                 else: print '        [-] Secure flag removed'
  626.                            
  627.                             if httponly == False and secure == False:
  628.                                 if cookie_names_ua[l] in cookie_names_ref and verbose == True:
  629.                                     for line in REFWRAP.wrap(cookie_full_ua[l]): print line
  630.                            
  631.                            
  632.                         l=l+1
  633.                     while k < len(cookie_names_ref):
  634.                         if cookie_names_ref[k] not in cookie_names_ua:
  635.                             if header_printed == False:
  636.                                 for line in UAWRAP.wrap(ualine): print line
  637.                                 print '\n'
  638.                                 header_printed = True
  639.                                 header_printed_global = True
  640.                                
  641.                             for line in MINUSWRAP.wrap(cookie_full_ref[k]): print line
  642.                         k=k+1
  643.    
  644.                 exclude = 0
  645.                 header_match = 0
  646.                 value_match = 0
  647.    
  648.             j = 0 # Reset counter for missing header check
  649.             exclude = 0
  650.             while j < ref_headers_len:
  651.                 ref_headers_match = ref_headers.headers[j].split(':',1)
  652.                 k = 0
  653.                 while k < ua_check_headers_len:
  654.                     ua_check_headers_match = ua_check_headers.headers[k].split(':',1)
  655.                     if ref_headers_match[0] == ua_check_headers_match[0]:
  656.                         header_match = 1
  657.                         break;
  658.    
  659.                     k=k+1
  660.                    
  661.                 if k == ua_check_headers_len and header_match != 1:
  662.                     if header_printed == False:
  663.                         for line in UAWRAP.wrap(ualine): print line
  664.                         print '\n'
  665.                         header_printed = True
  666.                         header_printed_global = True
  667.                     for line in MINUSWRAP.wrap(ref_headers.headers[j]): print line
  668.                            
  669.                 j=j+1
  670.                 exclude = 0
  671.                 header_match = 0
  672.                 value_match = 0
  673.    
  674.             if ref_md5.hexdigest() != ua_check_md5.hexdigest():
  675.                 if header_printed == False:
  676.                     for line in UAWRAP.wrap(ualine): print line
  677.                     print '\n'
  678.                     print '    [!] Data (MD5):', ua_check_md5.hexdigest()
  679.             elif verbose == True:
  680.                 if header_printed == False:
  681.                     for line in UAWRAP.wrap(ualine): print line
  682.                     print '\n'
  683.                     header_printed = True
  684.                     header_printed_global = True
  685.                 print '    [ ] Data (MD5):', ua_check_md5.hexdigest();
  686.            
  687.         print "\n"
  688.         if header_printed_global == False: print " [>] Checks completed... try enabling VERBOSE mode for more detailed output\n"   
  689.         if csvfilepresent == True:
  690.             try:
  691.                 csvoutputfile_handle.close() # Close file
  692.             except:
  693.                 print 'Unable to close output file handle... sorry', err
  694.                 exit(1)
  695.        
  696.         print " [>] That's all folks... Fo' Shizzle!"
  697.         print "\n"
  698.        
  699.     except KeyboardInterrupt: print '\n\n [*] Error: ctrlc_caught'; print ' [*] Thanks for coming... keep on pimpin!\n'; exit()
  700.            
  701. class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
  702.    
  703.     def http_error_301(self, req, fp, code, msg, headers):  
  704.         result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)              
  705.         try: result.status = code, msg
  706.         except: result.status = 'No Status Code in Return Header'      
  707.         return result
  708.    
  709.     def http_error_302(self, req, fp, code, msg, headers):
  710.         result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
  711.         try: result.status = code, msg
  712.         except: result.status = 'No Status Code in Return Header'
  713.     return result
  714.    
  715.     def http_error_303(self, req, fp, code, msg, headers):
  716.         result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
  717.         try: result.status = code, msg
  718.         except: result.status = 'No Status Code in Return Header'
  719.         return result
  720.  
  721.     def http_error_307(self, req, fp, code, msg, headers):
  722.         result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
  723.         try: result.status = code, msg
  724.         except: result.status = 'No Status Code in Return Header'
  725.         return result
  726.        
  727. try:
  728.     opts, args = getopt.getopt(sys.argv[1:], "u:f:s:d:o:vh", ["url=", "file=", "single", "default=", "output=", "verbose", "help", "debug"])
  729. except getopt.GetoptError:
  730.     print (logo)
  731.     print (usage)
  732.     sys.exit(2)
  733. if len(sys.argv) < 3:
  734.         print (logo)
  735.         print (usage)
  736.     sys.exit(2)
  737. for opt, arg in opts:
  738.     if opt in ("-h", "--help"):
  739.         print (logo)
  740.         print (usage)
  741.         sys.exit()
  742.     elif opt in ("-u", "--url"):
  743.         url = arg.lower()
  744.         if url.startswith("http"): url = arg
  745.         else: url = "http://" +arg
  746.     elif opt in ("-f", "--file"):
  747.         uafile = arg
  748.         uafilepresent = True
  749.         elif opt in ("-s", "--single"):
  750.                 single_uastring = arg
  751.                 single = True
  752.         elif opt in ("-d", "--default"):
  753.                 if arg == ' ': arg = 'MDCTB'
  754.                 default_opts = arg
  755.                 default_options = True
  756.     elif opt in ("-o", "--output"):
  757.         csvfile = arg
  758.         csvfilepresent = True
  759.     elif opt in ("-v", "--verbose"):
  760.         verbose = True
  761.     elif opt in ("--debug"):
  762.         debug = 1
  763.  
  764. if __name__== '__main__':  
  765.    print (logo)
  766.    main()
Add Comment
Please, Sign In to add comment