|
1 | 1 | from aiohttp import web |
2 | 2 |
|
3 | | -async def test_heuristic_taint(request: web.Request): |
4 | | - ensure_tainted( |
5 | | - # see https://docs.aiohttp.org/en/stable/web_reference.html#request-and-base-request |
6 | | - request, # $ tainted |
7 | | - |
8 | | - # yarl.URL (see `yarl` framework tests) |
9 | | - request.url, # $ tainted |
10 | | - request.url.human_repr(), # $ tainted |
11 | | - request.rel_url, # $ tainted |
12 | | - request.rel_url.human_repr(), # $ tainted |
13 | | - |
14 | | - request.forwarded, # $ tainted |
15 | | - |
16 | | - request.host, # $ tainted |
17 | | - request.remote, # $ tainted |
18 | | - request.path, # $ tainted |
19 | | - request.path_qs, # $ tainted |
20 | | - request.raw_path, # $ tainted |
21 | | - |
22 | | - # dict-like for captured parts of the URL |
23 | | - request.match_info, # $ tainted |
24 | | - request.match_info["key"], # $ tainted |
25 | | - request.match_info.get("key"), # $ tainted |
26 | | - |
27 | | - # multidict.MultiDictProxy[str] (see `multidict` framework tests) |
28 | | - request.query, # $ tainted |
29 | | - request.query.getone("key"), # $ tainted |
30 | | - |
31 | | - # multidict.CIMultiDictProxy[str] (see `multidict` framework tests) |
32 | | - request.headers, # $ tainted |
33 | | - request.headers.getone("key"), # $ tainted |
34 | | - |
35 | | - |
36 | | - |
37 | | - # dict-like (readonly) |
38 | | - request.cookies, # $ tainted |
39 | | - request.cookies["key"], # $ tainted |
40 | | - request.cookies.get("key"), # $ tainted |
41 | | - request.cookies.keys(), # $ tainted |
42 | | - request.cookies.values(), # $ tainted |
43 | | - request.cookies.items(), # $ tainted |
44 | | - list(request.cookies), # $ tainted |
45 | | - iter(request.cookies), # $ tainted |
46 | | - |
47 | | - |
48 | | - # aiohttp.StreamReader |
49 | | - # see https://docs.aiohttp.org/en/stable/streams.html#aiohttp.StreamReader |
50 | | - request.content, # $ tainted |
51 | | - await request.content.read(), # $ tainted |
52 | | - await request.content.readany(), # $ tainted |
53 | | - await request.content.readexactly(42), # $ tainted |
54 | | - await request.content.readline(), # $ tainted |
55 | | - await request.content.readchunk(), # $ tainted |
56 | | - (await request.content.readchunk())[0], # $ tainted |
57 | | - [line async for line in request.content], # $ tainted |
58 | | - [data async for data in request.content.iter_chunked(1024)], # $ tainted |
59 | | - [data async for data in request.content.iter_any()], # $ tainted |
60 | | - [data async for data, _ in request.content.iter_chunks()], # $ tainted |
61 | | - request.content.read_nowait(), # $ tainted |
62 | | - |
63 | | - # aiohttp.StreamReader |
64 | | - request._payload, # $ tainted |
65 | | - await request._payload.readany(), # $ tainted |
66 | | - |
67 | | - request.content_type, # $ tainted |
68 | | - request.charset, # $ tainted |
69 | | - |
70 | | - request.http_range, # $ tainted |
71 | | - |
72 | | - # Optional[datetime] |
73 | | - request.if_modified_since, # $ tainted |
74 | | - request.if_unmodified_since, # $ tainted |
75 | | - request.if_range, # $ tainted |
76 | | - |
77 | | - request.clone(scheme="https"), # $ tainted |
78 | | - |
79 | | - # asyncio.Transport |
80 | | - # https://docs.python.org/3/library/asyncio-protocol.html#asyncio-transport |
81 | | - # example given in https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest.transport |
82 | | - # uses `peername` to get IP address of client |
83 | | - request.transport, # $ tainted |
84 | | - request.transport.get_extra_info("key"), # $ MISSING: tainted |
85 | | - |
86 | | - # Like request.transport.get_extra_info |
87 | | - request.get_extra_info("key"), # $ tainted |
88 | | - |
89 | | - # Like request.transport.get_extra_info |
90 | | - request.protocol.transport.get_extra_info("key"), # $ MISSING: tainted |
91 | | - |
92 | | - # bytes |
93 | | - await request.read(), # $ tainted |
94 | | - |
95 | | - # str |
96 | | - await request.text(), # $ tainted |
97 | | - |
98 | | - # obj |
99 | | - await request.json(), # $ tainted |
100 | | - |
101 | | - # aiohttp.multipart.MultipartReader |
102 | | - await request.multipart(), # $ tainted |
103 | | - |
104 | | - # multidict.MultiDictProxy[str] (see `multidict` framework tests) |
105 | | - await request.post(), # $ tainted |
106 | | - (await request.post()).getone("key"), # $ tainted |
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 | | - request.body_exists, |
120 | | - request.has_body, |
121 | | - request.can_read_body, |
122 | | - ) |
123 | | - |
124 | | - ensure_not_tainted( |
125 | | - request.loop, |
126 | | - |
127 | | - request.app, |
128 | | - request.config_dict, |
129 | | - ) |
130 | | - |
131 | | - |
132 | 3 | async def test_taint(request: web.Request): # $ requestHandler |
133 | 4 |
|
134 | 5 | ensure_tainted( |
@@ -271,6 +142,17 @@ def get(self): # $ requestHandler |
271 | 142 | self.request.url # $ tainted |
272 | 143 | ) |
273 | 144 |
|
| 145 | +# not a request handler, and not called, btu since we have type-annotation, should be a |
| 146 | +# remote-flow-source. |
| 147 | +async def test_heuristic_taint(request: web.Request): |
| 148 | + # picking out just a few of the tests from `test_taint` above, to show that we have |
| 149 | + # the same taint-steps :) |
| 150 | + ensure_tainted( |
| 151 | + request, # $ tainted |
| 152 | + request.url, # $ tainted |
| 153 | + await request.content.read(), # $ tainted |
| 154 | + ) |
| 155 | + |
274 | 156 |
|
275 | 157 | app = web.Application() |
276 | 158 | app.router.add_get(r"/test_taint/{name}/{number:\d+}", test_taint) # $ routeSetup="/test_taint/{name}/{number:\d+}" |
|
0 commit comments