Live data from Hacker News

BatBadBut: You can't securely execute commands on Windows

flatt.tech

31–40 of 43 posts

Re: BatBadBut: You can't securely execute commands on Windows

#31
post #26

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

PowerShell has that whole execution policy thing, so you can't just launch a PowerShell script unless you wrap it in a batch file or some other script. I could see how allowing the user to whitelist individual scripts would make sense, but as far as I can tell that's not how it works? A blanket policy of "all scripts are forbidden unless wrapped with fragile and shady-looking hacks" doesn't seem particularly useful.

Disabling script signing on dev machines and requiring signatures on production scripts sounds like perfectly reasonable behavior to me. I know a lot of people are scared of pki but it’s way easier than people think. Signing things is a one liner, I keep certs on a portable HSM and it’s really low friction.

Re: BatBadBut: You can't securely execute commands on Windows

#32
post #15
post #10

Earlier quoted context omitted.

The primary linux interfaces for invoking programs with arguments (both in libc and the syscall level) have each argument be its own string, so it's possible to invoke a program with arguments such that no escaping or unescaping happens at all. If you want escaping, you have to either invoke /bin/sh (and give it your escaped command+argument string as an unescaped argument), or use 'system()' (which is literally defi…

Sure, but nothing is stopping /bin/sh from doing stupid things with its argument list once it gets them, which from what i understand is the equivalent of what is happening on windows.

The difference is that this bug exists at the border of two distinct components.

Suppose `/bin/sh` concatenated all arguments together, then split them back apart. That would be a stupid thing to do, but that stupidity would be entirely contained within `/bin/sh`. A bug report for `/bin/sh` could clearly point to the broken component and state that it needs to be fixed. This is possible because the `execve` API provides a list of strings. Any extra (concatenate, split) pairs must exist on one side or another of the border imposed by `execve`.

Here, there's a mismatch between two entirely separate components. The `CreateProcess` API accepts an arbitrary string. The `GetCommandLine` function returns that same arbitrary string. The (concatenate,split) pair must straddle the border between the two processes, with concatenation done on the side that calls `CreateProcess`, and splitting done on the side that calls `GetCommandLine`. A developer for the parent process can shrug and say that it's the fault of the child process for not parsing arguments correctly. A developer for the subprocess can shrug and say that it's the fault of the parent process for not providing arguments in the expected form.

Re: BatBadBut: You can't securely execute commands on Windows

#33
post #26

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

PowerShell has that whole execution policy thing, so you can't just launch a PowerShell script unless you wrap it in a batch file or some other script. I could see how allowing the user to whitelist individual scripts would make sense, but as far as I can tell that's not how it works? A blanket policy of "all scripts are forbidden unless wrapped with fragile and shady-looking hacks" doesn't seem particularly useful.

It's configurable with quite a few options.

But I guess here we have some of the underlying problem.

If something just executes whatever you throw at it, people complain.

If something doesn't just execute whatever your throw it, people complain as well. ;)

Re: BatBadBut: You can't securely execute commands on Windows

#34
post #26

Earlier quoted context omitted.

PowerShell has that whole execution policy thing, so you can't just launch a PowerShell script unless you wrap it in a batch file or some other script. I could see how allowing the user to whitelist individual scripts would make sense, but as far as I can tell that's not how it works? A blanket policy of "all scripts are forbidden unless wrapped with fragile and shady-looking hacks" doesn't seem particularly useful.

Disabling script signing on dev machines and requiring signatures on production scripts sounds like perfectly reasonable behavior to me. I know a lot of people are scared of pki but it’s way easier than people think. Signing things is a one liner, I keep certs on a portable HSM and it’s really low friction.

Unless you suddenly get sick and your HSM is unavailable?

Unless you get a 2nd person on the team (working remotely), and they want to be able to sign scripts as well?

Unless you get some sort of automated CI/CD system?

Re: BatBadBut: You can't securely execute commands on Windows

#36
post #26

Earlier quoted context omitted.

