cmd.exe executing PE files with non-executable extension #632

Closed
opened 2026-01-30 21:57:37 +00:00 by claunia · 4 comments
Owner

Originally created by @mitjakolsek on GitHub (Apr 23, 2019).

  • Your Windows build number: (Type ver at a Windows Command Prompt)
  • Microsoft Windows [Version 6.1.7601]
  • Microsoft Windows [Version 10.0.17134.706]
  • (likely all other Windows versions)
  • What you're doing and what's happening: (Copy & paste specific commands and their output, or include screen shots)
  1. Copy any PE .EXE file (e.g., net.exe from System32 folder) to any folder (e.g. c:\temp)
  2. Change the copied file's extension to "txt", i.e., rename net.exe to net.txt.
  3. Launch the Console (cmd.exe) and cd to c:\temp
  4. In the Console, type net.txt and press Enter
  5. Notice that net.txt was executed as the original net.exe executable
  • What's wrong / what should be happening instead:

Not claiming this is wrong as there are probably many historical reasons for the Console to behave this way but this could lead to security problems. According to Adam's analysis the Console first attempts to launch CreateProcess with the supplied arguments, and failing that, also tries ShellExecute, which understands file associations and, e.g., launches abc.txt in Notepad.

This execution logic allows a malicious PE file with a "non-executable" extension to be launched by cmd.exe as described in this blog post by Cylera where a PE/DCM polyglot file can be parsed as a DCM image, but at the same time launched as an executable by someone attempting to view the image from the Console (cd-ing to a folder with DCM files and "launching" image01.dcm). Such scenario doesn't seem too far-fetched as double-clicking the same DCM file in Explorer would actually open the image viewer.

As to what should be happening instead: again, there's surely a reason for the Console to first try CreateProcess (which also attempts to try different 10+ extensions such as .com, .exe, .bat, ... in trying very hard to find some matching executable). How about not calling CreateProcess on files without one of these known executable extensions? Perhaps combining that with a Registry flag for such omitting of the CreateProcess call and having the omitting enabled by default so that those whose apps would break could re-enable the CreateProcess call ? (I'm fully expecting this idea to be shot down by numerous sensible arguments :)

Thanks,
Mitja Kolsek

Originally created by @mitjakolsek on GitHub (Apr 23, 2019). * Your Windows build number: (Type `ver` at a Windows Command Prompt) - Microsoft Windows [Version 6.1.7601] - Microsoft Windows [Version 10.0.17134.706] - (likely all other Windows versions) * What you're doing and what's happening: (Copy & paste specific commands and their output, or include screen shots) 1) Copy any PE .EXE file (e.g., net.exe from System32 folder) to any folder (e.g. c:\temp) 2) Change the copied file's extension to "txt", i.e., rename net.exe to net.txt. 3) Launch the Console (cmd.exe) and cd to c:\temp 4) In the Console, type net.txt and press Enter 5) Notice that net.txt was executed as the original net.exe executable * What's wrong / what should be happening instead: Not claiming this is wrong as there are probably many historical reasons for the Console to behave this way but this could lead to security problems. According to [Adam's analysis](http://www.hexacorn.com/blog/2019/04/21/cmd-exe-running-any-file-no-matter-what-extension/) the Console first attempts to launch CreateProcess with the supplied arguments, and failing that, also tries ShellExecute, which understands file associations and, e.g., launches abc.txt in Notepad. This execution logic allows a malicious PE file with a "non-executable" extension to be launched by cmd.exe as described in [this blog post by Cylera](https://labs.cylera.com/2019/04/16/pe-dicom-medical-malware/) where a PE/DCM polyglot file can be parsed as a DCM image, but at the same time launched as an executable by someone attempting to view the image from the Console (cd-ing to a folder with DCM files and "launching" image01.dcm). Such scenario doesn't seem too far-fetched as double-clicking the same DCM file in Explorer would actually open the image viewer. As to what should be happening instead: again, there's surely a reason for the Console to first try CreateProcess (which also attempts to try different 10+ extensions such as .com, .exe, .bat, ... in trying very hard to find some matching executable). How about *not* calling CreateProcess on files *without* one of these known executable extensions? Perhaps combining that with a Registry flag for such omitting of the CreateProcess call and having the omitting enabled by default so that those whose apps would break could re-enable the CreateProcess call ? (I'm fully expecting this idea to be shot down by numerous sensible arguments :) Thanks, Mitja Kolsek
claunia added the Issue-FeatureResolution-By-DesignArea-InteropProduct-Cmd.exe labels 2026-01-30 21:57:37 +00:00
Author
Owner

