Lord777
Professional
- Messages
- 2,579
- Reaction score
- 1,504
- Points
- 113
As part of the development of his pentester activity, he became interested in such an area as ATM security. As everyone probably knows, in most cases, some modern ATMs are running certain versions of Windows OS: from XP to 10 (including Embedded / IoT editions). The OS runs a certain set of banking applications, and also implements additional security measures, such as Application Control. This post will be about one of the ways to bypass this protection.
There are a large number of ways to bypass the control of running applications, and their applicability / non-applicability depends on the correctness of the configuration and the tools used. Before I list the main workarounds, I will list the main features that are used to control the legitimacy of the application being launched:
- full / partial path to the application file or directory;
- file checksum (MD5, SHA-1, etc.);
- cryptographic signature of the file.
The above methods are used in combination with whitelisting / blacklisting applications, as well as extensions that are available to run. Now let's move on to the workarounds:
- execution in the context of trusted applications (cmd, NTVDM, etc.) / interpreters (Java, PHP, etc.);
- hash function collisions;
- DLL hijacking.
You can also note bypassing the blacklist of extensions (rare extensions that not everyone remembers about, like .scr,. com) and the use of vulnerabilities in the protecting products themselves (not AppLocker is the same) / in installed software. You can learn more about the above things from thematic reports from various conferences or contact yarbabin, as the author of one of the materials on the topic.
Let's get back to the point of the article: let's take a closer look at the bypass method through execution in the context of a trusted application, and more specifically - NTVDM. In the context of NTVDM in modern x86 versions of Windows (and in an abnormal way in x64 - https://github.com/leecher1337/ntvdmx64) runs 16-bit applications.
If you think that 16-bit applications are all about interrupts, assembler, and primitive MS-DOS operations, then this is not true. In the days of Windows 3.11 and later, it was possible to create 16-bit applications using WinAPI, and from such an application, no one bothers to download a 32-bit dynamic library that will execute arbitrary code developed in a familiar environment for a modern developer. This is a trivial and relatively well-known workaround.
Below I will give an example code for the old Microsoft Visual C 1.52 development environment (the latest version that allowed you to build 16-bit files, according to the Wiki) and implement the task described above.
So, we will need: a Windows 95 boot floppydisk, a Windows 95 image, and Microsoft Visual C 1.52 c. After installing the OS and development environment on the VM, launch the environment and copy the following code there:
The code is quite primitive: we simply call standard, but not very well-known modifications of methods LoadLibraryand FreeLibraryfor 32-bit applications from 16-bit, and also use a macro DECLARE_HANDLE32. What is it like? Yes, in general, nothing special:
A standard legacy macro that is only familiar to bearded programmers. By the way, you may ask why I call FreeLibrary32W at the end of the code, although it would seem that after the process is completed, the dynamic library will be unloaded anyway - by no means. In this case, everything works a little differently. After running the above code, the library is loaded in the context of the process ntvdm.exe however, after the job is completed, it is not unloaded.
Most likely, this is due either to the fact that the developers did not want to bother, or to the organization of system memory in older versions of Windows, which existed up to Windows NT, authentic emulation so to speak.
Now let's compile our application and check its performance. To do this, simply select Options - >Project-> > QuickWin application (. EXE) from the development environment menu, as well as Build Mode-Release.
After that, press Shift+F8 or through the Project->Build ***menu. The QuickWin application format was chosen because of its simplicity and lack of need to create a project, although it adds a solid overhead for those times: the resulting file was ~ 43 KB in size.
Transfer the resulting file to the target system and try to run it by specifying as an argument the name of a 32-bit dynamic library located in the same directory as the file being run (you can take the DLL that outputs Hello World from here or build it yourself).
The expected result is obtained, the DLL was loaded into the process ntvdm.exe, and a process with the name of our executable file (by the way, you can change the file extension, for example, to .com) was technically never created. Success.
There are a large number of ways to bypass the control of running applications, and their applicability / non-applicability depends on the correctness of the configuration and the tools used. Before I list the main workarounds, I will list the main features that are used to control the legitimacy of the application being launched:
- full / partial path to the application file or directory;
- file checksum (MD5, SHA-1, etc.);
- cryptographic signature of the file.
The above methods are used in combination with whitelisting / blacklisting applications, as well as extensions that are available to run. Now let's move on to the workarounds:
- execution in the context of trusted applications (cmd, NTVDM, etc.) / interpreters (Java, PHP, etc.);
- hash function collisions;
- DLL hijacking.
You can also note bypassing the blacklist of extensions (rare extensions that not everyone remembers about, like .scr,. com) and the use of vulnerabilities in the protecting products themselves (not AppLocker is the same) / in installed software. You can learn more about the above things from thematic reports from various conferences or contact yarbabin, as the author of one of the materials on the topic.
Let's get back to the point of the article: let's take a closer look at the bypass method through execution in the context of a trusted application, and more specifically - NTVDM. In the context of NTVDM in modern x86 versions of Windows (and in an abnormal way in x64 - https://github.com/leecher1337/ntvdmx64) runs 16-bit applications.
If you think that 16-bit applications are all about interrupts, assembler, and primitive MS-DOS operations, then this is not true. In the days of Windows 3.11 and later, it was possible to create 16-bit applications using WinAPI, and from such an application, no one bothers to download a 32-bit dynamic library that will execute arbitrary code developed in a familiar environment for a modern developer. This is a trivial and relatively well-known workaround.
Below I will give an example code for the old Microsoft Visual C 1.52 development environment (the latest version that allowed you to build 16-bit files, according to the Wiki) and implement the task described above.
So, we will need: a Windows 95 boot floppydisk, a Windows 95 image, and Microsoft Visual C 1.52 c. After installing the OS and development environment on the VM, launch the environment and copy the following code there:
Code:
#include <Windows.h> DECLARE_HANDLE32(HPROC32); DECLARE_HANDLE32(HINSTANCE32); int main(int argc, char** argv) { HMODULE hModule; HINSTANCE32 hDll; HINSTANCE32 (WINAPI *LoadLibraryEx32W) (LPCSTR, DWORD, DWORD); BOOL (WINAPI *FreeLibrary32W) (HINSTANCE32); printf("begin" "\n"); if(argc != 2) { printf("Usage: loader.exe my.dll" "\n"); return 1; } hModule = GetModuleHandle("KERNEL"); if(!hModule) { printf("GetModuleHandle - %08X" "\n", hModule); return 1; } (FARPROC) LoadLibraryEx32W = GetProcAddress(hModule, "LoadLibraryEx32W"); (FARPROC) FreeLibrary32W = GetProcAddress(hModule, "FreeLibrary32W"); if(!LoadLibraryEx32W || !FreeLibrary32W) { printf("GetProcAddress - %08X, %08X" "\n", LoadLibraryEx32W,FreeLibrary32W); return 1; } hDll = LoadLibraryEx32W(argv[1], 0, 0); if(!hDll) { printf("LoadLibraryEx32W - %08X" "\n", hDll); return 1; } getchar(); FreeLibrary32W(hDll); printf("end" "\n"); return 0; }
The code is quite primitive: we simply call standard, but not very well-known modifications of methods LoadLibraryand FreeLibraryfor 32-bit applications from 16-bit, and also use a macro DECLARE_HANDLE32. What is it like? Yes, in general, nothing special:
Code:
#ifdef STRICT
#define DECLARE_HANDLE32(name) struct name##__ { int unused; }; \
typedef const struct name##__ _far* name
#else /* STRICT */
#define DECLARE_HANDLE32(name) typedef DWORD name
#endif /* !STRICT */
#endif /* !DECLARE_HANDLE32 */
A standard legacy macro that is only familiar to bearded programmers. By the way, you may ask why I call FreeLibrary32W at the end of the code, although it would seem that after the process is completed, the dynamic library will be unloaded anyway - by no means. In this case, everything works a little differently. After running the above code, the library is loaded in the context of the process ntvdm.exe however, after the job is completed, it is not unloaded.

Most likely, this is due either to the fact that the developers did not want to bother, or to the organization of system memory in older versions of Windows, which existed up to Windows NT, authentic emulation so to speak.
Now let's compile our application and check its performance. To do this, simply select Options - >Project-> > QuickWin application (. EXE) from the development environment menu, as well as Build Mode-Release.

After that, press Shift+F8 or through the Project->Build ***menu. The QuickWin application format was chosen because of its simplicity and lack of need to create a project, although it adds a solid overhead for those times: the resulting file was ~ 43 KB in size.
Transfer the resulting file to the target system and try to run it by specifying as an argument the name of a 32-bit dynamic library located in the same directory as the file being run (you can take the DLL that outputs Hello World from here or build it yourself).

The expected result is obtained, the DLL was loaded into the process ntvdm.exe, and a process with the name of our executable file (by the way, you can change the file extension, for example, to .com) was technically never created. Success.