BatBadBut: You can't securely execute commands on Windows

by explodingwaffleon 4/9/2024, 8:05 PMwith 42 comments

by tmgrosson 4/9/2024, 10:22 PM

Is there any reason Windows couldn't add an equivalent of execvpe for arguments and environment to be passed as arrays, which newer programs could then use directly? The OS could handle safely re-quoting as a string for older programs that need compatibility, rather than leaving it up to the language or programmer to hopefully do right. Which seems pretty difficult, based on the fact that seven major languages got a CVE today - plus a possible exploit in every C application that is doing this by hand.

The API could even be a more modern pointer+length interface rather than null termination, to sidestep that class of mistakes/exploits (CWE-170).

https://www.daviddeley.com/autohotkey/parameters/parameters.... is a great read on how fragmented this all seems to be.

by kazinatoron 4/10/2024, 3:19 AM

> And unfortunately, the cmd.exe has different escaping rules compared to the usual escaping mechanism.

This "usual escaping mechanism" is a bit of a weasel word. Windows passes a single null-terminated character string to a process. Every application run-time must parse that into arguments itself.

I think what "usual escaping mechanism" refers to is the algorithm implemented in the Microsoft Visual C Run Time which takes the command line string and produces a char *argv[] for the main function.

There is no telling what uses that exact algorithm and what doesn't. Programs built with Microsoft languages probably do; obviously VC and VC++.

by whoisthemachineon 4/9/2024, 10:23 PM

This seems more like a gap in the windows API than in the programming languages.

by gibibiton 4/10/2024, 5:02 PM

Nice to see Rust (and Haskell too) released a fix immediately but Java is "affected, but won't fix". :)

by steve1977on 4/10/2024, 5:33 AM

Who‘s still using batch files and cmd.exe now that we have PowerShell?

by bawolffon 4/10/2024, 12:40 AM

That's a lot of preconditions to meet in order to exploit.

by hosejaon 4/10/2024, 10:45 AM

Would LOVE to hear what other side of an "airtight" hatchway this one is.

by ptxon 4/10/2024, 2:34 PM

This is a weird coincidence – I ran into this exact problem two days ago, the day before the post was published.

I was just trying to write a simple batch script that accepted filenames as arguments and was surprised to find that there is no safe way to do so, as they're always passed through shell expansion, so if you have a filename like "foo %PATH% bar.txt" (which is allowed) the script will receive it with the PATH variable expanded and cannot get at the actual filename.

Also, passing arguments to programs is unsafe on Windows even if you don't go through the shell, because the quoting rules are entirely up to the program being invoked. The CreateProcess function[0] accepts a string, not an array, so you have to quote the arguments – but you can't do this quoting correctly unless you know exactly what program you're invoking and what grammar it has chosen for parsing its lpCommandLine string.

The article mentions that "many programming languages guarantee that the command arguments are escaped properly", but there is no universal "escaped properly" on Windows. There is escaped properly for the C runtime's parser[1], or escaped properly for CommandLineToArgv[2] which parses "in a way that is similar to" the C runtime, or escaped properly for .NET which has its own set of rules[3] – but there is no guarantee that any particular program is using any of these ways; any program can use whatever rules it likes!

Raymond Chen has written[4] about this as well.

PowerShell has an interesting workaround[5] of sorts: If you specify "-EncodedCommand" and "-EncodedArguments" it lets you pass base64-encoded strings when you "require complex quotation marks or curly braces".

[0] https://learn.microsoft.com/en-us/windows/win32/api/processt...

[1] https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-c...

[2] https://learn.microsoft.com/en-us/windows/win32/api/shellapi...

[3] https://learn.microsoft.com/en-us/dotnet/api/system.environm...

[4] https://devblogs.microsoft.com/oldnewthing/20100917-00/?p=12...

[5] https://learn.microsoft.com/en-us/powershell/module/microsof...

by pogueon 4/10/2024, 12:12 AM

I'm seeing a 404 error?