PowerShell has that whole execution policy thing, so you can't just launch a PowerShell script unless you wrap it in a batch file or some other script. I could see how allowing the user to whitelist individual scripts would make sense, but as far as I can tell that's not how it works? A blanket policy of "all scripts are forbidden unless wrapped with fragile and shady-looking hacks" doesn't seem particularly useful.

It's configurable with quite a few options. But I guess here we have some of the underlying problem. If something just executes whatever you throw at it, people complain. If something doesn't just execute whatever your throw it, people complain as well. ;)

None of the options seem very useful, though.

Why block execution of PowerShell scripts when batch files, WSH scripts and plain executables can still run? You could try to prevent those other kinds of scripts from even getting onto the machine, I guess, but then why wouldn't you simply do the same for PowerShell scripts?

The AllSigned policy where it asks you explicitly about trusting new publishers[0] seems like what I'm asking for, except that it apparently requires the certificate to be installed in Trusted Root Certificate Authorities! That's way more trust than should be necessary.

The only option that seems to make sense (aside from Unrestricted) is buying a certificate from an existing CA that's already trusted, so that users don't need to trust you with acting as a CA, but that's quite expensive.

[0] https://www.hanselman.com/blog/signing-powershell-scripts

Re: BatBadBut: You can't securely execute commands on Windows

#37

> 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…

The “usual escaping mechanism” may also refer to CommandLineToArgvW, a Windows API function that implements this. I think it is a pretty common way to implement the parsing side, though I’m not sure if the Visual C runtime does something different.

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

Re: BatBadBut: You can't securely execute commands on Windows

#38
post #2

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…

Regrettably, Windows (MSVC) includes _exec functions, but with the behavior that it seems to rejoin arguments into a single string, which then gets split again. > Spaces embedded in strings may cause unexpected behavior; for example, passing _exec the string "hi there" will result in the new process getting two arguments, "hi" and "there". https://learn.microsoft.com/en-us/cpp/c-runtime-library/exec...

This is worse than not having these functions at all...

Oh yeah, pass those arguments as a list, then we'll completely ignore that and fuck your shit up. Err, I mean you need to quote them! Even though they are passed as separate arguments.

Re: BatBadBut: You can't securely execute commands on Windows

#39
post #9
post #2

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…

> 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? I fail to see how this would help. If i understand correctly, the issue is how cmd.exe interprets the args, not how the args get to it.

Because only the OS will actually know if it is running a batch script and wraps it in a call to cmd.exe or an executable. If the OS was passed an actual list of arguments it can then encode them the correct way for either path and handle all of the complexity of each escaping for all users.

Re: BatBadBut: You can't securely execute commands on Windows

#40
post #20

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

It’s not an admin vulnerability, so there’s no hatchway. The real issue here is blindly passing user-provided input to a batch script, possibly from the Internet, and if you’re doing that then you’ve got much bigger problems. If you’re doing it using an account with any kind of privileges, you’re kinda asking to get broken into.

That isn't the problem. It is completely possible to process untrusted data in a batch script. (Even if it likely isn't the best tool for the job) the problem is that the method of getting that untrusted data to a batch script is incredibly complex and was being done wrong by a number of programming languages.

For example imagine that I have a shell script to write an entry to a guestbook. Maybe I call it from my webapp like this:

    # webapp.py
    subprocess.run(['guestbook', untrusted_msg])
On Linux this is perfectly fine. I can then write my guestbook script like

    #!/bin/bash
    echo "$1" >> guestbook.txt
As far as I am aware there are no security issues here. The user can pass whatever they want as the message and other than some mess in the `guestbook.txt` file they can't cause any harm.

However this doesn't work well on Windows because in order to escape the arguments you need to know how the `guestbook` program parses its arguments. Right now basically all languages assume that the caller will use `CommandLineToArgvW`. However if `guestbook` is a batch file a different parsing mechanism is used and remote code execution can occur before the batch script even starts executing.

Basically in order to properly escape the arguments the caller needs to know what is being called. The current APIs don't have a way to know this so they can't do it right in all cases.

Post reply on HN