#!/usr/bin/env python import getopt, sys, re, urllib2, urllib, BaseHTTPServer from urllib2 import Request, urlopen, URLError, HTTPError ################## HEADER ################################### # # Traceroute-like HTTP scanner # Using the "Max-Forwards" header # RFC 2616 - HTTP/1.1 - Section 14.31 # RFC 3261 - SIP - Section 8.1.1.6 # # # By Nicolas Gregoire (nicolas.gregoire@agarri.fr) # # 0.5 : First public release # 0.4 : Private release, looking for bugs - More heuristics # 0.3 : A lot more options - More verbosity levels - Some heuristics # # By Julien Cayssol (tools@aqwz.com) # # 0.2 : Add extract of headers # 0.1 : Initial version # # # Heuristics : # - Status Codes : # - HTTP Status Code == 502 # - HTTP Status Code == 483 # - Specific data in body or headers : # - X-Forwarded-For in body when using TRACE # - Via or X-Via in headers # - Differences between hops : # - HTTP Status Codes # - Server headers # - Content-Type headers # - Via headers # - HTML titles # - HTML
tags # - X-Forwarded-For values when using TRACE # ############## GLOBAL VARIABLES ################################### global_data = { 'StatusCode':{}, 'Server':{} , 'Content-Type':{}, 'Title':{}, 'Address':{}, 'X-Fwd':{}, 'Via':{} } score = 0 verbosity = 0 scheme = 'http' host = '127.0.0.1' port = '80' path = '/' method = 'TRACE' body_content = None max_fwds = 3 userAgent = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko/20060502 Firefox/1.5.0.2' contentType = 'text/html' ############## FUNCTIONS ################################### # Pretty printing def zprint(string, flag = '=='): print '[' + flag + '] ' + string # Increment the heuristic score def inc_score(): global score score = score + 1 if verbosity: zprint('Score : ' + str(score), '!!') # Help def showUsage(): print 'Usage : ' + sys.argv[0] + ' [-h] [-m method] [-s scheme] [-t target] [-p port] [-P path] [-v 0|1|2] [-f forwards]' print '\t[-h] Help (this text)' print '\t[-m] HTTP Method : default is "TRACE"' print '\t[-s] Scheme : default is "http"' print '\t[-t] Target host : default is "127.0.0.1"' print '\t[-p] Port : default is "80"' print '\t[-P] Path : default is "/"' print '\t[-f] Max # of forwards : default is "3"' print '\t[-v] Verbosity : 0 = default, 1 = verbose, 2 = debug' print 'Examples :' print sys.argv[0] + ' -t www.example.org' print ' => TRACE /' print sys.argv[0] + ' -t www.example.org -m GET -s https -p 443 -v 1' print ' => GET / on a SSL host' print sys.argv[0] + ' -t www.example.org -m POST -P /axis2/checkacc -v 2 -f 5' print ' => Debug mode on a specific end-point' sys.exit(1) # Parse CLI args def getArguments(): try: if len(sys.argv) < 2: zprint('No arguments ? Probably a bad choice. Use "-h" ...', '!!') sys.exit(1) optlist, list = getopt.getopt(sys.argv[1:], 'hm:s:t:p:P:v:f:') except getopt.GetoptError: showUsage() for opt in optlist: if opt[0] == '-h': showUsage() if opt[0] == '-m': global method method = opt[1] if opt[0] == '-s': global scheme scheme = opt[1] if opt[0] == '-t': global host host = opt[1] if opt[0] == '-p': global port port = opt[1] if opt[0] == '-P': global path path = opt[1] if opt[0] == '-v': global verbosity verbosity = int(opt[1]) if opt[0] == '-f': global max_fwds max_fwds = int(opt[1]) # Extract some interesting data from the headers def analyse_headers(data): if verbosity: print zprint('Analyzing headers', '**') wanted_headers = [ 'Server', 'Via', 'X-Via', 'Set-Cookie', 'X-Forwarded-For', 'Content-Type', 'Content-Length', 'Last-Modified', 'Location', 'Date', ] for h_name in wanted_headers: h_value = data.getheader(h_name) if h_value != None: # Print the value if verbosity: zprint(h_value, h_name) # Add it to the global structure if needed if h_name == 'Server' or h_name == 'Content-Type': global_data[h_name][hop] = h_value # Some heuristics if h_name == 'Via' or h_name == 'X-Via': zprint('"Via" header : Probably a reverse proxy', '++') global_data['Via'][hop] = h_value inc_score() # Extract some interesting data from the body def analyse_body(data): if verbosity: print zprint('Analyzing body', '**') wanted_patterns = [ '