Skip to content

Commit 6158dd6

Browse files
committed
Finish Sinks
1 parent bd894ae commit 6158dd6

File tree

1 file changed

+84
-15
lines changed

1 file changed

+84
-15
lines changed

python/ql/src/experimental/Security/CWE-113/HeaderInjection.ql

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class WerkzeugHeaderCall extends DataFlow::CallCfgNode {
3131
DataFlow::Node getHeaderInputNode() { result = this.getArg(1) }
3232
}
3333

34-
class FlaskHeaderCall extends DataFlow::CallCfgNode {
34+
class FlaskHeaderCall extends DataFlow::Node {
3535
DataFlow::Node headerInputNode;
3636

3737
FlaskHeaderCall() {
@@ -44,39 +44,108 @@ class FlaskHeaderCall extends DataFlow::CallCfgNode {
4444
responseMethod.getObject().getALocalSource() = headerInstance and
4545
sinkDeclaration.getATarget() = responseMethod.asExpr().getParentNode() and
4646
headerInputNode.asExpr() = sinkDeclaration.getValue() and
47-
this.getFunction() = responseMethod
47+
this.asExpr() = sinkDeclaration.getATarget()
4848
)
4949
}
5050

5151
DataFlow::Node getHeaderInputNode() { result = headerInputNode }
5252
}
5353

54-
class FlaskMakeResponse extends DataFlow::Node {
55-
FlaskMakeResponse() {
54+
class FlaskMakeResponseCall extends DataFlow::Node {
55+
DataFlow::Node headerInputNode;
56+
57+
FlaskMakeResponseCall() {
5658
exists(
5759
DataFlow::CallCfgNode headerInstance, DataFlow::AttrRead responseMethod,
5860
AssignStmt sinkDeclaration
5961
|
6062
headerInstance = API::moduleImport("flask").getMember("make_response").getACall() and
6163
responseMethod.getAttributeName() = "headers" and
6264
responseMethod.getObject().getALocalSource() = headerInstance and
63-
(
64-
sinkDeclaration.getATarget() = responseMethod.asExpr().getParentNode() and
65-
this.asExpr() = sinkDeclaration.getValue()
66-
)
67-
//or
68-
//extendMethod.getAttributeName() = "extend" and
69-
//extendMethod.getObject().getALocalSource() = responseMethod and
70-
//this = extendMethod.(DataFlow::CallCfgNode).getArg(0)
65+
sinkDeclaration.getATarget() = responseMethod.asExpr().getParentNode() and
66+
this.asExpr() = sinkDeclaration.getATarget() and
67+
headerInputNode.asExpr() = sinkDeclaration.getValue()
68+
)
69+
}
70+
71+
DataFlow::Node getHeaderInputNode() { result = headerInputNode }
72+
}
73+
74+
class FlaskMakeResponseExtendCall extends DataFlow::CallCfgNode {
75+
DataFlow::Node headerInputNode;
76+
77+
FlaskMakeResponseExtendCall() {
78+
exists(
79+
DataFlow::CallCfgNode headerInstance, DataFlow::AttrRead responseMethod,
80+
DataFlow::AttrRead extendMethod
81+
|
82+
headerInstance = API::moduleImport("flask").getMember("make_response").getACall() and
83+
responseMethod.getAttributeName() = "headers" and
84+
responseMethod.getObject().getALocalSource() = headerInstance and
85+
extendMethod.getAttributeName() = "extend" and
86+
extendMethod.getObject().getALocalSource() = responseMethod and
87+
this.getFunction() = extendMethod and
88+
headerInputNode = this.getArg(0)
7189
)
7290
}
91+
92+
DataFlow::Node getHeaderInputNode() { result = headerInputNode }
93+
}
94+
95+
class FlaskResponseArg extends DataFlow::CallCfgNode {
96+
DataFlow::Node headerInputNode;
97+
98+
FlaskResponseArg() {
99+
this = API::moduleImport("flask").getMember("Response").getACall() and
100+
headerInputNode = this.getArgByName("headers")
101+
}
102+
103+
DataFlow::Node getHeaderInputNode() { result = headerInputNode }
104+
}
105+
106+
class DjangoResponseSetItemCall extends DataFlow::CallCfgNode {
107+
DjangoResponseSetItemCall() {
108+
exists(DataFlow::AttrRead setItemMethod |
109+
this.getFunction() = setItemMethod and
110+
setItemMethod.getObject().getALocalSource() =
111+
API::moduleImport("django").getMember("http").getMember("HttpResponse").getACall() and
112+
setItemMethod.getAttributeName() = "__setitem__"
113+
)
114+
}
115+
116+
DataFlow::Node getHeaderInputNode() { result = this.getArg(1) }
117+
}
118+
119+
class DjangoResponseAssignCall extends DataFlow::Node {
120+
DataFlow::Node headerInputNode;
121+
122+
DjangoResponseAssignCall() {
123+
exists(
124+
DataFlow::CallCfgNode headerInstance, Subscript responseMethod, DataFlow::Node responseToNode,
125+
AssignStmt sinkDeclaration
126+
|
127+
headerInstance =
128+
API::moduleImport("django").getMember("http").getMember("HttpResponse").getACall() and
129+
responseMethod.getValue() = responseToNode.asExpr() and
130+
responseToNode.getALocalSource().asExpr() = headerInstance.asExpr() and
131+
sinkDeclaration.getATarget() = responseMethod and
132+
this.asExpr() = sinkDeclaration.getATarget() and
133+
headerInputNode.asExpr() = sinkDeclaration.getValue()
134+
)
135+
}
136+
137+
DataFlow::Node getHeaderInputNode() { result = headerInputNode }
73138
}
74139

75140
class HeaderInjectionSink extends DataFlow::Node {
76141
HeaderInjectionSink() {
77-
this instanceof WerkzeugHeaderCall or
78-
this instanceof FlaskHeaderCall or
79-
this instanceof FlaskMakeResponse
142+
this = any(WerkzeugHeaderCall a).getHeaderInputNode() or
143+
this = any(FlaskHeaderCall a).getHeaderInputNode() or
144+
this = any(FlaskMakeResponseCall a).getHeaderInputNode() or
145+
this = any(FlaskMakeResponseExtendCall a).getHeaderInputNode() or
146+
this = any(FlaskResponseArg a).getHeaderInputNode() or
147+
this = any(DjangoResponseSetItemCall a).getHeaderInputNode() or
148+
this = any(DjangoResponseAssignCall a).getHeaderInputNode()
80149
}
81150
}
82151

0 commit comments

Comments
 (0)