source: trunk/bin/bletchley-http2py @ 77

Last change on this file since 77 was 73, checked in by tim, 10 years ago

added PKCS12 capabilities to clonecertchain

  • Property svn:executable set to *
File size: 7.5 KB
Line 
1#!/usr/bin/env python3
2#-*- mode: Python;-*-
3#
4# Requires Python 3+
5
6'''
7This script reads a raw HTTP request and writes to stdout a Python
8script.  The generated script sends the same (or a very similar)
9request using the standard httplib/http.client library, or optionally
10using the more user friendly python-requests library.
11
12Certainly if you have a raw request, you could simply send it via TCP
13sockets, but if for some reason the server behaves oddly with flow control,
14insists on using gzip/deflate encoding, insists on using chunked encoding,
15or any number of other annoying things, then using an HTTP library is a
16lot more convenient.  This script attempts to make that conversion easy.
17
18
19Copyright (C) 2011-2013 Virtual Security Research, LLC
20Author: Timothy D. Morgan
21
22 This program is free software: you can redistribute it and/or modify
23 it under the terms of the GNU Lesser General Public License, version 3,
24 as published by the Free Software Foundation.
25
26 This program is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with this program.  If not, see <http://www.gnu.org/licenses/>.
33'''
34
35
36import sys
37import argparse
38
39bopen = lambda f: open(f, 'rb')
40
41parser = argparse.ArgumentParser(
42    description='A script which accepts an HTTP request and prints out a'
43    ' generated Python script which sends a similar request.  This is useful'
44    ' when one wants to automate sending a large number of requests to a'
45    ' particular page or application.'
46    ' For more information, see: http://code.google.com/p/bletchley/wiki/Overview')
47parser.add_argument(
48    'requestfile', type=bopen, nargs='?', default=sys.stdin.buffer, 
49    help='A file containing an HTTP request.  Defaults to stdin if omitted.')
50parser.add_argument(
51    '--requests', action='store_true', help='Generate a script that uses the'
52    ' python-requests module rather than httplib/http.client (experimental).')
53
54args = parser.parse_args()
55input_req = args.requestfile.read()
56
57
58if b'\r\n\r\n' in input_req:
59    raw_headers,body = input_req.split(b'\r\n\r\n', 1)
60elif b'\n\n' in input_req:
61    raw_headers,body = input_req.split(b'\n\n', 1)
62else:
63    raw_headers = input_req
64    body = b''
65
66raw_headers = raw_headers.decode('utf-8')
67
68header_lines = raw_headers.split('\n')
69method,path,version = header_lines[0].split(' ', 2)
70
71host = 'TODO'
72port = 80
73use_ssl = False
74protocol = 'http'
75
76headers = []
77for l in header_lines[1:]:
78    if len(l) < 1: 
79        break
80    # Handle header line continuations
81    if l[0] in ' \t':
82        if len(headers) == 0:
83            continue
84        name,values = headers[-1]
85        values.append(l.lstrip('\t'))
86        headers[-1] = (name,values)
87        continue
88
89    name,value = l.split(':',1)
90    value = value.lstrip(' ').rstrip('\r')
91
92    # Skip headers that have to do with transfer encodings and connection longevity
93    if name.lower() not in ['accept','accept-language',
94                            'accept-encoding','accept-charset',
95                            'connection', 'keep-alive', 'host', 
96                            'content-length', 'proxy-connection']:
97        headers.append((name,[value]))
98
99    if name.lower() == 'host':
100        if ':' in value:
101            host,port = value.split(':',1)
102            port = int(port, 10)
103            if port == 443:
104                use_ssl = True
105                protocol = 'https'
106        else:
107            host = value
108
109
110formatted_body = '\n            '.join([repr(body[i:i+40]) for i in range(0,len(body),40)])
111if formatted_body == '':
112    formatted_body = "b''"
113
114
115if args.requests:
116    print('''#!/usr/bin/env python3
117
118import sys
119try:
120    import requests
121except:
122    sys.stderr.write('ERROR: Could not import requests module.  Ensure it is installed.\\n')
123    sys.stderr.write('       Under Debian, the package name is "python3-requests"\\n.')
124    sys.exit(1)
125
126# from bletchley import blobtools,buffertools
127# from bletchley import chosenct
128# from bletchley.CBC import *
129
130
131# TODO: ensure the host, port, and SSL settings are correct.
132host = %s
133port = %s
134protocol = %s
135''' % (repr(host),repr(port),repr(protocol)))
136
137    headers = dict(headers)
138    # XXX: We don't currently support exactly formatted header
139    #      continuations with python requests, but this should be
140    #      semantically equivalent.
141    for h in headers.keys():
142        headers[h] = ' '.join(headers[h])
143
144    print('''
145session = requests.Session()
146# TODO: use "data" to supply any parameters to be included in the request
147def sendRequest(session, data=None):
148    method = %s
149    path = %s
150    headers = %s
151    url = "%%s://%%s:%%d%%s" %% (protocol,host,port,path)
152    body = (%s)
153
154    return session.request(method, url, headers=headers, data=body, allow_redirects=False)
155    ''' % (repr(method), repr(path), repr(headers), formatted_body))
156
157    print('''   
158
159def fetch(data):
160    global session
161    ret_val = None
162
163    # TODO: customize code here to retrieve what you need from the response(s)
164    # For information on the response object's interface, see:
165    #   http://docs.python-requests.org/en/latest/api/#requests.Response
166    response = sendRequest(session, data)
167    print(response.headers)
168    print(repr(response.content))
169
170    return ret_val
171
172data = ''
173fetch(data)
174''')
175
176
177
178else:
179    print('''#!/usr/bin/env python3
180
181import sys
182import http.client as httpc
183# from bletchley import blobtools,buffertools
184# from bletchley.CBC import *
185
186
187# TODO: ensure the host, port, and SSL settings are correct.
188host = %s
189port = %s
190use_ssl = %s
191''' % (repr(host),repr(port),repr(use_ssl)))
192
193    print('''
194# TODO: use "data" to supply any parameters to be included in the request
195def sendRequest(connection, data=None):
196    method = %s
197    path = %s
198    body = (%s)
199   
200    connection.putrequest(method, path)
201    ''' % (repr(method), repr(path), formatted_body))
202
203    for name,values in headers:
204        if len(values) > 1:
205            continuations = ','.join([repr(v) for v in values[1:]])
206            print('''    connection.putheader(%s, %s, %s)''' % (repr(name),repr(values[0]),continuations))
207        else:
208            print('''    connection.putheader(%s, %s)''' % (repr(name),repr(values[0])))
209
210    print('''   
211    if len(body) > 0:
212        connection.putheader('Content-Length', len(body))
213    connection.endheaders()
214    connection.send(body)
215   
216    return connection.getresponse()
217
218
219def newConnection():
220    if use_ssl:
221        return httpc.HTTPSConnection(host, port)
222    else:
223        return httpc.HTTPConnection(host, port)
224
225
226def fetch(data, other=None):
227    ret_val = False
228    connection = newConnection()
229
230    # TODO: customize code here to retrieve what you need from the response(s)
231    # For information on the response object's interface, see:
232    #   http://docs.python.org/library/httplib.html#httpresponse-objects
233    response = sendRequest(connection, data)
234    print(response.getheaders())
235    print(repr(response.read()))
236
237    connection.close()
238    return ret_val
239
240data = ''
241fetch(data)
242''')
243
244print('''
245
246# Padding Oracle Attacks
247# ciphertext = blobtools.decode('{ encoding }', data)
248# poa = POA(fetch, {block size}, ciphertext, threads=1, log_file=sys.stderr)
249# print(poa.probe_padding()) # sanity check
250# print(poa.decrypt())
251
252# Byte-by-byte probing of ciphertext
253# ciphertext = blobtools.decode('{ encoding }', data)
254# result = chosenct.probe_bytes(fetch, ciphertext, [1,2,4,8,16,32,64,128], max_threads=5)
255# print(result.toHTML())
256''')
Note: See TracBrowser for help on using the repository browser.