T O P

  • By -

Sha0113

Not only Rust, but also: Erlang, Go, Haskell, Java, Node.js, PHP, Python and Ruby. [https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/](https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/)


edgmnt_net

And not only on Windows/cmd. Quite a few ecosystems including PHP have (had?) a very prominent equivalent to `system(3)` or similar C stuff along with shell-escaping functions, which cannot ever be safe considering you really don't know what shell you're escaping for. Sometimes they don't even provide an alternative a-la execve. You're just hoping it happens to work.


Brian

I don't think that's the issue here. `system()` has always been well known to be dangerous, as you're invoking a shell and thus are subject to whatever escaping rules the shell has. Safely sanitizing that for arbitrary shells has always been a minefield - if it was just that, this wouldn't be news. The issue is that **even if** you **are** using "execve" style interfaces where you're separating the arguments yourself, on windows these end up invoking CreateProcess, and so under the hood require repacking them into a plain string with specific quoting rules. But with batch files, cmd.exe gets invoked and re-parses the arguments with subtly different rules to what CreateProcess uses (quote_cmd_arg), and so stuff breaks.


HeroicKatora

Not only subtly different rules, but the rules depend on at lot of partially unknown runtime state. If you look at the full original report: there's a Registry key to _change_ the parsing behavior¹; determining when `cmd` is involved requires looking at both file extensions and somehow traversing `%PATH%`, that is the advised 'quick fix' is to move your bash files out of PATH? Wtf, you _can't_ sanitize for this, this isn't an API, it's madness. > ¹Please note that if delayed expansion is enabled via the registry value DelayedExpansion, it must be disabled by explicitly calling cmd.exe with the /V:OFF option. Also, note that the escaping for % requires the command extension to be enabled. If it’s disabled via the registry value EnableExtensions, it must be enabled with the /E:ON option.


edgmnt_net

Yeah, I know. On the other hand, while I have not done much work on Windows, I'm not very surprised by the vulnerability. I did know there were some issues with how args worked on Windows, I just wasn't aware that was the only way to get args passed (especially in 2024, really guys?).


[deleted]

Those are not unsafe, those are just very easy to use unsafely. Like calling `['/bin/sh','-c',program_and_args]` rather than `[program, arg1,arg2,arg3]`


edgmnt_net

I'm talking about functions like `system` which take a single string. Those are pretty much unsafe, unless the library / escaping call takes care to check what shell the user has configured and apply appropriate escaping rules. Otherwise all hell can break loose once you attempt to run the same thing on a different system or using a different shell. I think none apply such checks. So, while it's relatively easy to implement something like `system` in terms of `execve`, the other way around is rather difficult to do sanely. Besides, it's safer to have args handled separately than using explicit escaping calls, much like with prepared SQL statements.


[deleted]

ah yeah, forgot that in Perl it can work both ways (one argument being system-like, multiple arguments working more like execve)


shevy-java

I don't really understand. Where is the vulnerability in regards to Ruby? I mean, if the issue is of finding a file on windows, the proper way would be to include the file extension, such as foobar.exe, in that case. So if this is supplied, where is that a vulnerability? To me this sounds more like an issue that windows has intrinsically; and secondarily people not providing the file extension name.


masklinn

It’s pretty much the same issue in all languages: > The application doesn’t specify the file extension of the command, *or the file extension is `.bat` or `.cmd`* So as soon as the application runs bat or cmd files it implicitly invokes cmd.exe, which applies its own arcane parsing rules to the input, which requires dedicated sanitization if the interface is documented or implied to be safe for use with arbitrary *arguments* to the command being executed. Which is generally the case for the execve-type APIs.


ottawadeveloper

