forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUnsafeCreateProcessCall.ql
More file actions
131 lines (112 loc) · 4.39 KB
/
UnsafeCreateProcessCall.ql
File metadata and controls
131 lines (112 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* @name NULL application name with an unquoted path in call to CreateProcess
* @description Calling a function of the CreateProcess* family of functions, where the path contains spaces, introduces a security vulnerability.
* @id cpp/unsafe-create-process-call
* @kind problem
* @problem.severity error
* @security-severity 7.8
* @precision medium
* @msrc.severity important
* @tags security
* external/cwe/cwe-428
*/
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
predicate isCreateProcessFunction(FunctionCall call, int applicationNameIndex, int commandLineIndex) {
call.getTarget().hasGlobalName("CreateProcessA") and
applicationNameIndex = 0 and
commandLineIndex = 1
or
call.getTarget().hasGlobalName("CreateProcessW") and
applicationNameIndex = 0 and
commandLineIndex = 1
or
call.getTarget().hasGlobalName("CreateProcessWithTokenW") and
applicationNameIndex = 2 and
commandLineIndex = 3
or
call.getTarget().hasGlobalName("CreateProcessWithLogonW") and
applicationNameIndex = 4 and
commandLineIndex = 5
or
call.getTarget().hasGlobalName("CreateProcessAsUserA") and
applicationNameIndex = 1 and
commandLineIndex = 2
or
call.getTarget().hasGlobalName("CreateProcessAsUserW") and
applicationNameIndex = 1 and
commandLineIndex = 2
}
/**
* A function call to CreateProcess (either wide-char or single byte string versions)
*/
class CreateProcessFunctionCall extends FunctionCall {
CreateProcessFunctionCall() { isCreateProcessFunction(this, _, _) }
int getApplicationNameArgumentId() { isCreateProcessFunction(this, result, _) }
int getCommandLineArgumentId() { isCreateProcessFunction(this, _, result) }
}
/**
* Dataflow that detects a call to CreateProcess with a NULL value for lpApplicationName argument
*/
module NullAppNameCreateProcessFunctionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue }
predicate isSink(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call, Expr val | val = sink.asExpr() |
val = call.getArgument(call.getApplicationNameArgumentId())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call | result = call.getLocation() |
sink.asExpr() = call.getArgument(call.getApplicationNameArgumentId())
)
}
}
module NullAppNameCreateProcessFunction = DataFlow::Global<NullAppNameCreateProcessFunctionConfig>;
/**
* Dataflow that detects a call to CreateProcess with an unquoted commandLine argument
*/
module QuotedCommandInCreateProcessFunctionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(string s |
s = source.asExpr().getValue().toString() and
not isQuotedOrNoSpaceApplicationNameOnCmd(s)
)
}
predicate isSink(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call, Expr val | val = sink.asExpr() |
val = call.getArgument(call.getCommandLineArgumentId())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
Location getASelectedSinkLocation(DataFlow::Node sink) {
exists(CreateProcessFunctionCall call | result = call.getLocation() |
sink.asExpr() = call.getArgument(call.getCommandLineArgumentId())
)
}
}
module QuotedCommandInCreateProcessFunction =
DataFlow::Global<QuotedCommandInCreateProcessFunctionConfig>;
bindingset[s]
predicate isQuotedOrNoSpaceApplicationNameOnCmd(string s) {
s.regexpMatch("\"([^\"])*\"[\\s\\S]*") // The first element (path) is quoted
or
s.regexpMatch("[^\\s]+") // There are no spaces in the string
}
from CreateProcessFunctionCall call, string msg1, string msg2
where
exists(Expr appName |
appName = call.getArgument(call.getApplicationNameArgumentId()) and
NullAppNameCreateProcessFunction::flowToExpr(appName) and
msg1 = call.toString() + " with lpApplicationName == NULL (" + appName + ")"
) and
exists(Expr cmd |
cmd = call.getArgument(call.getCommandLineArgumentId()) and
QuotedCommandInCreateProcessFunction::flowToExpr(cmd) and
msg2 =
" and with an unquoted lpCommandLine (" + cmd +
") introduces a security vulnerability if the path contains spaces."
)
select call, msg1 + " " + msg2