@miniksa commented on GitHub (Apr 23, 2019):

I love the idea and the write up, but I'm pretty sure we're still not going to be able to do anything about it.

It is an exploit in that it is trickery that can cause a user to run something they didn't intend, but the same thing really goes if you renamed your file to a name that the user is inclined to trust and placed it in their view hoping they would click on it. The tricky hiding binary would still be exected with the same user token and privileges being processed as net.txt as if you named it something more convincing like excel.exe and placed it on the user's desktop. There's a lot of tricky things you can do to convince a user to click on or execute something as their own token. This just happens to be one of many. I've sent files to my coworkers as fun.notavirus before.

An example of something we'd really be looking for in terms of an exploit that could be serviceable would be an elevation of privilege type attack where the user is tricked into running something as their standard user, but it somehow manages to jump into an administrative or system context via cmd.exe and have privileges above and beyond what would normally be authorized.

Given that there's probably some large company out there that has spent years exploiting the fact that this works to run their oil rigs, manufacturing lines, or enterprise network... we have a propensity to not make a change in cmd.exe unless it's super justified.

Additionally... the entire world of *NIX operating systems gets away with letting just about any file be executable with any extension. Sure *NIX have the r/w/x permissions by default, but Windows has ACLs that can be sufficiently used to lock down the same sort of behavior if necessary.

We also offer administrators who are paranoid about this sort of thing the ability to lock down the usage of cmd.exe at all by regular users through several methods in policies and app blocking mechanisms.

All-in-all, cmd.exe is a powerful, legacy tool. Consider it like a table saw from several decades ago before they added the guards around the spinning blade and the "drops the blade when it senses your finger is too close" feature. There's no one really who is going to go retrofit those features onto your old saw because it's cost prohibitive. You have to go buy a new one and stop people from using the old, unsafe one. Microsoft's newer saw is PowerShell. Fortunately it's free, but its cost is migrating scripts and education on how it works differently.

@miniksa commented on GitHub (Apr 23, 2019): I love the idea and the write up, but I'm pretty sure we're still not going to be able to do anything about it. It is an exploit in that it is trickery that can cause a user to run something they didn't intend, but the same thing really goes if you renamed your file to a name that the user is inclined to trust and placed it in their view hoping they would click on it. The tricky hiding binary would still be exected with the same user token and privileges being processed as `net.txt` as if you named it something more convincing like `excel.exe` and placed it on the user's desktop. There's a lot of tricky things you can do to convince a user to click on or execute something as their own token. This just happens to be one of many. I've sent files to my coworkers as `fun.notavirus` before. An example of something we'd really be looking for in terms of an exploit that could be serviceable would be an elevation of privilege type attack where the user is tricked into running something as their standard user, but it somehow manages to jump into an administrative or system context via `cmd.exe` and have privileges above and beyond what would normally be authorized. Given that there's probably *some* large company out there that has spent years exploiting the fact that this works to run their oil rigs, manufacturing lines, or enterprise network... we have a propensity to not make a change in `cmd.exe` unless it's super justified. Additionally... the entire world of *NIX operating systems gets away with letting just about any file be executable with any extension. Sure *NIX have the r/w/x permissions by default, but Windows has ACLs that can be sufficiently used to lock down the same sort of behavior if necessary. We also offer administrators who are paranoid about this sort of thing the ability to lock down the usage of `cmd.exe` at all by regular users through several methods in policies and app blocking mechanisms. All-in-all, `cmd.exe` is a powerful, legacy tool. Consider it like a table saw from several decades ago before they added the guards around the spinning blade and the "drops the blade when it senses your finger is too close" feature. There's no one really who is going to go retrofit those features onto your old saw because it's cost prohibitive. You have to go buy a new one and stop people from using the old, unsafe one. Microsoft's newer saw is PowerShell. Fortunately it's free, but its cost is migrating scripts and education on how it works differently.
Author
Owner

