@@ -52,20 +52,27 @@ module SqlInjection {
5252
5353  private  string  inputfile ( )  {  result  =  [ "inputfile" ,  "i" ]  } 
5454
55+   bindingset [ call] 
56+   pragma [ inline_late] 
57+   private  predicate  sqlCmdSinkCommon ( DataFlow:: CallNode  call ,  DataFlow:: Node  s )  { 
58+     s  =  call .getNamedArgument ( query ( ) ) 
59+     or 
60+     // If the input is not provided as a query parameter or an input file 
61+     // parameter then it's the first argument. 
62+     not  call .hasNamedArgument ( query ( ) )  and 
63+     not  call .hasNamedArgument ( inputfile ( ) )  and 
64+     s  =  call .getArgument ( 0 ) 
65+     or 
66+     // TODO: Here we really should pick a splat argument, but we don't yet extract whether an 
67+     // argument is a splat argument. 
68+     s  =  unique(  |  |  call .getAnArgument ( ) ) 
69+   } 
70+ 
5571  class  InvokeSqlCmdSink  extends  Sink  { 
5672    InvokeSqlCmdSink ( )  { 
57-       exists ( DataFlow:: CallNode  call  |  call .matchesName ( "Invoke-Sqlcmd" )  | 
58-         this  =  call .getNamedArgument ( query ( ) ) 
59-         or 
60-         // If the input is not provided as a query parameter or an input file 
61-         // parameter then it's the first argument. 
62-         not  call .hasNamedArgument ( query ( ) )  and 
63-         not  call .hasNamedArgument ( inputfile ( ) )  and 
64-         this  =  call .getArgument ( 0 ) 
65-         or 
66-         // TODO: Here we really should pick a splat argument, but we don't yet extract whether an 
67-         // argument is a splat argument. 
68-         this  =  unique(  |  |  call .getAnArgument ( ) ) 
73+       exists ( DataFlow:: CallNode  call  | 
74+         call .matchesName ( "Invoke-Sqlcmd" )  and 
75+         sqlCmdSinkCommon ( call ,  this ) 
6976      ) 
7077    } 
7178
@@ -94,11 +101,17 @@ module SqlInjection {
94101    override  string  getSinkType ( )  {  result  =  "write to "  +  memberName  } 
95102  } 
96103
104+   /** 
105+    * A call of the form `&sqlcmd`. 
106+    * 
107+    * We don't know if this is actually a call to an SQL execution procedure, but it is 
108+    * very common to define a `sqlcmd` variable and point it to an SQL execution program. 
109+    */ 
97110  class  SqlCmdSink  extends  Sink  { 
98111    SqlCmdSink ( )  { 
99112      exists ( DataFlow:: CallOperatorNode  call  | 
100113        call .getCommand ( ) .asExpr ( ) .getValue ( ) .stringMatches ( "sqlcmd" )  and 
101-         call . getAnArgument ( )   =   this 
114+         sqlCmdSinkCommon ( call ,   this ) 
102115      ) 
103116    } 
104117
0 commit comments