Skip to content

Commit 32aba1c

Browse files
committed
Port over UI5LogsToHttp
NOTE: The end-to-end results of the queries are okay (the `#select` portion is unchanged), but there are difference in `nodes` and `edges` that probably needs attention.
1 parent 4c5b7f6 commit 32aba1c

File tree

2 files changed

+64
-57
lines changed

2 files changed

+64
-57
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import javascript
2+
import advanced_security.javascript.frameworks.ui5.dataflow.DataFlow
3+
import advanced_security.javascript.frameworks.ui5.UI5LogInjectionQuery
4+
5+
class ClientRequestInjectionVector extends DataFlow::Node {
6+
ClientRequestInjectionVector() {
7+
exists(ClientRequest req |
8+
this = req.getUrl() or
9+
this = req.getADataNode()
10+
)
11+
}
12+
}
13+
14+
class UI5LogEntryFlowState extends string {
15+
UI5LogEntryFlowState() { this = ["not-logged-not-accessed", "logged-and-accessed"] }
16+
}
17+
18+
module UI5LogEntryToHttp implements DataFlow::StateConfigSig {
19+
class FlowState = UI5LogEntryFlowState;
20+
21+
predicate isSource(DataFlow::Node node, FlowState state) {
22+
node instanceof RemoteFlowSource and
23+
state = "not-logged-not-accessed"
24+
}
25+
26+
predicate isAdditionalFlowStep(
27+
DataFlow::Node start, FlowState preState, DataFlow::Node end, FlowState postState
28+
) {
29+
UI5LogInjection::isAdditionalFlowStep(start, end) and
30+
preState = postState
31+
or
32+
/*
33+
* NOTE: This disjunct is a labeled version of LogArgumentToListener in
34+
* FlowSteps.qll, a DataFlow::SharedFlowStep. As the class is considered
35+
* legacy on version 2.4.0, we leave the two here (labeled) and there
36+
* (unlabeled). This is something we should also tidy up when we migrate
37+
* to the newer APIs.
38+
*/
39+
40+
inSameWebApp(start.getFile(), end.getFile()) and
41+
start =
42+
ModelOutput::getATypeNode("SapLogger")
43+
.getMember(["debug", "error", "fatal", "info", "trace", "warning"])
44+
.getACall()
45+
.getAnArgument() and
46+
end = ModelOutput::getATypeNode("SapLogEntries").asSource() and
47+
preState = "not-logged-not-accessed" and
48+
postState = "logged-and-accessed"
49+
}
50+
51+
predicate isSink(DataFlow::Node node, FlowState state) {
52+
node instanceof ClientRequestInjectionVector and
53+
state = "logged-and-accessed"
54+
}
55+
}

javascript/frameworks/ui5/src/UI5LogInjection/UI5LogsToHttp.ql

Lines changed: 9 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,69 +12,21 @@
1212
*/
1313

1414
import javascript
15+
import advanced_security.javascript.frameworks.ui5.UI5LogsToHttpQuery
1516
import advanced_security.javascript.frameworks.ui5.dataflow.DataFlow
16-
import semmle.javascript.frameworks.data.internal.ApiGraphModels
17-
import advanced_security.javascript.frameworks.ui5.UI5LogInjectionQuery
18-
import advanced_security.javascript.frameworks.ui5.dataflow.DataFlow::UI5PathGraph
1917

20-
class ClientRequestInjectionVector extends DataFlow::Node {
21-
ClientRequestInjectionVector() {
22-
exists(ClientRequest req |
23-
this = req.getUrl() or
24-
this = req.getADataNode()
25-
)
26-
}
27-
}
18+
module UI5LogsToHttpFlow = TaintTracking::GlobalWithState<UI5LogEntryToHttp>;
2819

29-
class UI5LogEntryFlowState extends DataFlow::FlowLabel {
30-
UI5LogEntryFlowState() { this = ["not-logged-not-accessed", "logged-and-accessed"] }
31-
}
20+
module UI5LogsToHttpUI5PathGraph =
21+
UI5PathGraph<UI5LogsToHttpFlow::PathNode, UI5LogsToHttpFlow::PathGraph>;
3222

33-
class UI5LogEntryToHttp extends TaintTracking::Configuration {
34-
UI5LogEntryToHttp() { this = "UI5 Log Entry included in an outbound HTTP request" }
23+
import UI5LogsToHttpUI5PathGraph
3524

36-
override predicate isSource(DataFlow::Node node, DataFlow::FlowLabel state) {
37-
node instanceof RemoteFlowSource and
38-
state = "not-logged-not-accessed"
39-
}
40-
41-
override predicate isAdditionalFlowStep(
42-
DataFlow::Node start, DataFlow::Node end, DataFlow::FlowLabel preState,
43-
DataFlow::FlowLabel postState
44-
) {
45-
exists(UI5LogInjectionConfiguration cfg |
46-
cfg.isAdditionalFlowStep(start, end) and
47-
preState = postState
48-
)
49-
or
50-
/*
51-
* NOTE: This disjunct is a labeled version of LogArgumentToListener in
52-
* FlowSteps.qll, a DataFlow::SharedFlowStep. As the class is considered
53-
* legacy on version 2.4.0, we leave the two here (labeled) and there
54-
* (unlabeled). This is something we should also tidy up when we migrate
55-
* to the newer APIs.
56-
*/
57-
58-
inSameWebApp(start.getFile(), end.getFile()) and
59-
start =
60-
ModelOutput::getATypeNode("SapLogger")
61-
.getMember(["debug", "error", "fatal", "info", "trace", "warning"])
62-
.getACall()
63-
.getAnArgument() and
64-
end = ModelOutput::getATypeNode("SapLogEntries").asSource() and
65-
preState = "not-logged-not-accessed" and
66-
postState = "logged-and-accessed"
67-
}
68-
69-
override predicate isSink(DataFlow::Node node, DataFlow::FlowLabel state) {
70-
node instanceof ClientRequestInjectionVector and
71-
state = "logged-and-accessed"
72-
}
73-
}
74-
75-
from UI5LogEntryToHttp cfg, UI5PathNode source, UI5PathNode sink, UI5PathNode primarySource
25+
from
26+
UI5LogsToHttpUI5PathGraph::UI5PathNode source, UI5LogsToHttpUI5PathGraph::UI5PathNode sink,
27+
UI5LogsToHttpUI5PathGraph::UI5PathNode primarySource
7628
where
77-
cfg.hasFlowPath(source.getPathNode(), sink.getPathNode()) and
29+
UI5LogsToHttpFlow::flowPath(source.getPathNode(), sink.getPathNode()) and
7830
primarySource = source.getAPrimarySource()
7931
select sink, primarySource, sink, "Outbound network request depends on $@ log data.", primarySource,
8032
"user-provided"

0 commit comments

Comments
 (0)