Batch Everywhere

How to Execute Shell Commands or Open a Shell Inside a Surrogate File

After reading the article How to launch Command Prompt and PowerShell from MS Paint, about how to launch a cmd/PowerShell interpreter from a BMP file created using MS Paint, with the conditions that the file is saved as a 24-bit Bitmap type (.bmp extension), and the file name’s extension is later changed to .bat, it got my attention to first, replicate the steps outlined in the article, and second, to confirm the expected behaviour, that’s, a cmd prompt will open on the system right after I execute the specially crafted BMP image file.

Its core idea is to create a BMP image of 6 pixels and colour each pixel with a specific RGB colour value. The file size is 74 bytes, attached here for reference. Following the steps outlined in the article to launch “cmd.exe”, we get the following image, zoomed in at 5000% the size of the original image:

Graph-1: Specially crafted BMP image zoomed in at 5000%

Each of the pixels contains the following RGB values, from left to right (use the Pencil tool and not the Fill with color tool to color each of the pixels):

Table-1: Windows Command Prompt Pixels RGB Values

Each of the RGB cells in the table shown above contains the values as entered in decimal in MS Paint, followed by the hexadecimal representation, and finally the ASCII equivalent. The ASCII representation for each of those values should already give you an idea about what’s happening. These values map into the BMP file structure as one BITMAPLINE line of 6 RGBTRIPLE color structures, where each RGBTRIPLE color structure holds the RGB value for each of the specially crafted pixels. Table-1 can be read starting with pixel/row-1, from right to left, and onward, down to pixel/row-6.

The following hex dump shows the structure of the specially crafted BMP file shown in figure-1.

0000h  42 4D 4A 00 00 00 00 00 00 00 36 00 00 00 28 00  BMJ…….6…(. 
0010h  00 00 06 00 00 00 01 00 00 00 01 00 18 00 00 00  ……………. 
0020h  00 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00  ……………. 
0030h  00 00 00 00 00 00 00 00 0A 0D 0A 0D 63 6D 64 2E  …………cmd. 
0040h  65 78 65 00 00 00 00 00 00 00                    exe…….

The bytes highlighted in green and underscored are the pixels’ RGB values in hexadecimal. They are the BITMAPLINE line structure of 6 RGBTRIPLE color structures. You can take the same hexdump and save it as binary using your favorite hex editor. Changing the BMP file extension from .bmp to .bat, and executing the file, a cmd shell opens with the following prompts:

C:\Users\usadmin\Desktop\cmd_playground>BMJ
‘BMJ’ is not recognized as an internal or external command,
operable program or batch file.

C:\Users\usadmin\Desktop\cmd_playground>cmd.exe
Microsoft Windows [Version 10.0.19045.2604]
(c) Microsoft Corporation. All rights reserved.

C:\Users\usadmin\Desktop\cmd_playground>

<bmp_file.bat>

First, the Windows Command Processor “cmd.exe” is the utility responsible for interpreting batch commands. It reads strings only and not binary data, therefore, whatever binary data is in the file, is skipped. As evidenced in the prompt output shown above, first, it attempts to execute the string “BMJ” as either an internal (for example, IF, FOR, REM, DIR, ERASE, DEL, CLS…) or external command (CMD, COMP, MORE, SORT…), operable program or batch file, but fails to do so. Finally, it lands on the hardcoded string “cmd.exe“, which is properly delimited, because the processor reads a batch file’s content line-by-line, and thereafter executes it as an external program. The reason why it is able to execute it successfully is that internally, the starting “cmd.exe” process would go through the list of environment variables defined on your system, searching for executables, extensions, and paths, among other things, and in this case, it finds that the executable “cmd.exe” is defined by the environment variable “Path“, which holds the value “%SystemRoot%\system32“, which points to the path where the “cmd.exe” resides.

Under the Hood

If you look under the hood of how the Windows Command Processor “cmd.exe” works, you’ll realize the following key points:

– You do not need any of the laborious techniques documented publicly to achieve the same results.

– It works with any file format, for example, jpeg, exe, pcap, png, dll, zip, rar,… (with some edge cases) as long as the first byte in the file is not 0x00 and the batch command or the native command to be executed follows either of these regex patterns:

<anything>(\r\n\r\n|\n\r\n\r)[,;=@%^”]?<command to be executed>(\x00|\x0a|\x0d|<other_allowed_chars>)
Or If it is at the beginning of the file, offset 0x00, then, no need for any delimiter.
Or, in certain cases
<anything>\r\n\r\n[,;=@%^”]?<powershell.exe>(\x00|\x0a|\x0d|<other_allowed_chars>) 

You simply open a sample file of whatever format type you’re targeting with a hex editor and edit it from there. There is no restriction on where it is located. Another tidbit is that if you start the file with 0x0a|0x1a, you avoid executing unrecognized commands. Additionally, no need for the extension “.exe”, “cmd” is enough to spawn a shell, why, because the extension “.exe” is defined by the system environment variable “PATHEXT”, for the external command “CMD”.

It is important to note that other than at the beginning (offset 0x00) of the file, if there is an “empty” sequence of “\r\n” in the binary, meaning it is not followed by an acceptable character, then the script will bail out at this occurrence, even if there are valid sequences later in the file that executes shell commands.

Reverse engineering cmd.exe shows that you could hook the function DumpParseTree() to print out parsed commands tree information. This function is supposed to be only available in the debug version, however, the implementation is available in the release version as well, but inactive. To activate it, patch the flag cs:uchar fDumpParse by changing its value to 0x1 to dump such a tree, against every command being executed. This flag is set inside the function struct node * Parser(unsigned int, __int64, int). Moreover, setting the flag unsigned char fDumpTokens to 0x1 enables dumping the getting and ungetting of tokens. The flags and function names are available from the PDB debug information file.

Security Policy

If the “Prevent access to the command prompt” Group Policy is enabled, then you won’t be able to open cmd.exe, but you could still execute whatever batch commands, as long as the option “Disable the command prompt script processing also?” is set to “No”.

Even if you set the policy “Don’t run specified Windows applications” to disable the execution of “powershell.exe”, you could still get it to execute from the batch file as long as it is not started by the Windows Explorer process.

Moreover, when the cmd interpreter is started, it checks the Registry for the key: “\HCU\SOFTWARE\Policies\Microsoft\Windows\System\DisableCMD” such that if the value is set to ‘1’, it bails out. By default, when the policy “Prevent access to the command prompt” is enabled, the key “DisableCMD” is set to ‘2’. It is set to ‘1’ only when the option “Disable the command prompt script processing also?” is set to “Yes”. This opens the door to BYO patched cmd interpreter to bypass such a restriction.

End

The take away from this is that it has nothing to do with a specific file format type, the “cmd.exe” processor simply treats it like any file, with the exception that the file is binary and not text.

That’s it for now. If you have any suggestions or questions, please leave them in the comment section below.

Mohamad Mokbel
March 05, 2023

One thought on “Batch Everywhere

  1. Great analysis , thanks for sharing… wondering what are the preventative measures against this threat..

Leave a Reply

Your email address will not be published. Required fields are marked *