Skip to content

Commit 51a9094

Browse files
committed
Python: Add sinks for http.server.BaseHTTPRequestHandler
1 parent a27431e commit 51a9094

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

python/ql/src/semmle/python/web/HttpResponse.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ import semmle.python.web.bottle.Response
77
import semmle.python.web.turbogears.Response
88
import semmle.python.web.falcon.Response
99
import semmle.python.web.cherrypy.Response
10+
import semmle.python.web.stdlib.Response
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Provides the sinks for HTTP servers defined with standard library (stdlib).
3+
*/
4+
5+
import python
6+
import semmle.python.security.TaintTracking
7+
import semmle.python.web.Http
8+
9+
private predicate is_wfile(AttrNode wfile) {
10+
exists(ClassValue cls |
11+
// Python 2
12+
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
13+
or
14+
// Python 3
15+
cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler")
16+
|
17+
wfile.getObject("wfile").pointsTo().getClass() = cls
18+
)
19+
}
20+
21+
/** Sink for `h.wfile.write` where `h` is an instance of BaseHTTPRequestHandler. */
22+
class StdLibWFileWriteSink extends HttpResponseTaintSink {
23+
StdLibWFileWriteSink() {
24+
exists(CallNode call |
25+
is_wfile(call.getFunction().(AttrNode).getObject("write")) and
26+
call.getArg(0) = this
27+
)
28+
}
29+
30+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
31+
}
32+
33+
/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHTTPRequestHandler. */
34+
class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
35+
StdLibWFileWritelinesSink() {
36+
exists(CallNode call |
37+
is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and
38+
call.getArg(0) = this
39+
)
40+
}
41+
42+
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind }
43+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.py:72:26:72:58 | Taint sink | externally controlled string |
2+
| test.py:73:31:73:54 | Taint sink | [externally controlled string] |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import python
2+
import semmle.python.web.HttpResponse
3+
import semmle.python.security.strings.Untrusted
4+
5+
from HttpResponseTaintSink sink, TaintKind kind
6+
where sink.sinks(kind)
7+
select sink, kind

python/ql/test/library-tests/web/stdlib/test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def do_GET(self):
6969
self.send_response(200)
7070
self.send_header("Content-type", "text/plain; charset=utf-8")
7171
self.end_headers()
72-
self.wfile.write(b"Hello BaseHTTPRequestHandler")
72+
self.wfile.write(b"Hello BaseHTTPRequestHandler\n")
73+
self.wfile.writelines([b"1\n", b"2\n", b"3\n"])
7374
print(self.headers)
7475

7576

0 commit comments

Comments
 (0)