Shortly after Putin launched his “special military operation” in Ukraine on February 24th, 2022, researchers from ESET published information about two novel destructive malware families – HermeticWiper and ISAACWiper. HermeticWiper was part of a three-pronged campaign that included a worm and pseudo-ransomware component known as HermeticWizard and HermeticRansom, respectively. HermeticWiper is the data-wiping component.
ISAACWiper, on the other hand, was a relatively simple wiper, and some samples included debug strings exposing its capabilities to researchers. Although these two wipers significantly differed in implementation, they are both attributed to the Russian GRU. Specifically, the Sandworm team. ESET researchers discovered these wipers on the networks of Ukrainian organizations the night before the conflict started as part of a coordinated hybrid attack. A hybrid attack, in this sense, is a cyber attack synchronized with a physical attack. This post will only focus on the cyber aspects.
ISAACWiper gets its name from ESET researchers who discovered the malware and named it after one of the pseudorandom number generators (PRNG) it used – Indirection, Shift, Accumulate, Add, and Count (ISSAC). However, a few days later, they updated their publication to state that ISAACWiper did not use the ISAAC PRNG. Instead, it used the Mersenne Twister PRNG. Still, the name ISAACWiper stuck. However, Microsoft calls it LasainWiper or Lasainraw, but it’s unclear why.
WatchGuard Threat Lab and Panda Labs sought to contribute to ESET’s research by deep diving into one of the less-analyzed wipers – ISAACWiper. We performed this research as part of additional research on novel wipers discovered since the inception of the Russia-Ukraine conflict, and this was one of the results.
- PE Studio
- Detect it Easy (DiE)
- RDG Packer Detector
- Professional PE file Explorer (PPEE) (Puppy)
- Many Microsoft documentation lookups
The picture below shows the file details from PE Studio. This reveals a myriad of information about the sample:
- The file is a DLL
- It is a 32-bit Portable Executable (PE32)
- It was compiled on February 25th, 2022. The same day it was discovered.
- It was compiled in debugger mode. The code contains debug strings, as you will see later.
- The file has a somewhat high entropy indicating it might be packed.
Detect it Easy (DiE) shows that the .text section, which houses executable code, is packed.
Peeking at the file in RDG Packer Detector reveals that the sample uses aPLib compression. There also exists the presence of the isDebuggerPresent API, an easy-to-bypass anti-debugging technique often employed by malware authors and software programmers alike. Luckily, neither the isDebuggerPresent API nor aPLib compression hinders the analysis much.
Looking at the library imports reveals more of the intended behavior of ISAACWiper. Pivoting back to PE Studio, we can see two imported DLLs – Kernel32.dll and User32.dll. The Kernel32 DLL provides applications access to kernel-level operations within Windows, such as Input/Output (I/O) operations, memory management, process and thread creation, and synchronization methods. The User32 DLL allows applications access to fundamental user tasks such as creating modals and GUI configurations. Let’s look at some of the specific functions imported from these libraries.
Looking at the functions responsible for execution, we can see that the sample uses the command line and can perform process and thread operations.
This sample has limitless potential for file and directory creation, deletion, and discovery.
The synchronization functions reveal the use of critical section operations. In concurrent programming, critical sections are code-protected sections that exclude access from other processes, threads, or tasks. In other words, no other application can interrupt the operations of a critical section of code. You may have heard of a mutual exclusion object (mutex), which ensures that only one process can access a shared resource at any time. As you will see, ISAACWiper leverages this to perform uninterrupted wipe operations.
These functions allow applications to acquire information from the operating system. For example, getting a windows directory or checking if a processor feature is present. These contain some anti-debugging methods, too, such as GetTickCount or isDebuggerPresent. However, ISAACWiper employs GetTickCount to aid in the wiping process instead of for anti-debugging.
GetDiskFreeSpaceExW and GetLogicalDrives allow the file to acquire a list of all physical and logical disks (partitions) and even diagnostic information from them.
The strings within the file are pretty revealing of its behavior. There exists a mention of a log.txt file and a bunch of debug strings that foreshadow the attempted deletion of disk drives.
Finishing up the file overview with a view of Puppy showing the original file name and the functions it exports. The original name was Cleaner.dll, which exports a function named _Start@4. You may also notice that the TimeDateStamp is about 100 years in the future. This is because some malware authors add fake time stamps to confuse researchers. Knowing the export function allows us to go directly to that function. So, that is what we will do.
Since there is only one export function – _Start@4 – we can go directly to that function, bypassing any anti-debugging techniques before it. This function is straightforward; it calls the sub_10002500 function (2500), ExitWindowsEx, and then returns. The ExitWindowsEx function takes two parameters, dwReason, and uFlags. The ‘2’ argument pushed before the function call translates to EWX_REBOOT. Meaning the _Start@4 function calls 2500 and then reboots the system. The obvious next step is to see what the 2500 function contains.
Using the graphical view in IDA, we see that the 2500 function begins with a ton of variable declarations, followed by a call to 4A80 and then a conditional jump.
Observing the pseudocode shows the debug strings discussed earlier corresponding to the 6FC0 function.
The 4A80 function creates the log.txt file where the debug strings end up.
The contents of log.txt after execution of the file, and before the data wiping process begins:
Following the creation of log.txt, ISAACWiper has two consecutive conditionals before continuing operations. These two functions, 7240 and 74F0, attempt to acquire information about disks on the systems.
This function gets a list of physical drives on the system starting with the root ‘.\\’. For most machines, the first drive will be the C drive. The subfunction 87F0 performs the legwork to acquire the list of physical drives.
Microsoft states that you can acquire a handle to a device on a system by using CreateFile and DeviceIoControl. Microsoft documentation explains the process below:
This is precisely the process ISAACWiper uses to get a handle to a disk. Looking at the pseudocode for the 87F0 function below, it calls CreateFile with read access, followed by a DeviceIoControl call with an IOCTL_STORAGE_GET_DEVICE_NUMBER argument. It then performs a check to ensure the resulting buffer is a disk. This algorithm occurs several times throughout the analysis of this file with the only exception being the arguments passed to it.
The 7240 function continues with a call to GetDiskFreeSpaceExW to get the amount of space on the disk.
The following function, 74F0, uses that same algorithm to get a handle to a disk. Only this time, the argument passed to DeviceIoControl is IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. Microsoft describes this argument as an attempt to get physical disk metadata such as cylinder count, sectors per track, and, most importantly, the total size of the disk.
3310 Function (cont.):
The subsequent significant behavior arrives right before the wiping operations begin in function 3310. We see the same algorithm; this time, the CreateFile call has write access rights, and the DeviceIoControl call has the FSCTL_LOCK_VOLUME argument. This means the disk volume is locked, and only a specific object handle can access the volume.
Once the volume is locked, the main functionality of the wiping operation commences. The algorithm begins by calling GetTickCount to acquire a seed number. The file then implements the Mersenne Twister PRNG and creates random data using GetTickCount as a seed. It may be difficult to detect the algorithm, but the conditional at the bottom of the pseudocode below gives it away. That is the “twist” portion of the Mersenne Twister PRNG.
ISAACWiper uses this “twisted” data to overwrite the first 10,000 bytes of the physical drive using WriteFile. Ultimately, destroying the MBR of the disk.
The volume is then unlocked using the FSCTL_UNLOCK_VOLUME argument via DeviceIoControl, and the handle is closed.
ISAACWiper doesn’t stop there. After the MBR’s destruction, two additional functions exist near the end of the file that performs additional wiping operations – 39F0 and 3700. The CreateThread call contains 39F0. Meaning a single thread performs all of the procedures for the 39F0 function.
The next iteration of the wiping operations is slightly different but still employs the same underlying techniques. It uses GetTickCount as a seed number. This time the malware creates a directory at the root directory with the name “Tmd” concatenated with GetTickCount. This results in something that looks like: “C:\Tmd7B11.tmp.” It then creates a file within that directory following the same methodology, but the name starts with “Tmf” instead of “Tmd.” This results in something that looks like: “C:\Tmd7B11.tmp\Tmf7B30.” Then the same algorithm as before: GetTickCount as the seed and Mersenne Twister to morph the data.
This function is responsible for iterating through files on each disk and continuously writing 10,000 bytes to them, using the same techniques. It finds the first file using FindFirstFileW; finds the physical disk using the 87F0 function (described above); uses GetTickCount to assist in the file creation process; and then calls 3560. Then it finds the next file.
The final step is to look at function 3560. It’s the same algorithm used to write 10,000 garbage bytes to a file.
Executing the file results in the following file operations:
Looking at the contents of the log.txt file after execution shows the garbage data.
Also, attempting to run any application throws an error.