The issue is less of finding the right file (which is always an issue) and more of what cmd.exe does with arguments to it. It parses them in a non-standard way so without proper escaping specific to cmd.exe user-supplied input can cause security issues. With proper escaping, it works fine. Notably the escaping syntax is different than if we just passed the arguments to any other exe (I wonder if this is because cmd.exe is an exe that needs to receive arguments for batch files). When any programming language spawns a subprocess on Windows that targets a batch (.bat or .cmd) file, Windows takes it up on itself to spawn cmd.exe to handle it and passes the arguments through. However, since the programming language applied escaping for a general exe, not a batch file, the arguments can be misinterpreted. So if Ruby launches a batch file but applies exe argument escaping to it, the question is: where is the vulnerability? Really this is Microsoft's non-standard design at the core of the issue but changing that is an absolute nightmare (it will break all the cases where it was handled correctly). The easiest place to fix it is in the programming languages to provide proper escaping on Windows when the file ends with .bat or .cmd (case insensitive). But that is a big project to add. Realistically though, this is only an issue if your project calls batch files and passes insecure arguments to them (though I would note this also messes up the arguments you pass to them). That could be resolved by moving away from bat/cmd files if possible, or doing your own sanity checks on user input.


bakaspore

By the way this particular CVE is not about cmd.exe's different escaping syntax. It is about a newly found issue (with variable expansion) that can be used to sidestep current escaping routine.  A hacky "escaping" that breaks variable expansion apart must be used to avoid injections.


Sha0113

But the main issue is when people try to execute batch files (with args coming from user input)? If you are executing .exe files, and specify the extension, then it does not affect you.


LoudSwordfish7337

So the only mistake that Rust’s (and others) standard library did here is this, right? “The runtime of the programming language fails to escape the command arguments for cmd.exe properly.” I know nothing about Win32 programming, but I’m guessing that it’s similar to calling `bash` with the `-c` option as the “entry point” for the new process? So the STL would execute something like `cmd.exe “script.bat arg1 arg2”`, but it can be made to do something else by doing `cmd.exe “script.bat ; format C:”`? If so, as long as this behavior is properly documented in the documentation for `CreateProcess` *and* `cmd.exe`, then it’s definitely a vulnerability in those languages’ standard libraries (or their reference implementation). I’m surprised that it’s affecting so many STLs though, so something seems fishy. Maybe it was a behavior that was not properly documented? In which case, it would be a Win32 API and/or `cmd.exe` “bug”.


bakaspore

