source: bin/bletchley-http2py @ 13

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

added http -> python conversion script

  • Property svn:executable set to *
File size: 4.8 KB
RevLine 
[4]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-2012 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(description='Process some integers.')
44parser.add_argument('requestfile', type=file, nargs='?', default=sys.stdin, 
45                    help='A file containing an HTTP request.  Defaults to stdin if omitted.')
46parser.add_argument('--burp', action='store_true', help='Input file is a XML export from Burp. (First request in file is used.)')
47args = parser.parse_args()
48
49if args.burp:
50    safe_parser = etree.ETCompatXMLParser(resolve_entities=False)
51    root = etree.parse(args.requestfile, parser=safe_parser)
52    input_req = root.xpath('/items/item/request')[0].text
53    root = None
54else:
55    input_req = args.requestfile.read()
56
57
58print('''#!/usr/bin/env python
59
60import sys
61# function with either Python 2.7 or 3.x
62try:
63    import http.client as httpc
64except:
65    import httplib as httpc
66''')
67
68
69if '\r\n\r\n' in input_req:
70    raw_headers,body = input_req.split('\r\n\r\n', 1)
71elif '\n\n' in input_req:
72    raw_headers,body = input_req.split('\n\n', 1)
73else:
74    raw_headers = input_req
75    body = ''
76
77header_lines = raw_headers.split('\n')
78method,path,version = header_lines[0].split(' ', 2)
79
80host = 'TODO'
81port = 0
82use_ssl = False
83
84headers = []
85for l in header_lines[1:]:
86    if len(l) < 1: 
87        break
88    # Handle header line continuations
89    if l[0] == '\t':
90        if len(headers) == 0:
91            continue
92        name,values = headers[-1]
93        values.append(l.lstrip('\t'))
94        headers[-1] = (name,values)
95        continue
96
97    name,value = l.split(':',1)
98    value = value.lstrip(' ').rstrip('\r')
99
100    # Skip headers that have to do with transfer encodings and connection longevity
101    if name.lower() not in ['accept','accept-language',
102                            'accept-encoding','accept-charset',
103                            'connection', 'keep-alive', 'host', 
104                            'content-length']:
105        headers.append((name,[value]))
106
107    if name.lower() == 'host':
108        if ':' in value:
109            host,port = value.split(':',1)
110            if port == 443:
111                use_ssl = True
112        else:
113            host = value
114
115print('''
116# TODO: ensure the host, port, and SSL settings are correct.
117host = %s
118port = %s
119use_ssl = %s
120''' % (repr(host),repr(port),repr(use_ssl)))
121
122print('''
123def sendRequest(connection):
124    method = %s
125    path = %s
126    body = %s
127
128    connection.putrequest(method, path)
129    ''' % (repr(method), repr(path), repr(body)))
130
131for name,values in headers:
132    if len(values) > 1:
133        continuations = ','.join([repr(v) for v in values[1:]])
134        print('''    connection.putheader(%s, %s, %s)''' % (repr(name),repr(values[0]),continuations))
135    else:
136        print('''    connection.putheader(%s, %s)''' % (repr(name),repr(values[0])))
137
138print('''   
139    if len(body) > 0:
140        connection.putheader('Content-Length', len(body))
141    connection.endheaders()
142    connection.send(body)
143   
144    return connection.getresponse()
145
146
147connection = None
148if use_ssl:
149    connection = httpc.HTTPSConnection(host, port)
150else:
151    connection = httpc.HTTPConnection(host, port)
152
153# TODO: customize code here to retrieve what you need from the response(s)
154# For information on the response object's interface, see:
155#   http://docs.python.org/library/httplib.html#httpresponse-objects
156
157connection.connect()
158response = sendRequest(connection)
159print(response.getheaders())
160print(repr(response.read()))
161connection.close()
162''')
Note: See TracBrowser for help on using the repository browser.