-
-
Notifications
You must be signed in to change notification settings - Fork 32.6k
bpo-34489: subprocess / fixed vulnerability by execution of batch-files (.cmd/.bat) in python for windows / insufficient escape #8906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…cial chars for quoting of arguments by exec process", if executing windows batch-files (bat/cmd). See https://github.com/sebres/PoC/tree/master/SB-0D-001-win-exec for details.
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA). Unfortunately our records indicate you have not signed the CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue. You can check yourself to see if the CLA has been received. Thanks again for your contribution, we look forward to reviewing it! |
…ellations as well as randomly generated combinations)
Regression tests extended, to invoke it with debug-output (as well as to execute also slow particular tests) use: python Lib\test\test_subprocess.py --debug |
…ecutable only, because currently no proper way to supply the newline to windows batch-files or command processor)
…uence (quoting of arguments for windows)
The CMD shell does not use VC++ rules to parse the command line. Backslash is not an escape character in CMD, and CMD does not remove double quotes that are added to escape special characters and white space. For example, given a test.bat script that executes
Also, there is no way to really escape "%" in a
|
I know. In this case it does no matter what Additionally this does not matter at al, because otherwise it is simply unusable because vulnerable by supplying of args like this to the batch-files - see python.diff. So in my opinion a bit "wrong"
Nope, you are wrong, there is a way (and it is already implemented), just checkout and try, so for example compare: -origin\python -Wd -3 -E -tt -R ./Lib/test/regrtest.py -v -m "*inject*" test_subprocess.py
+pr8906\python -Wd -3 -E -tt -R ./Lib/test/regrtest.py -v -m "*inject*" test_subprocess.py
...
Ran 156 tests in ...
-FAILED (failures=3, skipped=84)
+OK (skipped=2) or simply try it using a simple example above subprocess.call(['test-dump.exe', r'%USERDOMAIN%\&\%USERNAME%'])
subprocess.call(['test-dump.CMD', r'%USERDOMAIN%\&\%USERNAME%']) results in: >>> subprocess.call(['test-dump.exe', r'%USERDOMAIN%\&\%USERNAME%'])
`test-dump.exe´ `%USERDOMAIN%\&\%USERNAME%´
>>> subprocess.call(['test-dump.CMD', r'%USERDOMAIN%\&\%USERNAME%'])
- # inside origin\python
- `test-dump.exe´ `MY_DOMAIN\´'\sebres' is not recognized as an internal or external command, operable program or batch file.
+ # inside pr8906\python
+ `test-dump.exe´ `%USERDOMAIN%\&\%USERNAME%´ In my opinion both should produce the same result. An interpolation of variables (much less interim invocations of some executables) is a nonsense! |
But in the example I provided
Look at the output from your version of
The argument begins with |
My proposal does nothing is this direction if args supplied as string, it works only if you try to use called as "safe" variant, so using cmd as tuple or array. Please provide better (more speaking) example, so something like
Wrong. See above. So again, if I'm wrong, please provide an example used array (or tuple).
Hmm... You are right here, indeed. >>> os.environ['X'] = 'simply-X'; os.environ['"X"'] = 'quoted-X'; os.environ['""X""'] = 'doublq-X'
>>> subprocess.call(['test-dump.CMD', r'%X%', r'%"X"%', r'"%X%"'])
`test-dump.exe´ `quoted-X´ `%"X"%´ `"quoted-X"´ But, it looks like it is still possible (note the 2nd arg), but indeed more complex now (should possibly switch to "unpaired-quote"-similar logic/escape). WiP. |
For simplicity I started with a command line instead of using your version of
We can't use VC++ rules to create a command line for a program such as cmd.exe that does not itself use VC++ rules. In this case a VC++ escaped double quote is not seen as escaped by CMD, so the quote matching is wrong. My recommendation in bpo-33515 was to document that running a batch script (.bat or .cmd) always acts as if If I have time I'll check your code against some cases using command-line utilities such as reg.exe, setx.exe, sc.exe, schtasks.exe, and icacls.exe. If Python takes this burden on, it has to be robust. A solution that works only in simple cases is just asking for trouble. Again, personally I'd rather put the onus on the code that needs the shell, rather than pack all of the complexity into subprocess. Most people's use cases will actually be simple, and if starts to get mind-bendingly complex that's a sign that maybe you need a different approach. |
@eryksun I assume, I understand now what you meant with
will indeed result INSIDE the batch But this is an INITIAL state, it was ever "escaped" this way, also in original (unmodified) python (as well as in many other languages for windows). |
Just for the better understanding, so still again:
WiP. |
The new behavior could be implemented in a private function that's only called if the first item of the list is a .bat or .cmd file. (Note that
Do we currently recommended using an args list to run a batch script? We shouldn't. Assuming this PR is accepted for 3.8, it should be documented for older versions that using an args list in Windows is only for programs that follow the VC++ convention, which excludes CMD and batch scripts. If we support the creation of CMD-compatible command lines, the algorithm should at least guarantee that We need to use a pair of quotes for each literal double quote, as noted in this Stack Overflow answer. We can't use VC++ backslash escaping since that convention results in mismatched quotes in CMD. That said, it should be noted that VC++ and
IMO, it's more important that it works correctly in the VC++ runtime.
Yes, it would need to be documented that text between percent characters gets quoted, under the assumption that no existing environment-variable names contain double quotes. For internal consumption, batch scripts would have to handle replacing |
|
Labeling as "Do not merge" based on WIP comment. |
Because MS refuses the fix of the issue (see
|
Thanks for the PR, but closing as the CLA has not been signed within the last month. If you do decide to sign the CLA we can re-open this PR. |
@sebres you can email contributors@python.org as outlined at https://www.python.org/psf/contrib/contrib-form/ and see if the form was received. |
@sebres reopened! |
Hi @seberg! Unfortunately this did not reach a conclusion before Python 2.7 reached EOL on January 1st. As this does not appear to be a critical security issue, there is almost no chance that it will be accepted in this brief limbo window between end-of-support and the final 2.7.18 release, so I'm going to go ahead and close it. Do feel free to open a new PR against the Thanks for your contribution anyway, and I hope your next one is more fruitful! |
bpo-34489
Closes bpo-34489 vulnerability "insufficient escape of special chars for quoting of arguments by exec process" for python-language, if executing windows batch-files (bat/cmd).
Fixed for 2.7, but can be easy merged (or cherry-picked) for 3.x up to master.
What version of python is affected?
All
Does this issue reproduce with the latest master?
Yes
What did you do?
Execution of batch-file using
subprocess
module with arguments containing some special meta-characters.A recipe for reproducing the error as well as more extensive PoC with additional info (and more lang's affected also) - github/sebres/PoC/SB-0D-001-win-exec
A complete runnable program - test-dump-inv.py.
A simple example:
For more "broken" cases, see the result of my test-suite - python.diff
What did you expect to see?
Arguments are escaped/quoted properly.
What did you see instead?
Arguments are insufficient escaped/quoted, so it is vulnerable currently.
Solution:
BuildCommandLine
)Possible similar issues:
[[bpo-33515]](https://bugs.python.org/issue33515)