Snippets

grimhacker raw2proxy.py

Created by grimhacker last modified
'''
.       .1111...          | Title: raw2proxy.py
    .10000000000011.   .. | Author: Oliver Morton (Sec-1 Ltd)
 .00              000...  | Email: oliverm-tools@sec-1.com
1                  01..   | Description:
                    ..    | Parse files containing raw HTTP requests and
                   ..     | make these requests via a proxy.
GrimHacker        ..      |
                 ..       |
grimhacker.com  ..        |
@grimhacker    ..         |
----------------------------------------------------------------------------
Raw2Proxy - Send Raw HTTP Requests to a Proxy
    Copyright (C) 2015  Oliver Morton (Sec-1 Ltd)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
'''

__version__ = "$Revision: 1.0 $"
# $Source$

import os
import sys
import argparse
import logging
import urllib2
from BaseHTTPServer import BaseHTTPRequestHandler
from StringIO import StringIO


class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, raw_request):
        self.rfile = StringIO(raw_request)
        self.raw_requestline = self.rfile.readline()
        self.error_code = None
        self.error_message = None
        self.parse_request()

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message


def make_request(raw_request, protocol="http", proxy={'http': '127.0.0.1:8080', 'https': '127.0.0.1:8080'}):
    try:
        logging.debug("Parsing raw_request")
        request = HTTPRequest(raw_request)  #Parse the raw request to an object.
    except Exception as e:
        raise Exception("Failed to parse raw request. {0}".format(e))
    try:
        # Extract the information we need from the request object:
        logging.debug("Extracting required information")
        host = request.headers.get('host')
        url = "{protocol}://{host}{path}".format(protocol=protocol, host=host, path=request.path)
        body = request.rfile.read()
        args = {'headers': request.headers}
        if body:
            args['data'] = body  # Add body parameters if they exist.
    except Exception as e:
        raise Exception("Failed to extract fields from parsed request. {0}".format(e))
    try:
        # Create the Proxy Handler so we go through the proxy
        logging.debug("Creating ProxyHandler")
        proxy_handler = urllib2.ProxyHandler(proxy)
        logging.debug("Creating Opener")
        opener = urllib2.build_opener(proxy_handler)
        urllib2.install_opener(opener)
        # Build the HTTP Request
        logging.debug("Building HTTP request")
        url_request = urllib2.Request(url, **args)
        url_request.get_method = lambda: request.command  # Handle methods (PUT, DELETE, GET, etc)
    except Exception as e:
        raise Exception("Failed to create opener. {0}".format(e))
    try:
        # Send the HTTP Request
        logging.debug("Sending HTTP request")
        response = opener.open(url_request)
        logging.debug("Response = {0}".format(response.read()))  # Print the response
    except urllib2.HTTPError, error:
        contents = error.read()
        logging.debug("Error response = {0}".format(contents))  # Print the error response
    except Exception as e:
        raise Exception("Failed to send request. {0}".format(e))

def main(files, protocol, proxy):
    failed = []
    try:
        for file_ in files:
            logging.info("Handling: {0}".format(file_))
            try:
                with open(file_, "r") as f:
                    raw_request = f.read()
                    try:
                        make_request(raw_request, protocol=protocol, proxy={'https': proxy, 'http': proxy})
                    except Exception as e:
                        failed.append((file_, e))
                        logging.warning("Error handling: {0} - {1}".format(file_, e))
            except Exception as e:
                failed.append((file_, e))
                logging.warning("Error reading: {0} - {1}".format(file_, e))
    except Exception as e:
        for file_ in files:
            failed.append((file_, e))
        logging.critical("Error: {0}".format(e))
    if failed:
        print
        logging.warning("The following requests were not successfully handled and may not be in your proxy:\n{0}".format("\n".join(str(file_) for file_, reason in failed)))
    logging.info("Done. Check your proxy.")

def print_version():
    """Print command line version banner."""
    print """
.       .1111...          | Title: raw2proxy.py  {0}
    .10000000000011.   .. | Author: Oliver Morton (Sec-1 Ltd)
 .00              000...  | Email: oliverm-tools@sec-1.com
1                  01..   | Description:
                    ..    | Parse files containing raw HTTP requests and
                   ..     | make these requests via a proxy.
GrimHacker        ..      |
                 ..       |
grimhacker.com  ..        |
@grimhacker    ..         |
----------------------------------------------------------------------------
""".format(__version__)

if __name__ == "__main__":
    print """
    Raw2Proxy - Send Raw HTTP Requests to a Proxy {0}
    Copyright (C) 2015  Oliver Morton (Sec-1 Ltd)
    This program comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it
    under certain conditions. See GPLv2 License.
""".format(__version__)

    parser = argparse.ArgumentParser(description="Send Raw HTTP Requests to a Proxy")
    parser.add_argument("-V", "--version", help="Print version banner", action="store_true")
    parser.add_argument("-v", "--verbose", help="Debug logging", action="store_true")
    parser.add_argument("-d", "--directory", help="Directory containing raw HTTP requests in files")
    parser.add_argument("-f", "--files", help="Files containing raw HTTP requests", nargs="+")
    parser.add_argument("-p", "--proxy", help="HTTP Proxy to send requests via. DEFAULT=127.0.0.1:8080", default="127.0.0.1:8080")
    parser.add_argument("--https", help="Use HTTPS", action="store_true")
    args = parser.parse_args()

    if args.version:
        print_version()
        exit()
    
    if args.verbose:
        level = logging.DEBUG
    else:
        level = logging.INFO
    logging.basicConfig(level=level,
                        format="%(levelname)s: %(message)s")

    if not (args.files or args.directory):
        logging.critical("Specify directory and/or files!")
        parser.print_usage()
        exit()

    files = []
    if args.files:
        logging.debug("Getting file names from command line")
        files += args.files
    if args.directory:
        logging.debug("Getting file names from directory '{0}'".format(args.directory))
        try:
            for (dirpath, dirnames, filenames) in os.walk(args.directory):
                for filename in filenames:
                    files.append(os.path.join(dirpath, filename))
                break
        except Exception as e:
            logging.critical("Failed to get file names from directory '{0}'".format(args.directory))
            exit()

    protocol = "http"
    if args.https:
        protocol = "https"

    main(files, protocol, args.proxy)

Comments (1)

  1. Jason Ross

    This worked great for me, but I needed it to do HTTPS and handle invalid certificates. That turned out to be fairly straight forward. Here's a diff -u of the change:

    --- orig    2017-06-07 13:41:24.000000000 -0400
    +++ /Users/jross/bin/raw2proxy.py   2017-06-07 13:38:55.000000000 -0400
    @@ -1,3 +1,4 @@
    +#!/usr/bin/env python
     '''
     .       .1111...          | Title: raw2proxy.py
         .10000000000011.   .. | Author: Oliver Morton (Sec-1 Ltd)
    @@ -33,6 +34,7 @@
    
     import os
     import sys
    +import ssl
     import argparse
     import logging
     import urllib2
    @@ -77,6 +79,9 @@
             logging.debug("Creating Opener")
             opener = urllib2.build_opener(proxy_handler)
             urllib2.install_opener(opener)
    +        # ignore invalid certs
    +        context = ssl._create_unverified_context()
    +   opener.context = context
             # Build the HTTP Request
             logging.debug("Building HTTP request")
             url_request = urllib2.Request(url, **args)