source: trunk/bin/bletchley-http2py @ 39

Last change on this file since 39 was 39, checked in by tmorgan, 12 years ago

misc output improvements, putting more items in organized functions

  • Property svn:executable set to *
File size: 5.5 KB
Line 
1#!/usr/bin/env python
2
3# Requires Python 2.7+
4
5'''
6This script reads a raw HTTP request from stdin and writes to stdout
7a Python script.  The generated script sends the same (or a very similar)
8request using the httplib/http.client libraries.
9
10Certainly if you have a raw request, you could simply send it via TCP
11sockets, but if for some reason the server behaves oddly with flow control,
12insists on using gzip/deflate encoding, insists on using chunked encoding,
13or any number of other annoying things, then using an HTTP library is a
14lot more convenient.  This script attempts to make that conversion easy.
15
16
17Copyright (C) 2011-2013 Virtual Security Research, LLC
18Author: Timothy D. Morgan
19
20 This program is free software: you can redistribute it and/or modify
21 it under the terms of the GNU Lesser General Public License, version 3,
22 as published by the Free Software Foundation.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program.  If not, see <http://www.gnu.org/licenses/>.
31'''
32
33
34import sys
35import argparse
36try:
37    from lxml import etree
38except:
39    sys.stderr.write('ERROR: Could not import lxml module.  Ensure it is installed.\n')
40    sys.stderr.write('       Under Debian, the package name is "python-lxml"\n.')
41    sys.exit(1)
42
43parser = argparse.ArgumentParser(
44    description='A script which accepts an HTTP request and prints out a'
45    ' generated Python script which sends a similar request.  This is useful'
46    ' when one wants to automate sending a large number of requests to a'
47    ' particular page or application.'
48    ' For more information, see: http://code.google.com/p/bletchley/wiki/Overview')
49parser.add_argument(
50    'requestfile', type=file, nargs='?', default=sys.stdin, 
51    help='A file containing an HTTP request.  Defaults to stdin if omitted.')
52parser.add_argument(
53    '--burp', action='store_true', help='Input file is a XML export from Burp.'
54    ' (First request in file is used.)')
55args = parser.parse_args()
56
57if args.burp:
58    safe_parser = etree.ETCompatXMLParser(resolve_entities=False)
59    root = etree.parse(args.requestfile, parser=safe_parser)
60    input_req = root.xpath('/items/item/request')[0].text
61    root = None
62else:
63    input_req = args.requestfile.read()
64
65
66
67if '\r\n\r\n' in input_req:
68    raw_headers,body = input_req.split('\r\n\r\n', 1)
69elif '\n\n' in input_req:
70    raw_headers,body = input_req.split('\n\n', 1)
71else:
72    raw_headers = input_req
73    body = ''
74
75header_lines = raw_headers.split('\n')
76method,path,version = header_lines[0].split(' ', 2)
77
78host = 'TODO'
79port = 80
80use_ssl = False
81
82headers = []
83for l in header_lines[1:]:
84    if len(l) < 1: 
85        break
86    # Handle header line continuations
87    if l[0] == '\t':
88        if len(headers) == 0:
89            continue
90        name,values = headers[-1]
91        values.append(l.lstrip('\t'))
92        headers[-1] = (name,values)
93        continue
94
95    name,value = l.split(':',1)
96    value = value.lstrip(' ').rstrip('\r')
97
98    # Skip headers that have to do with transfer encodings and connection longevity
99    if name.lower() not in ['accept','accept-language',
100                            'accept-encoding','accept-charset',
101                            'connection', 'keep-alive', 'host', 
102                            'content-length', 'proxy-connection']:
103        headers.append((name,[value]))
104
105    if name.lower() == 'host':
106        if ':' in value:
107            host,port = value.split(':',1)
108            if port == 443:
109                use_ssl = True
110        else:
111            host = value
112
113
114print('''#!/usr/bin/env python
115
116import sys
117# function with either Python 2.7 or 3.x
118try:
119    import http.client as httpc
120except:
121    import httplib as httpc
122''')
123
124
125print('''
126# TODO: ensure the host, port, and SSL settings are correct.
127host = %s
128port = %s
129use_ssl = %s
130''' % (repr(host),repr(port),repr(use_ssl)))
131
132chunked_body = '\n            '.join([repr(body[i:i+40]) for i in range(0,len(body),40)])
133if chunked_body == '':
134    chunked_body = "''"
135
136print('''
137# TODO: use "data" to supply any parameters to be included in the request
138def sendRequest(connection, data=None):
139    method = %s
140    path = %s
141    body = (%s)
142   
143    connection.putrequest(method, path)
144    ''' % (repr(method), repr(path), chunked_body))
145
146for name,values in headers:
147    if len(values) > 1:
148        continuations = ','.join([repr(v) for v in values[1:]])
149        print('''    connection.putheader(%s, %s, %s)''' % (repr(name),repr(values[0]),continuations))
150    else:
151        print('''    connection.putheader(%s, %s)''' % (repr(name),repr(values[0])))
152
153print('''   
154    if len(body) > 0:
155        connection.putheader('Content-Length', len(body))
156    connection.endheaders()
157    connection.send(body)
158   
159    return connection.getresponse()
160
161
162def newConnection():
163    connection = None
164    if use_ssl:
165        return httpc.HTTPSConnection(host, port)
166    else:
167        return httpc.HTTPConnection(host, port)
168
169
170def fetch(data):
171    ret_val = None
172    connection = newConnection()
173
174    # TODO: customize code here to retrieve what you need from the response(s)
175    # For information on the response object's interface, see:
176    #   http://docs.python.org/library/httplib.html#httpresponse-objects
177    response = sendRequest(connection, data)
178    print(response.getheaders())
179    print(repr(response.read()))
180
181    connection.close()
182    return ret_val
183
184data = ''
185fetch(data)
186''')
Note: See TracBrowser for help on using the repository browser.