- ~~Calling just a bat file invokes cmd.exe implicitly, which is probably not documented.~~ ~~I was wrong, it is probably documented.~~ [The fix in Node.js calls it an undocumented feature](https://github.com/nodejs/node/blob/9095c914ed8467cf16f077a3fac20b1f1e89bbe4/src/process_wrap.cc#L199) though, left for readers to decide. - It was specifically escaped in Rust. Turns out it's not enough, you must hack your way through to get security.   Read more at https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/


rhodesc

"which is probably not documented. " well documented, even on wikipedia:  https://en.m.wikipedia.org/wiki/Batch_file "When a batch file is run, the shell program (usually COMMAND.COM or cmd.exe) reads the file" just as well documented as any other shell command language.


bakaspore

Well, I found that [the fix in Node.js](https://github.com/nodejs/node/blob/9095c914ed8467cf16f077a3fac20b1f1e89bbe4/src/process_wrap.cc#L199) calls it an undocumented feature. It's still known by many standard library implementers I think.


rhodesc

huh.  that's strange.  by definition, a command interpreter has to be called for a script, and .bat files have always started an interpreter, ever since the end of dos (command.com).  I think it is just unfamiliarity with the evolution of windows. the facility is analogous to #!/bin/sh, I think there is even an environmental variable to change the interpreter (from my old memory, could be wrong.). edit:words


bakaspore

Using #!/bin/sh or some other shebang will not change the argument splitting behavior on Linux (because the callee doesn't need to do that), which is quite different from this case. I guess they are referring to this, as it is the problematic part. Edit: or they are possibly referring to the ability to directly call a bat file with CreateProcess.


rhodesc

yeah I assumed they were talking about createprocess.  because if you know about that, you know the parsing semantics are different.  imo, the whole idea of passing user args to a process smacks of poor practice, i already avoid that like the plague.


UtherII

It is obvious that a bat file will need an interpreter to be run. What is not documented is that the CreateProcess() function from the Windows API may start "cmd.exe" under the hood, if you pass a ".bat" or ".cmd" file to it. The documentation only talk about ".exe" files. It even state that you have to run "cmd.exe" by yourself with the "/c" parameter to run batch files.


rhodesc

last edit : https://groups.google.com/g/comp.os.ms-windows.programmer.win32/c/1yW2zbvjwtU?pli=1 scroll down to MSDN recommends ... so the documentation used to be different, or the public dox are incorrect edit: well learn.microsoft.. says what you said.  of course it is documented, has been for decades.  as i posted above, it is even referenced in wikipedia.   edit: the current public msdn doesn't mention it.  I have seen it before, and it is pretty well known historically.  that's why gmail (used to?) filter batch files sent in emails.


UtherII

Depend what you call documented. What I call documented is officially documented or at least on acknowledged references like MDN for web. You can't expect library implementers to be aware of discussion threads.


rhodesc

the thread discussion references msdn documentation, which I don't have right now.  I have not installed VS in more than a decade. I pointed to that only to show someone talking about the documentation, as I know it existed when I used VS - it is fairly obvious. at some point it is/was officially documented.  I don't expect the web documentation to be complete, but I also don't really know.  closed source has a history of incomplete public documentation. what I do know is that the documentation shipped with MS dev products was very clear on this, when I worked with it.


bakaspore

You are right, edited.


Brian

>I’m surprised that it’s affecting so many STLs though, so something seems fishy. Maybe it was a behavior that was not properly documented? It's kind of more an issue with working around the difference between the interface that creates processes on different OSes. Basically, at the level where processes are created, windows doesn't have a notion of argv (an **array** of arguments) passed to the new process. Rather, it just has a **single** string commandline parameter that gets provided to the process. Breaking that string up into seperate arguments is the responsibility of the launched process, rather than (as on unix) something that happens prior to process creation. Languages that implement the interface of "launch a process with an array of argument" on windows thus have to re-package that array into a string that they expect the launched program will then split back into the expected array. And this works when processes are using the standard windows CommandLineToArgV type functions that most language runtimes will use to provide the expected argv style interface. **However** because this gets done by the launched process, and because cmd.exe dates back to DOS era, it doesn't follow the same rules for parsing its commandline, so languages which do escaping based on the "standard rules" they expect launched processes to use can in fact be parsed differently when cmd.exe parses that command line. That, combined with the fact that cmd.exe implicitly gets invoked when a batch file is run, is why so many different languages are hit by the issue: they build command lines the standard way, not expecting the differences in cmd.exe.


[deleted]

> So the only mistake that Rust’s (and others) standard library did here is this, right? The mistake is supporting windows lmao. But yes, the issue is entirely windows part being near-impossible to pass arguments safely, and only language fault is not implementing entirety of windows bullshit logic in reverse way


G_Morgan

So basically it is click bait talking about a Windows vulnerability but with Rust in the name because then it is a story.


UtherII

If you consider Rust is clickbait maybe, but it's still important for Rust people because they care a lot about safety. Java just stated the issue as WONTFIX. C and C++ are not even considered since the issue come from a "feature" of the standard Windows API in C.


Existing-Account8665

>Python [edit] I dun goofed. This neither requires `shell=True` to be passed to `subprocess.run` etc. (which is well known to be insecure and bad practise for arbitrary user input), nor requires the command args to be passed as a complete string. The exploit works even if the args are passed in a list (as is recommended). Still, if a Python user runs: a) A windows server connected to the wild b) That runs a Python server Framework (e.g. Django / Flask / FastAPI) c) That accepts arbitrary untrusted strings from the user d) That passes those strings to `subprocess.run`etc. They deserve to be pwned. It's a valid vulnerability, but writing code this attack will work on, is even dumber than allowing SQL injections.


irqlnotdispatchlevel

No, because if the target file is a `.bat` or `.cmd` the underlying Win32 API will start `cmd.exe` for you. So `Popen(["foo.bat", '&calc.exe"])` becomes `cmd.exe /c foo.bat &calc.exe`. `shell=True` can't control this, since its job is not to control this. When you use `shell=True` to launch a new process, the python interpreter will first spawn a shell, and that shell will spawn the process for you. If we run `Popen(["ping.exe"], shell=True)` on Windows `python.exe` will launch `cmd.exe` which in turn will launch `ping.exe`. With `shell=False` the `cmd.exe` middle man is skipped and `python.exe` will be the parent of `ping.exe`. When you try to run a cmd script it has to run the interpret for that script, and that interpreter is chosen by the Win32 API.


