-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathhttp_server.py
More file actions
124 lines (92 loc) · 3.91 KB
/
http_server.py
File metadata and controls
124 lines (92 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import sys
import os
import cgi
if sys.version_info[0] == 2:
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from CGIHTTPServer import CGIHTTPRequestHandler
if sys.version_info[0] == 3:
from http.server import HTTPServer, BaseHTTPRequestHandler, SimpleHTTPRequestHandler, CGIHTTPRequestHandler
def test_cgi_FieldStorage_taint():
# When a python script is invoked through CGI, the default values used by
# `cgi.FieldStorage` constructor makes it handle data from incoming request.
# You _can_ also manually set the input-data, as is shown below in `MyHandler`.
form = cgi.FieldStorage()
ensure_tainted(
form, # $ tainted
# `form['key']` will be a list, if multiple fields named "key" are provided
form['key'], # $ tainted
form['key'].value, # $ tainted
form['key'].file, # $ tainted
form['key'].filename, # $ tainted
form['key'][0], # $ tainted
form['key'][0].value, # $ tainted
form['key'][0].file, # $ tainted
form['key'][0].filename, # $ tainted
[field.value for field in form['key']], # $ MISSING: tainted
# `form.getvalue('key')` will be a list, if multiple fields named "key" are provided
form.getvalue('key'), # $ tainted
form.getvalue('key')[0], # $ tainted
form.getfirst('key'), # $ tainted
form.getlist('key'), # $ tainted
form.getlist('key')[0], # $ tainted
[field.value for field in form.getlist('key')], # $ MISSING: tainted
)
class MyHandler(BaseHTTPRequestHandler):
def taint_sources(self):
ensure_tainted(
self, # $ tainted
self.requestline, # $ tainted
self.path, # $ tainted
self.headers, # $ tainted
self.headers['Foo'], # $ tainted
self.headers.get('Foo'), # $ tainted
self.headers.get_all('Foo'), # $ tainted
self.headers.keys(), # $ tainted
self.headers.values(), # $ tainted
self.headers.items(), # $ tainted
self.headers.as_bytes(), # $ tainted
self.headers.as_string(), # $ tainted
str(self.headers), # $ tainted
bytes(self.headers), # $ tainted
self.rfile, # $ tainted
self.rfile.read(), # $ tainted
)
form = cgi.FieldStorage(
self.rfile,
self.headers,
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('content-type')},
)
ensure_tainted(form) # $ tainted
def do_GET(self): # $ requestHandler
# send_response will log a line to stderr
self.send_response(200)
self.send_header("Content-type", "text/plain; charset=utf-8")
self.end_headers()
self.wfile.write(b"Hello BaseHTTPRequestHandler\n")
self.wfile.writelines([b"1\n", b"2\n", b"3\n"])
print(self.headers)
def do_POST(self): # $ requestHandler
form = cgi.FieldStorage(
self.rfile,
self.headers,
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('content-type')},
)
if 'myfile' not in form:
self.send_response(422)
self.end_headers()
return
field = form['myfile']
field.file.seek(0, os.SEEK_END)
filesize = field.file.tell()
print("Uploaded {!r} with {} bytes".format(field.filename, filesize))
self.send_response(200)
self.end_headers()
if __name__ == "__main__":
server = HTTPServer(("127.0.0.1", 8080), MyHandler)
server.serve_forever()
# Headers works case insensitvely, so self.headers['foo'] == self.headers['FOO']
# curl localhost:8080 --header "Foo: 1" --header "foo: 2"
# To test file submission through forms, use
# curl -F myfile=@<yourfile> localhost:8080