Movies have narrowed down the vision of security in digital world. Majority non technical population and a good portion of technical, feel that security breach is not critical until it is an attacker controlling our system. Although it is true that RCE and unauthorized control is considered the most undesirable situations but it is also not false that other security compromises are unbearable. Anything that falls under CIA triad is addressed as critical. Unavailability falls under one of the wings of CIA. In this writeup, I will address how I managed to make my host operating system give up and make itself unresponsive to the user.
Windows operating system uses the concept of threads and processes in a very systematic manner. Additionally, there are various communications and procedure calls that act as daemons; like Remote Procedure Calls and Inter Process Communication. One such feature that Windows provides is Asynchronous Procedure Calls, which are supposed to perform operating system actions asynchronously. APCs are never run directly. They are scheduled in APC Queue. These APCs are serviced by threads that are in alertable state. Alertable state can never be enforced. A thread voluntarily chooses to enter this state. It does so by calling an Ex Windows call like SleepEx or WaitForSingleObjectEx with the bAlertable flag set.
This thread after entering alertable state, sleeps until there is an APC in the APC Queue to serve. Once it finds an APC to serve, that is when APC is really run. Until this point, APC is just scheduled in a queue, analogous to processes waiting in Ready Queue. The important point here is that if the APC Queue is empty, the thread is blocked. This means, it consumes resources but does nothing in favour of CPU. This thin gap can be abused to make operating system’s multiprogramming feature its own enemy. The biggest advantage of operating system leads to its failure.
I wrote a program that uses WINAPI and it spawns threads up to maximum limit, each consuming huge stack. I ensured that User APC Queue must be empty all the time. After its maximum limit, the program takes a halt, so I can responsibly terminate it and recover my system from undesirable state. The threads stayed blocked and the stack kept expanding linearly with time. Eventually, the resources were consumed to a good extent that paging started failing. Multiprogramming is a success due to demand paging. Since the resources were held static, other processes experienced exponential growth in page faults, leading to increased thrashing. Disks work in milliseconds, whereas main memory works in the nanoseconds range. This means frequent swaps results in average access time of page in milliseconds, making the system up to 10⁶ times slower.
I ran this program on my hardware directly, so I don’t introduce anymore syscall and ABI translations; although there were a little underlying WINAPI usage. After running my program, it took not more than 1 minute to hang. My system started lagging, and eventually I started facing screen blackouts. By the time I realized I should stop the program, multiple processes crashed (including the program itself). A small program can make a user not efficiently use his system (unavailability threat vector).
The attack can be escalated by an already residing payload or a dropper to drop multiple compiled versions of same program, ensuring they all run at different addresses. It can be made brutal by adding them to Windows Startups folder, making the user and operating system not even launch the core applications. The demonstration is undoubtedly hazardous and must be done with utmost care and with responsibility. This is an educational post and must not be implemented to affect others.
Top comments (0)