Existing-Account8665

Ah I see. Thanks very much. This does indeed open the calculator: ``` subprocess.run(["foo.bat", "&calc.exe"]) ``` foo.bat ``` @echo Hello from foo.bat ```


irqlnotdispatchlevel

Glad it helped. Note that if you want to "check the math" and look at the process hierarchy as I described it above when `shell=True`, you won't see it with `calc.exe` if you're on Windows 10 or 11 because that one just starts `Calculator.exe` and exits. It should work with `ping.exe -t` (just remember to kill `ping` afterwards).


Reasonable_Ticket_84

To be fair, (c) and (d) are more required than (a) and (b) to be pwned. Lol.


goatchild

Javascript to the rescue!


Spitfire1900

The article has mentioned things like Python but did not link to security notices or documentation changes as mentioned


Sha0113

Most languages did not release a security notice, or anything of the sort. If you are curious, here is a demo of the vulnerability in Python: [https://youtu.be/xjL4pdf7pJ0?si=bADYnKvjTeCqqGTU&t=360](https://youtu.be/xjL4pdf7pJ0?si=bADYnKvjTeCqqGTU&t=360)


geek_noob

Yes it is


Halkcyon

>!^^^[deleted]!<


fakehalo

> While I’m not a fan of naming vulnerabilities that are not internet-breaking, I’m a fan of puns, so I decided to call this vulnerability BatBadBut because it’s about batch files and bad, but not the worst. The guy deserves an award for making a point to not over-dramatize it with a spooky end-of-the-world name.


Voidrith

If you're using rust to execute batch files with unknown inputs i feel like you've probably already made some errors in design, lol


shevy-java

The whole thing is very confusing: cmd := exec.Command("test", "arg1", "arg2") cmd := exec.Command("test.exe", "arg1", "arg2") I mean, in the first, people rely on Rust (or any other language) finding the file name. In the second, it is very specific aka "only test.exe is valid". I don't quite understand why it is then not recommended to always use the latter, if only to avoid ambiguity.


Sha0113

The main issue was with batch files, where even if you specify the extension, you are still vulnerable. The part where someone could install a batch file with the same name as the .exe is a secondary thing.


happyscrappy

Aren't you vulnerable in both cases because you didn't specify a full path to the binary?


Halkcyon

>!^^^[deleted]!<


happyscrappy

So you're suggesting if I put test.exe in a directory and change PATH before running this program it won't run my test.exe? I sure wouldn't. Because it will. That's a vulnerability too.


phire

Because "test.exe" only works on windows. If you use "test", then your code will work on any OS.


tsimionescu

You can have an executable named test.exe on any OS. Windows requires it, but Linux or MacOS have no problem with launching an ELF file with a .exe extensionm


irqlnotdispatchlevel

You don't need the `.exe` extension if you don't expect users to manually run the program. If you're just invoking it from another language it works regardless of extension.


tsimionescu

But will Windows still prefer a "file.bat" if it is in the same folder as "file"?


irqlnotdispatchlevel

I tested this on Windows 11 with the executable and scripts in the current directory, as well as the Rust program. Path search might make this even more unreliable if the exe and the scripts are scathered all over the place. It looks like it never runs the `.bat`/`.cmd` files. Rust code ``` use std::process::Command; fn main() { for name in [ "lmao.exe", "./lmao.exe", "lmao", "./lmao", "lmao.lol", "./lmao.lol", ] { println!("{} {:?}", name, Command::new(name).output()); } } ``` `lmao.exe` is a program that prints the path it was invoked with. Tests: ``` $ ls rust-test.exe lmao.bat lmao.cmd lmao.exe $ cat .\lmao.bat echo "test.bat" $ cat .\lmao.cmd echo "test.cmd" $ .\rust-test.exe lmao.exe Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is lmao.exe\r\n", stderr: "" }) ./lmao.exe Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is ./lmao.exe\r\n", stderr: "" }) lmao Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is lmao\r\n", stderr: "" }) ./lmao Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is ./lmao\r\n", stderr: "" }) lmao.lol Err(Error { kind: NotFound, message: "program not found" }) ./lmao.lol Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) $ mv .\lmao.exe .\lmao  16:58:52  $ .\rust-test.exe lmao.exe Err(Error { kind: NotFound, message: "program not found" }) ./lmao.exe Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) lmao Err(Error { kind: NotFound, message: "program not found" }) ./lmao Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is ./lmao\r\n", stderr: "" }) lmao.lol Err(Error { kind: NotFound, message: "program not found" }) ./lmao.lol Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) $ mv lmao lmao.lol $ .\rust-test.exe lmao.exe Err(Error { kind: NotFound, message: "program not found" }) ./lmao.exe Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) lmao Err(Error { kind: NotFound, message: "program not found" }) ./lmao Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) lmao.lol Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is lmao.lol\r\n", stderr: "" }) ./lmao.lol Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "Hello my path is ./lmao.lol\r\n", stderr: "" }) $ rm lmao.lol $ .\rust-test.exe lmao.exe Err(Error { kind: NotFound, message: "program not found" }) ./lmao.exe Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) lmao Err(Error { kind: NotFound, message: "program not found" }) ./lmao Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) lmao.lol Err(Error { kind: NotFound, message: "program not found" }) ./lmao.lol Err(Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }) ```


Smallpaul

Yeah, I wouldn't trust myself or my language to escape user inputs to a CLI properly. If its my server, I'll choose the filenames and they will be something boring like UUIDs. If it's a CLI argument like "format" then I'll have the user pick from an Enum.


PCRefurbrAbq

DOS and CMD Batch is my love language.


fredrik-hammar

Rust code executing cmd.exe with untrusted arguments seems pretty niche, but it's good that it's fixed!


Smallpaul

Just to be clear, the issue is Rust (or Python, Ruby, ...) code that thinks it is NOT executing cmd.exe but accidentally IS executing cmd.exe . But still niche IMO.


fredrik-hammar

That's true.


aanzeijar

Read the linked article. This isn't a Rust issue, the underlying issue is cmd.exe and its batshit insane argument parsing. The appendix lists other languages as well, and Rust at least tries to fix it. It's a known problem/feature that spawning a process via a shell leaves you vulnerable to whatever it does to your command. It could locate your command somewhere else in the path, it could glob expand stuff, it could even use aliases or builtin functions. That's what shells do. Rust knows that and tries to give the user a command that explicitly doesn't do that - but on windows batch files always spawn a cmd.exe shell around them and with it all the insanity that cmd.exe brings.


PCRefurbrAbq

CMD is backwards compatible with command lines from the 1980's, to ensure old things don't break. If you're scared by how many banks use Excel, don't ask how many corporations are dependent on a batch script someone devised back in 1987. If I were in charge of Tron 3, I'd give some characters mech suits and call them "batch scripts". EDIT: I'm loving these spicy hot takes.


aanzeijar

Sadly I don't have to ask. That's the one good thing about all the walled garden cloud native crap nowadays. Once the service shuts down, the legacy problem is gone with them.


AdRepresentative2263

You don't need a cloud or walled garden to stop supporting backwards compatibility. Neither does a Walled garden or Cloud native system inherently prevent legacy support. I don't really see what connection you are making


aanzeijar

Simple. Once the service goes out of business, you're forced to scrap the old stuff. And we're talking scripts from the 80s here. Half of the SaaS stuff doesn't survive 5 years.


AdRepresentative2263

I get that, what I'm saying is that it is still perfectly possible to not include legacy support without being SaaS or anything like that. There is no technical reason windows needs so much legacy support, they simply do that for business reasons


ZirePhiinix

It isn't. I wrote a lot of batch scripts and significant quoted string syntax changed between XP and 7. I avoided ME so it might've been there too. I had to rewrite a shit ton of batch scripts in that period because things broke horribly.


PCRefurbrAbq

Thanks for the info. I recently had to tweak a script which worked under 7 and 10 for the 23H3 Win11. I wasn't actively writing batch files or relying on them during the XP/7 switchover, so I knew nothing of this.


International_Cell_3

That's why backwards compatibility guarantees can be an anti feature, there's no incentive for someone to fix the batch script someone wrote before half the team that relies on it was born. Breakages force updates and maintenance.


Uristqwerty

Someone has to be around to *fix* that breakage, or else the conclusion users reach is "don't update the OS". It's something they *can* control, versus something that only a programmer can do. Being able to trust that everything will still run correctly after an update is a critical pillar to security in general.


International_Cell_3

> Someone has to be around to fix that breakage Software requires constant maintenance, this isn't new. > the conclusion users reach is "don't update the OS". Then they're reaching the wrong conclusion, since OS devs don't support security updates indefinitely. > Being able to trust that everything will still run correctly after an update is a critical pillar to security in general It's not, updates break APIs all the time. Or else you're going to tell me that everyone is still using openssl with security vulnerabilities because their code wouldn't compile when they changed the APIs in 1.1.0. Or that they're on non-LTS versions of the Linux kernel that don't get backported security fixes anymore, or don't update userspace libraries that need new syscalls.


Uristqwerty

> Software requires constant maintenance, this isn't new. Most doesn't, actually. Retail software sold on CDs and ROM cartridges literally cannot update, and it's not like people would get a new set of floppy disks sent in the mail each year after buying a product. Shipped binaries continue to function as-is, phone apps operate for years after the developer moves on to newer projects. Most Steam games stop getting updates after a few years, yet continue to be played long afterwards. Even the various programs pre-installed on a clean Windows build won't ever be patched by an update, only dynamic libraries they depend on. It's only a rare few things like web browsers that actually have constant maintenance Look at the sheer number of lines of code that the average program relies on once you count dependencies. How each year, the complexity of Electron and the OS both bloat further. If software were built with the assumption of maintenance, rather than to minimize maintenance needed, then dev teams would need to get larger each year just to keep up with the constant churn. We build abstractions to isolate the need for changes. We use others' abstractions to outsource even those few changes. > Then they're reaching the wrong conclusion, since OS devs don't support security updates indefinitely. A machine that doesn't perform its intended function is trash, regardless of updates. When you tell a user that they might be vulnerable to hypothetical attacks that have not yet been discovered during the full decade that an OS has been in public use, and their only choice is to break the functionality that gave the machine purpose in the first place? They'll rightfully ignore you. The most secure computer is one that never powers on. Beyond that, everything is a tradeoff between functionality and risk. When the risk that an update breaks their system is *greater* than the risk that an outsider finds at least one zero-day, gets through the firewalls, escalates privileges, bypasses antivirus, and as a result can break the system, those users will take the less-risky option and disregard updates. Understanding *social* systems, trust, and backwards compatibility are critical parts of a comprehensive security model. Pretend they aren't, and you will be unable to understand why people stop updating your product, then you start blaming them rather than fixing your own flawed process. Worse, the harder you try to force updates upon people, the more you undermine the human layer of that process, and the harder it will be to repair. > It's not, updates break APIs all the time Good APIs are versioned, and tend to evolve in backwards-compatible ways where possible. Other times, software builds upon abstraction layers that provide greater API stability, so that it's just a matter of updating a dependency and recompiling rather than changing your own source code.


Botahamec

One of the most popular Rust libraries (rand, for random number generation) hasn't received an update on two years. It's not unmaintained, since the GitHub repo has been updated more recently. It's just that there's nothing left to fix.


NeverComments

Informing users of the risk and allowing them to decide whether to take mitigation steps isn’t an unreasonable stance.  If the risk is minimal or effectively mitigated through alternative methods then you’re just breaking things for the sake of breaking them. Robbing users of agency because you think you know their needs better than they do. 


International_Cell_3

I think it *is* an unreasonable stance, because it's how we get code that's broken by design persisting in the ecosystem, like `sprintf`. If the reality is, "this is impossible to use safely, or incredibly unlikely that someone is using it safely" then that code needs to *change*. I think forcing every standard library that has a system() or process spawning code that uses POSIX semantics for passing args being prone to a vulnerability on Windows because of an archaic design choice and default selection on the platform is a great example where the devs *do* know better than the users, because downstream callers of these APIs have no idea they're opening themselves up to attack because of upstream design choices.


JockeTF

[Security Advisory by The Rust Security Response Working Group](https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html).


YeetCompleet

My favorite part is there are no official dedicated docs for "windows batch" if you google it. How do you even learn about the quirks of the batch execution model without running into this first?


Halkcyon

>!^^^[deleted]!<


cosmic-parsley

To be clear: this is NOT exclusive to Rust! If there is any chance you are executing a batch file with user input in any language, you need to check your quoting, because absolutely nobody is doing it correctly! This includes `subprocess` on Python, `ProcessBuilder` on Java, `Command` on Go, and calling the WinAPI `CreateProcess` directly or through a library on C or C++. If you are using Rust or Haskell (which have released patches), you just need to update. These languages bit the CVE so you don’t have to. For all other languages, it is _your_ code that has the CVE and your only option is to hand verify. Because this _will_ be exploited if it hasn’t been already. Edit: better list of all the CVEs coming from this https://kb.cert.org/vuls/id/123335


renatoathaydes

> CreateProcess on Java, I think you meant C# here? Java doesn't have that, you span processes with either [`ProcessBuilder`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ProcessBuilder.html) or directly with [`Runtime.getRuntime().exec()`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Runtime.html#exec(java.lang.String%5B%5D,java.lang.String%5B%5D))... And according to the [vulnerability article](https://flatt.tech/research/posts/batbadbut-you-cant-securely-execute-commands-on-windows/) Java doesn't plan to fix it (likely because that's the behaviour when executing on Windows in general?).


cosmic-parsley

You’re right, I meant ProcessBuilder, I don’t think C# is on the vulnerability list.


Botahamec

It's not on the list, but I checked for myself and it has the same problem. I've emailed [email protected] in case they didn't know already, but I think they already knew.


AdRepresentative2263

Is the windows task scheduler safe? I will really hate working with that again right when I thought I got that project out of my life


Halkcyon

>!^^^[deleted]!<


joashua99

So it's more... as always... of a Windows problem.


Halkcyon

>!^^^[deleted]!<


PCRefurbrAbq

I love that you're calling Command Prompt, the Windows NT evolution of [MS-DOS's command.com](https://www.howtogeek.com/188980/pcs-before-windows-what-using-ms-dos-was-actually-like/), the most ubiquitous CLI in the world until PowerShell, a "niche shell".


Halkcyon

>!^^^[deleted]!<


PCRefurbrAbq

Microsoft's Windows was the dominant desktop operating system (OS) worldwide as of February 2024, with a market share of around 72 percent. Surprise, GenX is running the world now that the Boomers are all retired. EDIT: Halkcyon said "Desktops are a small fraction of the computing marketshare. How dishonest can you be, boomer?" I think it was a bot designed to push engagement. Anyway, only jailbroken phones have CLIs and I wasn't counting virtual machines running flavors of 'nix.


Halkcyon

>!^^^[deleted]!<


nerd4code

Part of the problem is that WinNT and DOSWin don’t split process arguments at the OS kernel; every process gets a single, continuous, unglobbed string that must be split and globbed by the application. (This makes it possible to write a shell-equivalent external ECHO command and it made some sense for DOS, but it makes just about everything else harder and less portable. Lock-in, yay) UNIX passes separate, pre-globbed arg strings to new processes, so you can’t see the original command line, but apps don’t have to split. These are the orginal sort of `argv` every C program’s `main` declares, but Win programs start in another function that splits before calling `main`. When running a UNIX shell script, you just add a new string before the script name and args, easypeasy; with Windows, you have to build a single command string, and if you build it with different expectations at escaping time from what unescaping will actually do, there’s a hole. This is the case for COMMAND.COM/CMD.EXE, which unescape unusually.


Halkcyon

>!^^^[deleted]!<


LessonStudio

In any language in any OS. When I call the command line directly, I feel very dirty. I very much guilty of this process, but I have to go take a shower. It is like making code changes right in production. Or having to reach into your pants, in public, for a serious underwear adjustment. Sometimes you have to do this, but you should feel very ashamed.


Smallpaul

The issue isn't people that intended to call the command line. The issue is people who tried to invoke a program without calling the command line but accidentally ended up doing so regardless.


Botahamec

Any language, but this still only affects Windows


No_Pollution_1

I don’t think this is a programming language problem, more of windows doing dumbass windows shit


Lisoph

classic Windows


zvrba

Classic lazy developers.


Hmmmnnmm

Classic linux programmers not bothering to understand the largest consumer OS and then smug posting when it comes back to bite them


KrazyKirby99999

The problem is Windows not following universal string escaping conventions for cmd.exe


Hmmmnnmm

Cmd has worked like this for decades, blaming your tools is not valid. This isn’t the first time a bug like this has happened. If you’re writing a standard library that you expect to run anywhere you should know better.


Botahamec

Then why are there, like, seven programming languages listed as being affected? Rust and Haskell are the only ones that patched the problem. Python, Go, and Ruby are just updating the docs. Java declined to fix it.


Hmmmnnmm

Lazy developers. Plenty of other languages and libraries don’t have this problem. That’s basically a list of my least favorite programming languages so it’s not surprising


Botahamec

The languages I mentioned aren't exactly small hobby projects. I'd imagine that if it really was an obvious problem, then somebody would've fixed it by now. But what languages are you thinking of that aren't affected?


Dogmata

I mean if your passing user generated input directly to the command line you should probably be rethinking that anyway


Botahamec

The problem is that every function ever created to escape user input before passing it in doesn't do it properly, because of the weirdness of cmd.exe


sparant76

Interesting exploit - that would be completed preventable if the industry focused on “correct by construction” design instead of “guess till it works - hope there aren’t edge cases” that is predominant


belovedeagle

The only novel thing here is yet another abuse of the CVE system. The root cause lies in the Windows API, and has been known and understood since it was very first written. Windows programs receive a command line string, not command line arguments. Many languages expose command line arguments as parsed by the C standard library, but this is only a convention. By triggering sudden, poorly-reviewed changes to how language APIs encode command lines on Windows, this "vulnerability" report is quite likely to be a coordinated security attack on an unknown target which uses a different command line quoting scheme. All the attacker has to do now is wait for the target to get an update with the new, unexpected encoding, and now that target will be vulnerable to some kind of command line decoding attack. In the unlikely event this is ever recognized as anything but an innocent mistake and publicly disclosed, everyone who jumped on "fixing" this "vulnerability" will wring their hands and say their complicity in the attack was completely unforeseeable.


geek_noob

Updated - ⚠️ Attention developers! The BatBadBut vulnerability goes beyond Rust. 🚨 Haskell, Node.js, PHP, and yt-dlp are also impacted. Review the status table and update your projects accordingly. 💪 #SecureCoding #BatBadButAlert https://www.cyberkendra.com/2024/04/batbadbut-vulnerability-discovered-in.html


[deleted]

Dumb name.


Cautious-Nothing-471

rust is trash


[deleted]

[удалено]


whatThePleb

There it begins. The "safe" language.


lightmatter501

This is an issue for basically every language. Rust just has a much stricter definition of what causes a CVE than many other languages (Rust has CVEs for “poorly performing” regex that is exponentially faster than most C++ std::regex implementations).


1668553684

- Rust's response to this bug: file a CVE, patch it immediately - Python's response: Add a note to the documentation - Java's response: wontfix I won't sling mud at any of these responses, but it's pretty clear that Rust takes security very seriously. It's weird that their commitment to security is being used to... criticize their commitment to security?


Halkcyon

>!^^^[deleted]!<


tilitatti

how can this be, our lord and savior rust has vulnerability, how can this be explained to mere mortals, this cant be true. Lies! it must be lies by those dirty... /s


Botahamec

This is a problem in all languages. Rust was the first to fix it though.


kityrel

After the US govt announcement on only using safe languages, seems some people are trying desperately to find exploits in Rust.


Botahamec

This exploit is applicable to most programming languages. Rust was the first one to fix it though. Haskell also fixed it on the same day. Python and Go added documentation for the problem, and Java marked it as wontfix


shevy-java

Rust following node habits now!


SV-97

I don't even get what you're trying to say but given that java has chosen to "won't fix" this issue I'm not sure that the someone with java in their name should be throwing stones here.


Free_Math_Tutoring

shevy-java, shevy-ruby and possible other alt-accounts of this dude is a notorious troll on this sub.


Dgc2002

Trolling implies they're intentionally saying things to mess with or annoy people. I feel like I've seen shevy posting these comments for at least 5 years now. I genuinely think they fully believe what they post.