1414import javascript
1515import advanced_security.javascript.frameworks.ui5.dataflow.DataFlow
1616import semmle.javascript.frameworks.data.internal.ApiGraphModels
17- import advanced_security.javascript.frameworks.ui5.dataflow.DataFlow:: UI5PathGraph
1817import advanced_security.javascript.frameworks.ui5.UI5LogInjectionQuery
19- import semmle.javascript.security.dataflow.LogInjectionQuery as LogInjection
2018
2119class ClientRequestInjectionVector extends DataFlow:: Node {
2220 ClientRequestInjectionVector ( ) {
@@ -43,12 +41,6 @@ class UI5Logger extends RequiredObject {
4341 }
4442}
4543
46- private predicate test ( MethodCallNode call , Node receiver , SourceNode receiverSource ) {
47- call .getMethodName ( ) = "getLogEntries" and
48- receiver = call .getReceiver ( ) and
49- receiverSource = receiver .getALocalSource ( )
50- }
51-
5244class SapLogger extends DataFlow:: Node {
5345 SapLogger ( ) { this = ModelOutput:: getATypeNode ( "SapLogger" ) .getInducingNode ( ) }
5446}
@@ -70,67 +62,74 @@ class LogListener extends DataFlow::Node {
7062 LogListener ( ) { this = isLogListener ( ) }
7163
7264 FunctionNode getOnLogEntryMethod ( ) {
73- exists ( DataFlow:: PropWrite propWrite | propWrite .getPropertyName ( ) = "onLogEntry" |
74- result = propWrite .getRhs ( )
65+ exists ( DataFlow:: PropWrite onLogEntryProp | onLogEntryProp .getPropertyName ( ) = "onLogEntry" |
66+ result = onLogEntryProp .getRhs ( )
7567 )
7668 }
7769}
7870
71+ class UI5LogEntryFlowState extends DataFlow:: FlowLabel {
72+ UI5LogEntryFlowState ( ) { this = [ "not-logged-not-accessed" , "logged-and-accessed" ] }
73+ }
74+
7975class UI5LogEntryToHttp extends TaintTracking:: Configuration {
80- UI5LogEntryToHttp ( ) { this = "UI5 log entries being passed to outbound HTTP requests " }
76+ UI5LogEntryToHttp ( ) { this = "UI5 Log Entry included in an outbound HTTP request " }
8177
82- override predicate isSource ( DataFlow:: Node node , DataFlow:: FlowLabel label ) {
78+ override predicate isSource ( DataFlow:: Node node , DataFlow:: FlowLabel state ) {
8379 node instanceof RemoteFlowSource and
84- label = "not-logged"
80+ state = "not-logged-not-accessed "
8581 }
8682
87- /*
88- * !!!!!!!!!! NOTE !!!!!!!!!!
89- *
90- * The `DataFlow::FlowLabel` class became deprecated together with
91- * `DataFlow::Configuration` and `TaintTracking::Configuration`.
92- *
93- * There is now no standard library taking advantage of `DataFlow::FlowLabel`
94- * specifically, so we shouldn't expect our pre-labels and post-labels to
95- * be propagated along with steps in `LogInjection::Configuration.isAdditionalFlowStep`!
96- */
97-
9883 override predicate isAdditionalFlowStep (
99- DataFlow:: Node start , DataFlow:: Node end , DataFlow:: FlowLabel preLabel ,
100- DataFlow:: FlowLabel postLabel
84+ DataFlow:: Node start , DataFlow:: Node end , DataFlow:: FlowLabel preState ,
85+ DataFlow:: FlowLabel postState
10186 ) {
102- /* 1. From a remote flow source to a logging function. */
103- exists ( UI5LogInjectionConfiguration config |
104- config .isAdditionalFlowStep ( start , end ) and
105- preLabel = "not-logged" and
106- postLabel = "logged"
107- )
108- /*
109- * 2. From a logging function to a log entry: a shared flow step
110- * `LogArgumentToListener` in FlowSteps.qll, implemented as a
111- * `DataFlow::SharedFlowStep`.
112- */
113-
114- /*
115- * 3. From a log entry to an HTTP sending function.
116- */
117-
118- }
87+ inSameWebApp ( start .getFile ( ) , end .getFile ( ) ) and
88+ start =
89+ ModelOutput:: getATypeNode ( "SapLogger" )
90+ .getMember ( [ "debug" , "error" , "fatal" , "info" , "trace" , "warning" ] )
91+ .getACall ( )
92+ .getAnArgument ( ) and
93+ end = ModelOutput:: getATypeNode ( "SapLogEntries" ) .asSource ( ) and
94+ preState = "not-logged-not-accessed" and
95+ postState = "logged-and-accessed"
96+ }
11997
120- override predicate isSink ( DataFlow:: Node node , DataFlow:: FlowLabel label ) {
98+ override predicate isSink ( DataFlow:: Node node , DataFlow:: FlowLabel state ) {
12199 node instanceof ClientRequestInjectionVector and
122- label = "accessed"
100+ state = "logged-and- accessed"
123101 }
124102}
125103
126- from UI5LogEntryToHttp cfg , UI5PathNode source , UI5PathNode sink , UI5PathNode primarySource
127- where
128- cfg .hasFlowPath ( source .getPathNode ( ) , sink .getPathNode ( ) ) and
129- primarySource = source .getAPrimarySource ( )
130- select sink , primarySource , sink , "Outbound network request depends on $@ log data." , primarySource ,
104+ /**
105+ * Config without states for sanity check
106+ */
107+ module UI5LogEntryToHttp implements DataFlow:: ConfigSig {
108+ predicate isSource ( DataFlow:: Node node ) { node instanceof RemoteFlowSource }
109+
110+ predicate isAdditionalFlowStep ( DataFlow:: Node start , DataFlow:: Node end ) {
111+ inSameWebApp ( start .getFile ( ) , end .getFile ( ) ) and
112+ start =
113+ ModelOutput:: getATypeNode ( "SapLogger" )
114+ .getMember ( [ "debug" , "error" , "fatal" , "info" , "trace" , "warning" ] )
115+ .getACall ( )
116+ .getAnArgument ( ) and
117+ end = ModelOutput:: getATypeNode ( "SapLogEntries" ) .asSource ( )
118+ }
119+
120+ predicate isSink ( DataFlow:: Node node ) { node instanceof ClientRequestInjectionVector }
121+ }
122+
123+ import DataFlow:: PathGraph
124+
125+ // import UI5LogEntryToHttpFlow::PathGraph
126+ module UI5LogEntryToHttpFlow = TaintTracking:: Global< UI5LogEntryToHttp > ;
127+
128+ from UI5LogEntryToHttp cfg , DataFlow:: PathNode source , DataFlow:: PathNode sink
129+ where cfg .hasFlowPath ( source , sink )
130+ select sink , source , sink , "Outbound network request depends on $@ log data." , source ,
131131 "user-provided"
132- // import DataFlow::PathGraph
133- // from UI5LogEntryToHttp cfg, DataFlow::PathNode source, DataFlow::PathNode sink
134- // where cfg.hasFlowPath(source, sink)
132+ // from UI5LogEntryToHttpFlow::PathNode source, UI5LogEntryToHttpFlow::PathNode sink
133+ // where UI5LogEntryToHttpFlow::flowPath(source, sink)
135134// select sink, source, sink, "Outbound network request depends on $@ log data.", source,
136135// "user-provided"
0 commit comments