2000-style fuzzing on modern Windows 10 applications
Fig. 1. Bruised, but not broken. The Windows calculator, whose code was recently published on Github , turned out to be one of two tested applications that did not hang and did not fall in opposition to the fuzzer of window messages developed in 2000. The window size has been specially enlarged to show fuzzing artifacts.
It is time for the second part of our efforts to test ancient fuzzing methods on modern systems. If you missed, here is the first part . This time, we will try Windows 10 fuzzing techniques from the article “Empirical Investigation of the Reliability of Windows NT Applications Using Random Testing” (aka “NT Fuzzing Report”) by Justin Forrester and Barton Miller, published in 2000.
Researchers tested 33 applications of Windows NT and an earlier version of Windows 2000 for susceptibility to distorted window messages and random mouse and keyboard events. Since Dr. Miller published the fuzzer code, we used exactly the same tools as the original authors to look for bugs in modern Windows applications.
The results are almost identical: 19 years ago, 100% of the tested applications crashed or crashed when they encountered distorted window messages. Today, the same fuzzer dropped or hung 93% of the tested applications. Only two stood, including our old friend Calculator (Fig. 1). We also found a bug (but not a security issue) on Windows.
A brief introduction to Windows
So what are window messages and why do they cause a program to crash?
Windows GUI applications are event-driven: mouse movements, button presses, keystrokes, etc. An event-driven application will do nothing until it receives an event. Once an event is received, the application performs the action based on the event, and then expects other events. Sounds familiar? This architecture has received a second life in platforms such as node.js .
Window messages are a Windows event notification method . Each of them has a numeric code associated with a specific event . Each message has one or more parameters, which by convention is called lParam and wParam. They define more detailed information about the event. Examples of such information are the coordinates of the movement of the mouse, which key is pressed or which text to display in the window. These messages can be sent by the program itself, the operating system, or other programs. They can arrive at any time and in any order and must be processed by the application on the receiving side.
Prior to Windows Vista, a low-privilege process could send a message to a high-privileged process. Using the right combination of messages, you can execute code in that process. In Vista, these “subversive attacks” were largely protected by UIPI and by isolating system services in a separate session.
Incorrect window message processing is unlikely to affect the security of modern Windows systems for two reasons. First, window messages cannot be sent over the network. Secondly, crashing an application or executing code at the same privilege level is not very useful for an attacker. Probably, it was obvious to the authors of the NT fuzzing report. They do not make safety statements, but correctly point out that failures in processing window messages imply a lack of rigorous testing.
There are some areas where executing code with the same privileges can compromise security. Some applications combine various security primitives to create an artificial privilege level that was not originally found in the operating system. A typical example is a sandbox for rendering in a browser. Browser manufacturers are well aware of these issues and have taken steps to address them . Another example is antivirus products. There, the control panel works with normal privileges, but is isolated from other anti-virus modules.
To fuzz all the applications in the test suite, we used the same core code and fuzzing technique described in the initial NT report. In particular, in both SendMessage and PostMessage modes, fazzer used three iterations of 500,000 messages with 42 seeds and three iterations of 500,000 messages with 1,337 seeds. The results appeared after performing only one iteration of each method.
We missed random mouse and keyboard input due to time constraints and a desire to focus solely on window messages. We also encourage those who wish to repeat testing and confirm the results.
For fuzzer in Windows 10 had to make two minor changes. First, adapt it for a 64-bit platform. The second change allowed fuzzer to select a specific window handle using the command line argument. Fuzzing a specific descriptor is a quick fix to the fuzzing of Universal Windows Platform (UWP) applications . The original program is focused on fuzzing windows that belong to a certain process, but all UWP applications display their user interface through the same process (Fig. 2). This means that the fuzzer cannot be directed to the main UWP application window.
Fig. 2. On the UWP platform, all applications belong to one process (
ApplicationFrameHost.exe) Fuzzing for these applications had to change the original fazzer NT and direct it to a specific window handles
When modifying fazzera manifested serious drawback: the values chosen for the two major sources of randomized input arguments
PostMessage, limited to 16-bit integers. Both arguments are 32-bit on 32-bit Windows and 64-bit on 64-bit Windows. The problem arises in
Fuzz.cppwhere the values are set
wParam = (UINT) rand(); lParam = (LONG) rand();
The rand () function returns a number in the range [0, 2 16 ], which greatly limits the set of tested values. We intentionally saved this error during testing so that the results are accurately matched with the original work.
In the original NT report, 33 programs were tested. We only have 28, because only one version of each program is used for testing. The Windows software ecosystem has changed significantly since 2000, although surprisingly much remains unchanged. The Microsoft Office suite contains the same programs as in the original tests. Netscape Communicator has evolved into Firefox. Adobe Acrobat has been renamed Adobe Reader, but is still valid. Even Winamp released a new release in 2018, which allows a fair comparison with the original report. However, some obsolete programs had to be replaced. See below for a list of changes and reasons for them:
- CD Player ⇨ Windows Media Player: CD Player functionality is included in the new program.
- Eudora ⇨ Windows Mail: Qualcomm is now dealing with chips rather than email clients. Since Eudora no longer exists, the default Windows mail client has been tested instead.
- Command AntiVirus ⇨ Avast Free Edition: Command AntiVirus is no longer available. It has been replaced by Avast as the most popular third-party antivirus.
- GSView ⇨ Photos: GSView is no longer supported. It was replaced with the default Windows photo viewer.
- JavaWorkshop Net NetBeans IDE: The JavaWorkshop IDE is no longer supported. NetBeans seems like a good free alternative that matches the spirit of what needs to be checked.
- Secure CRT ⇨ BitVise SSH: Secure CRT still exists, but a very long web form is required to download the trial version. BitVise SSH offered a quick boot.
- Telnet ⇨ Putty: The telnet application still exists on Windows, but now it is a console application. For fuzzing the GUI, we replaced it with Putty, the popular open source terminal emulator for Windows.
- We found Freecell and Solitaire in the Microsoft Solitaire Collection from the Windows App Store application catalog.
The specific version of the application is displayed in the result table. All fuzzing was carried out on a 64-bit system Windows 10 Pro version 1809 (build 17763.253).
As mentioned in the original report, the results should not be seen as security vulnerabilities, but as an indicator of the reliability and quality of software.
“Finally, our results form a quantitative starting point from which to judge the relative improvement in software reliability.”
- From the “Empirical Study of Windows NT Application Reliability Using Random Testing” by Justin Forrester and Barton Miller
The numbers are not particularly encouraging, although the situation is improving. In the initial NT report, all applications crashed or hung on fuzzing. Now two programs: the calculator and Avast Antivirus, survived the phasing of window messages without any negative consequences. We praise the Avast and Windows Calculator teams for their approach to erroneous window messages. The Calculator team has earned additional respect for opening the source code and demonstrating how to create a high-quality UWP application. See table 1 for all fuzzing results, together with the specific version of software used.
Table 1. Results of playing the original fuzzing on Windows 10. After 19 years, almost all applications still do not correctly handle distorted window messages
|Adobe Reader DC||2019.010.20098||glitch||ok|
|Windows Media Player||12.0.17763.292||glitch||glitch|
|Visual studio code||1.30.2||glitch||ok|
|Paint Shop Pro 2019||21.1||glitch||glitch|
|VS Community 2017||15.9.5||glitch||glitch|
|WinAmp 5.8||5.8 Build 3660||glitch||ok|
Unfortunately, curiosity prevailed, and we had to make one exception. It seemed that several unrelated applications were struck by one common problem. Debugging showed that the problem is with the message
WM_DEVICECHANGE. When the fuzzer sent this message, even the simplest application crashed - HelloWorld, the official example of the Windows API (Fig. 3).
Fig. 3. 32-bit HelloWorld.exe crashes when receiving a window message from fuzzer. This should not happen, as the program is completely simple. It is understood that the problem is somewhere in Windows.
After the fall of HelloWorld, we immediately realized that the problem affects only 32-bit applications, but not 64-bit ones. Some quick debugging showed that a crash was occurring inwow64win.dll, a 32-bit application compatibility layer for 64-bit . My superficial (and possibly incorrect) analysis of the problem allows me to conclude that the function
wow64win.dll!whcbfnINDEVICECHANGEregards wParam as a pointer to a structure
DEV_BROADCAST_HANDLE64in the target program. The function converts this structure into a structure
DEV_BROADCAST_HANDLE32for compatibility with 32-bit applications. The failure occurs due to the fact that the value
wParamgenerated by the fuzzer indicates an invalid memory.
wParambeing a local pointer is a bad idea, although it was probably a deliberate design decision for removable device notifications to work with legacy 32-bit Windows applications. But it’s still wrong that you can crash another application without any problems. We reported the issue to MSRC, although the security boundary did not cross. They confirmed that the error was not a security issue. We hope to see a fix for this generally accepted strange problem in a future version of Windows.
Window messages are underestimated and often ignored as unreliable input to Windows programs. Even 19 years after the first fuzzer of open-source window messages appeared, 93% of the tested applications still freeze or crash when the same program starts. But it is encouraging that some applications gracefully cope with these distorted inputs: this means that some organizations have frameworks and institutional knowledge to avoid such errors.
Of course, fuzzer can be improved in many ways, but even the simplest method crashed 93% of applications. Perhaps in some cases window messages even cross the real security frontier. If you explore this area, we hope you share the findings.