Skip to content

Commit 2b992a6

Browse files
committed
Python: Add aiohttp taint tests
1 parent 3cbb909 commit 2b992a6

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
from aiohttp import web
2+
3+
async def test_taint(request: web.Request): # $ requestHandler
4+
5+
ensure_tainted(
6+
request, # $ MISSING: tainted
7+
8+
# yarl.URL instances
9+
# https://yarl.readthedocs.io/en/stable/api.html#yarl.URL
10+
# see below
11+
request.url, # $ MISSING: tainted
12+
request.rel_url, # $ MISSING: tainted
13+
14+
request.forwarded, # $ MISSING: tainted
15+
16+
request.host, # $ MISSING: tainted
17+
request.remote, # $ MISSING: tainted
18+
request.path, # $ MISSING: tainted
19+
request.path_qs, # $ MISSING: tainted
20+
request.raw_path, # $ MISSING: tainted
21+
22+
# multidict.MultiDictProxy[str]
23+
# see https://multidict.readthedocs.io/en/stable/multidict.html#multidict.MultiDictProxy
24+
# TODO: Should have a better way to capture that we in fact _do_ model this as a
25+
# an instance of the right class, and have the actual taint_test for that in a
26+
# different file!
27+
request.query, # $ MISSING: tainted
28+
request.query["key"], # $ MISSING: tainted
29+
request.query.get("key"), # $ MISSING: tainted
30+
request.query.getone("key"), # $ MISSING: tainted
31+
request.query.getall("key"), # $ MISSING: tainted
32+
request.query.keys(), # $ MISSING: tainted
33+
request.query.values(), # $ MISSING: tainted
34+
request.query.items(), # $ MISSING: tainted
35+
request.query.copy(), # $ MISSING: tainted
36+
list(request.query), # $ MISSING: tainted
37+
iter(request.query), # $ MISSING: tainted
38+
39+
# multidict.CIMultiDictProxy[str]
40+
# see https://multidict.readthedocs.io/en/stable/multidict.html#multidict.CIMultiDictProxy
41+
# TODO: Should have a better way to capture that we in fact _do_ model this as a
42+
# an instance of the right class, and have the actual taint_test for that in a
43+
# different file!
44+
request.headers, # $ MISSING: tainted
45+
request.query.getone("key"), # $ MISSING: tainted
46+
47+
# https://docs.python.org/3/library/asyncio-protocol.html#asyncio-transport
48+
# TODO
49+
request.transport, # $ MISSING: tainted
50+
request.transport.get_extra_info("key"), # $ MISSING: tainted
51+
52+
# dict-like (readonly)
53+
request.cookies, # $ MISSING: tainted
54+
request.cookies["key"], # $ MISSING: tainted
55+
request.cookies.get("key"), # $ MISSING: tainted
56+
request.cookies.keys(), # $ MISSING: tainted
57+
request.cookies.values(), # $ MISSING: tainted
58+
request.cookies.items(), # $ MISSING: tainted
59+
list(request.cookies), # $ MISSING: tainted
60+
iter(request.cookies), # $ MISSING: tainted
61+
62+
63+
# aiohttp.StreamReader
64+
# see https://docs.aiohttp.org/en/stable/streams.html#aiohttp.StreamReader
65+
# TODO
66+
request.content, # $ MISSING: tainted
67+
request._payload, # $ MISSING: tainted
68+
69+
request.body_exists, # $ MISSING: tainted
70+
request.has_body, # $ MISSING: tainted
71+
72+
request.content_type, # $ MISSING: tainted
73+
request.charset, # $ MISSING: tainted
74+
75+
request.http_range, # $ MISSING: tainted
76+
77+
# Optional[datetime]
78+
request.if_modified_since, # $ MISSING: tainted
79+
request.if_unmodified_since, # $ MISSING: tainted
80+
request.if_range, # $ MISSING: tainted
81+
82+
request.clone(scheme="https"), # $ MISSING: tainted
83+
84+
# TODO: like request.transport.get_extra_info
85+
request.get_extra_info("key"), # $ MISSING: tainted
86+
87+
# bytes
88+
await request.read(), # $ MISSING: tainted
89+
90+
# str
91+
await request.text(), # $ MISSING: tainted
92+
93+
# obj
94+
await request.json(), # $ MISSING: tainted
95+
96+
# aiohttp.multipart.MultipartReader
97+
await request.multipart(), # $ MISSING: tainted
98+
99+
# multidict.MultiDictProxy[str]
100+
await request.post(), # $ MISSING: tainted
101+
(await request.post()).getone("key"), # $ MISSING: tainted
102+
)
103+
104+
import yarl
105+
assert isinstance(request.url, yarl.URL)
106+
assert isinstance(request.rel_url, yarl.URL)
107+
108+
109+
# things that are technically controlled by sender of request,
110+
# but doesn't seem that likely for exploitation.
111+
ensure_not_tainted(
112+
request.method,
113+
request.version,
114+
request.scheme,
115+
request.secure,
116+
request.keep_alive,
117+
118+
request.content_length,
119+
)
120+
121+
ensure_not_tainted(
122+
request.loop,
123+
124+
request.match_info,
125+
request.app,
126+
request.config_dict,
127+
)
128+
129+
# TODO: Should have a better way to capture that we in fact _do_ model this as a
130+
# an instance of the right class, and have the actual taint_test for that in a
131+
# different file!
132+
import yarl
133+
134+
ensure_tainted(
135+
request.url.user, # $ MISSING: tainted
136+
request.url.raw_user, # $ MISSING: tainted
137+
138+
request.url.password, # $ MISSING: tainted
139+
request.url.raw_password, # $ MISSING: tainted
140+
141+
request.url.host, # $ MISSING: tainted
142+
request.url.raw_host, # $ MISSING: tainted
143+
144+
request.url.port, # $ MISSING: tainted
145+
request.url.explicit_port, # $ MISSING: tainted
146+
147+
request.url.authority, # $ MISSING: tainted
148+
request.url.raw_authority, # $ MISSING: tainted
149+
150+
request.url.path, # $ MISSING: tainted
151+
request.url.raw_path, # $ MISSING: tainted
152+
153+
request.url.path_qs, # $ MISSING: tainted
154+
request.url.raw_path_qs, # $ MISSING: tainted
155+
156+
request.url.query_string, # $ MISSING: tainted
157+
request.url.raw_query_string, # $ MISSING: tainted
158+
159+
request.url.fragment, # $ MISSING: tainted
160+
request.url.raw_fragment, # $ MISSING: tainted
161+
162+
request.url.parts, # $ MISSING: tainted
163+
request.url.raw_parts, # $ MISSING: tainted
164+
165+
request.url.name, # $ MISSING: tainted
166+
request.url.raw_name, # $ MISSING: tainted
167+
168+
# multidict.MultiDictProxy[str]
169+
request.url.query, # $ MISSING: tainted
170+
request.url.query.getone("key"), # $ MISSING: tainted
171+
172+
request.url.with_scheme("foo"), # $ MISSING: tainted
173+
request.url.with_user("foo"), # $ MISSING: tainted
174+
request.url.with_password("foo"), # $ MISSING: tainted
175+
request.url.with_host("foo"), # $ MISSING: tainted
176+
request.url.with_port("foo"), # $ MISSING: tainted
177+
request.url.with_path("foo"), # $ MISSING: tainted
178+
request.url.with_query({"foo": 42}), # $ MISSING: tainted
179+
request.url.with_query(foo=42), # $ MISSING: tainted
180+
request.url.update_query({"foo": 42}), # $ MISSING: tainted
181+
request.url.update_query(foo=42), # $ MISSING: tainted
182+
request.url.with_fragment("foo"), # $ MISSING: tainted
183+
request.url.with_name("foo"), # $ MISSING: tainted
184+
185+
request.url.join(yarl.URL("wat.html")), # $ MISSING: tainted
186+
187+
request.url.human_repr(), # $ MISSING: tainted
188+
)
189+
190+
191+
app = web.Application()
192+
app.router.add_get(r"/test_taint/{name}/{number:\d+}", test_taint) # $ routeSetup="/test_taint/{name}/{number:\d+}"
193+
194+
195+
if __name__ == "__main__":
196+
web.run_app(app)

0 commit comments

Comments
 (0)