Issue 33515: subprocess.Popen on a Windows batch file always acts as if shell=True
Created on 2018-05-15 11:01 by abigail, last changed 2022-04-11 14:59 by admin.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 8906 | closed | sebres, 2018-08-24 19:43 | |
| Messages (2) | |||
|---|---|---|---|
| msg316638 - (view) | Author: Abigail (abigail) | Date: 2018-05-15 11:01 | |
It's possible to invoke an application without interpreting any of its arguments as shell magic: >>> print(subprocess.check_output(["C:/testapplication.exe", "foo", "&&", "echo", "%PROGRAMFILES%"])) Hello world from application! 5 arguments: Argument 0: 'C:/testapplication.exe' Argument 1: 'foo' Argument 2: '&&' Argument 3: 'echo' Argument 4: '%PROGRAMFILES%' But not so for batch scripts: >>> print(subprocess.check_output(["C:/testscript.bat", "foo", "&&", "echo", "%PROGRAMFILES%"])) Hello world from script! 2 arguments: Argument 0: 'C:/testscript.bat' Argument 1: 'foo' C:\Program Files I don't know if this is a fundamental limitation of Windows' batch script processing, or of the Win32 CreateProcess API, but this looks exploitable, as it allows shell injection: the subprocess docs warn about shell injection in a big red box, and promise you'll be safe if you a list of arguments and the default shell=False. Tested on Python 2.7.15 and Python 3.6.5. |
|||
| msg316716 - (view) | Author: Eryk Sun (eryksun) * ![]() |
Date: 2018-05-15 20:17 | |
There's no simple workaround for this behavior. All we can reasonably do is document that running a batch script directly has the same security risks as using shell=True. CMD doesn't support a file argument. It only supports running a /c or /k command, which can include running multiple commands joined by the &, &&, or || operators. CreateProcess thus executes a .bat or .cmd script by prepending "%ComSpec% /c" to the command line. If %ComSpec% isn't defined, it defaults to "%SystemRoot%\System32\cmd.exe /c". Environment variables in a command can be escaped in most cases by inserting the "^" escape character after the first "%" character. This disrupts matching the variable name (unless a variable name happens to start with "^"). The escape character itself gets skipped as long as it isn't quoted literally. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-04-11 14:59:00 | admin | set | github: 77696 |
| 2021-03-01 15:37:34 | eryksun | set | stage: patch review -> versions: + Python 3.9, Python 3.10, - Python 2.7, Python 3.6, Python 3.7 |
| 2018-08-24 19:43:11 | sebres | set | keywords:
+ patch stage: needs patch -> patch review pull_requests: + pull_request8375 |
| 2018-05-15 20:17:31 | eryksun | set | assignee: docs@python components: + Documentation versions: + Python 3.7, Python 3.8 keywords: + security_issue nosy: + eryksun, docs@python messages:
+ msg316716 |
| 2018-05-15 11:01:31 | abigail | create | |
