16 # |
16 # |
17 |
17 |
18 import ast |
18 import ast |
19 import re |
19 import re |
20 import sys |
20 import sys |
|
21 |
|
22 from Security.SecurityDefaults import SecurityDefaults |
21 |
23 |
22 # This regex starts with a windows drive letter (eg C:) |
24 # This regex starts with a windows drive letter (eg C:) |
23 # or one of our path delimeter characters (/, \, .) |
25 # or one of our path delimeter characters (/, \, .) |
24 fullPathMatchRe = re.compile(r'^(?:[A-Za-z](?=\:)|[\\\/\.])') |
26 fullPathMatchRe = re.compile(r'^(?:[A-Za-z](?=\:)|[\\\/\.])') |
25 |
27 |
40 (checkStartProcessWithShell, ("S605",)), |
42 (checkStartProcessWithShell, ("S605",)), |
41 (checkStartProcessWithNoShell, ("S606",)), |
43 (checkStartProcessWithNoShell, ("S606",)), |
42 (checkStartProcessWithPartialPath, ("S607",)), |
44 (checkStartProcessWithPartialPath, ("S607",)), |
43 ], |
45 ], |
44 } |
46 } |
45 |
|
46 |
|
47 def _defaultValues(key): |
|
48 """ |
|
49 Function to get the default values for a given check key. |
|
50 |
|
51 @param key key to get default values for |
|
52 @type str |
|
53 @return list with default values |
|
54 @rtype list of str |
|
55 """ |
|
56 if key == "shell_injection_subprocess": |
|
57 return [ |
|
58 'subprocess.Popen', |
|
59 'subprocess.call', |
|
60 'subprocess.check_call', |
|
61 'subprocess.check_output', |
|
62 'subprocess.run' |
|
63 ] |
|
64 elif key == "shell_injection_shell": |
|
65 return [ |
|
66 'os.system', |
|
67 'os.popen', |
|
68 'os.popen2', |
|
69 'os.popen3', |
|
70 'os.popen4', |
|
71 'popen2.popen2', |
|
72 'popen2.popen3', |
|
73 'popen2.popen4', |
|
74 'popen2.Popen3', |
|
75 'popen2.Popen4', |
|
76 'commands.getoutput', |
|
77 'commands.getstatusoutput' |
|
78 ] |
|
79 elif key == "shell_injection_noshell": |
|
80 return [ |
|
81 'os.execl', |
|
82 'os.execle', |
|
83 'os.execlp', |
|
84 'os.execlpe', |
|
85 'os.execv', |
|
86 'os.execve', |
|
87 'os.execvp', |
|
88 'os.execvpe', |
|
89 'os.spawnl', |
|
90 'os.spawnle', |
|
91 'os.spawnlp', |
|
92 'os.spawnlpe', |
|
93 'os.spawnv', |
|
94 'os.spawnve', |
|
95 'os.spawnvp', |
|
96 'os.spawnvpe', |
|
97 'os.startfile' |
|
98 ] |
|
99 else: |
|
100 return [] |
|
101 |
47 |
102 |
48 |
103 def _evaluateShellCall(context): |
49 def _evaluateShellCall(context): |
104 """ |
50 """ |
105 Function to determine the severity of a shell call. |
51 Function to determine the severity of a shell call. |
166 @type dict |
112 @type dict |
167 """ |
113 """ |
168 if config and "shell_injection_subprocess" in config: |
114 if config and "shell_injection_subprocess" in config: |
169 functionNames = config["shell_injection_subprocess"] |
115 functionNames = config["shell_injection_subprocess"] |
170 else: |
116 else: |
171 functionNames = _defaultValues("shell_injection_subprocess") |
117 functionNames = SecurityDefaults["shell_injection_subprocess"] |
172 |
118 |
173 if context.callFunctionNameQual in functionNames: |
119 if context.callFunctionNameQual in functionNames: |
174 shell, shellValue = hasShell(context) |
120 shell, shellValue = hasShell(context) |
175 if shell and shellValue: |
121 if shell and shellValue: |
176 if len(context.callArgs) > 0: |
122 if len(context.callArgs) > 0: |
205 @type dict |
151 @type dict |
206 """ |
152 """ |
207 if config and "shell_injection_subprocess" in config: |
153 if config and "shell_injection_subprocess" in config: |
208 functionNames = config["shell_injection_subprocess"] |
154 functionNames = config["shell_injection_subprocess"] |
209 else: |
155 else: |
210 functionNames = _defaultValues("shell_injection_subprocess") |
156 functionNames = SecurityDefaults["shell_injection_subprocess"] |
211 |
157 |
212 if context.callFunctionNameQual in functionNames: |
158 if context.callFunctionNameQual in functionNames: |
213 if not hasShell(context)[0]: |
159 if not hasShell(context)[0]: |
214 reportError( |
160 reportError( |
215 context.node.lineno - 1, |
161 context.node.lineno - 1, |
232 @type dict |
178 @type dict |
233 """ |
179 """ |
234 if config and "shell_injection_subprocess" in config: |
180 if config and "shell_injection_subprocess" in config: |
235 functionNames = config["shell_injection_subprocess"] |
181 functionNames = config["shell_injection_subprocess"] |
236 else: |
182 else: |
237 functionNames = _defaultValues("shell_injection_subprocess") |
183 functionNames = SecurityDefaults["shell_injection_subprocess"] |
238 |
184 |
239 if context.callFunctionNameQual not in functionNames: |
185 if context.callFunctionNameQual not in functionNames: |
240 shell, shellValue = hasShell(context) |
186 shell, shellValue = hasShell(context) |
241 if shell and shellValue: |
187 if shell and shellValue: |
242 reportError( |
188 reportError( |
260 @type dict |
206 @type dict |
261 """ |
207 """ |
262 if config and "shell_injection_shell" in config: |
208 if config and "shell_injection_shell" in config: |
263 functionNames = config["shell_injection_shell"] |
209 functionNames = config["shell_injection_shell"] |
264 else: |
210 else: |
265 functionNames = _defaultValues("shell_injection_shell") |
211 functionNames = SecurityDefaults["shell_injection_shell"] |
266 |
212 |
267 if context.callFunctionNameQual in functionNames: |
213 if context.callFunctionNameQual in functionNames: |
268 if len(context.callArgs) > 0: |
214 if len(context.callArgs) > 0: |
269 sev = _evaluateShellCall(context) |
215 sev = _evaluateShellCall(context) |
270 if sev == "L": |
216 if sev == "L": |
297 @type dict |
243 @type dict |
298 """ |
244 """ |
299 if config and "shell_injection_noshell" in config: |
245 if config and "shell_injection_noshell" in config: |
300 functionNames = config["shell_injection_noshell"] |
246 functionNames = config["shell_injection_noshell"] |
301 else: |
247 else: |
302 functionNames = _defaultValues("shell_injection_noshell") |
248 functionNames = SecurityDefaults["shell_injection_noshell"] |
303 |
249 |
304 if context.callFunctionNameQual in functionNames: |
250 if context.callFunctionNameQual in functionNames: |
305 reportError( |
251 reportError( |
306 context.node.lineno - 1, |
252 context.node.lineno - 1, |
307 context.node.col_offset, |
253 context.node.col_offset, |
323 @type dict |
269 @type dict |
324 """ |
270 """ |
325 if config and "shell_injection_subprocess" in config: |
271 if config and "shell_injection_subprocess" in config: |
326 functionNames = config["shell_injection_subprocess"] |
272 functionNames = config["shell_injection_subprocess"] |
327 else: |
273 else: |
328 functionNames = _defaultValues("shell_injection_subprocess") |
274 functionNames = SecurityDefaults["shell_injection_subprocess"] |
329 |
275 |
330 if config and "shell_injection_shell" in config: |
276 if config and "shell_injection_shell" in config: |
331 functionNames += config["shell_injection_shell"] |
277 functionNames += config["shell_injection_shell"] |
332 else: |
278 else: |
333 functionNames += _defaultValues("shell_injection_shell") |
279 functionNames += SecurityDefaults["shell_injection_shell"] |
334 |
280 |
335 if config and "shell_injection_noshell" in config: |
281 if config and "shell_injection_noshell" in config: |
336 functionNames += config["shell_injection_noshell"] |
282 functionNames += config["shell_injection_noshell"] |
337 else: |
283 else: |
338 functionNames += _defaultValues("shell_injection_noshell") |
284 functionNames += SecurityDefaults["shell_injection_noshell"] |
339 |
285 |
340 if len(context.callArgs): |
286 if len(context.callArgs): |
341 if context.callFunctionNameQual in functionNames: |
287 if context.callFunctionNameQual in functionNames: |
342 node = context.node.args[0] |
288 node = context.node.args[0] |
343 |
289 |