@eryksun commented on GitHub (Apr 23, 2019):

As to what should be happening instead: again, there's surely a reason for the Console to first try CreateProcess (which also attempts to try different 10+ extensions such as .com, .exe, .bat, ... in trying very hard to find some matching executable).

When you say "console", you mean the CMD shell, which could have its standard I/O connected to anything, including but not limited to a standard console.

Note that CMD does not try CreateProcessW on every potential file extension and every potential directory in the search PATH until either a match is successfully executed or the search is exhausted. Such an exhaustive search is more like what a Unix shell does. Instead, if you enter chcp, what CMD does is search every directory in PATH for "chcp" plus every extension in PATHEXT until it finds a match, which can even be "chcp" itself if "." is in PATHEXT. It tries to execute only this single matching file. If CreateProcessW fails with one of a few failure codes (e.g. ERROR_BAD_EXE_FORMAT or ERROR_ELEVATION_REQUIRED), it tries to execute the file via ShellExecuteExW. Notably it does not try the shell API for ERROR_ACCESS_DENIED. That's good since ShellExecuteExW doesn't check file security and never will, unless we get a ShellExecuteExExW. Thus by checking CreateProcessW first, CMD always abides whether the file security allows the current user to execute the file.

Disappointingly, in contrast to CMD, PowerShell does not honor the granted or denied execute access for scripts.

@eryksun commented on GitHub (Apr 23, 2019): > As to what should be happening instead: again, there's surely a reason for the Console to first try CreateProcess (which also attempts to try different 10+ extensions such as .com, .exe, .bat, ... in trying very hard to find some matching executable). When you say "console", you mean the CMD shell, which could have its standard I/O connected to anything, including but not limited to a standard console. Note that CMD does not try `CreateProcessW` on every potential file extension and every potential directory in the search `PATH` until either a match is successfully executed or the search is exhausted. Such an exhaustive search is more like what a Unix shell does. Instead, if you enter `chcp`, what CMD does is search every directory in `PATH` for "chcp" plus every extension in `PATHEXT` until it finds a match, which can even be "chcp" itself if "." is in `PATHEXT`. It tries to execute only this single matching file. If `CreateProcessW` fails with one of a few failure codes (e.g. `ERROR_BAD_EXE_FORMAT` or `ERROR_ELEVATION_REQUIRED`), it tries to execute the file via `ShellExecuteExW`. Notably it does not try the shell API for `ERROR_ACCESS_DENIED`. That's good since `ShellExecuteExW` doesn't check file security and never will, unless we get a `ShellExecuteExExW`. Thus by checking `CreateProcessW` first, CMD always abides whether the file security allows the current user to execute the file. Disappointingly, in contrast to CMD, PowerShell does not honor the granted or denied execute access for scripts.
Author
Owner

@mitjakolsek commented on GitHub (May 13, 2019):

Thanks @miniksa and @eryksun for your feedback!

@mitjakolsek commented on GitHub (May 13, 2019): Thanks @miniksa and @eryksun for your feedback!
Author
Owner

@miniksa commented on GitHub (May 18, 2019):

Not going to be able to do anything about this. Tagging it up and closing.

@miniksa commented on GitHub (May 18, 2019): Not going to be able to do anything about this. Tagging it up and closing.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#632