This blog post was authored by Roberto Santos
KONNI is a Remote Administration Tool that has being used for at least 8 years. The North Korean threat actor that is using this piece of malware has being identified under the Kimsuky umbrella. This group has been very busy, attacking political institutions located in Russia and South Korea. The last known attack where KONNI Rat was used was described here.
We found that KONNI Rat is being actively developed, and new samples are now including significant updates. In this blog post, we will cover some of the major changes and explain why the security community should keep a close eye on it.
Simplified Attack Chain
The attack usually starts leveraging a malicious Office document. When this document is opened by the victim, a multistage attack is started, involving various steps. But these steps are just the way that the attackers manage to accomplish tasks to elevate privileges, evade detection and deploy required files. As we described in a previous blog post, the attack chain could be summarized in the following diagram:
The attack usually starts leveraging a malicious Office document. When this document is opened by the victim, a multistage attack is started, involving various steps. But these steps are just the way that the attackers manage to accomplish tasks to elevate privileges, evade detection and deploy required files.
The final goal of the attack is installing what is called KONNI Rat, which is a .dll file supported by an .ini file. In a nutshell, the .dll file contains the functionality of the RAT, and the .ini file contains the address of the first C&C server. KONNI Rat's general behavior remains almost the same as previous versions, but there are changes we will cover below.
Rundll no longer supported
In previous KONNI Rat samples there were two branches. One handles if the malware was launched using a Windows service, and the other handles the execution through rundll. The next image shows these two old branches, with the strings svchost.exe and rundll32.exe visible:
However, new samples will not show these strings. In fact, rundll is no longer a valid way to execute the sample. Instead, when an execution attempt occurs using rundll, an exception is thrown in the early stages.
In early stages of our analysis, we thought that they were using the classic process name check, or any other usual technique. The reality is far simpler and brilliant; the actual export just implements the SvcMain prototype so the program will break at some point when accessing one of the arguments.
In the previous image we see the state of the machine at the moment that this exception is thrown. RDI at that point should contain a pointer to the service name. The exception happens because the Service Main function meets one prototype and rundll32 will expect another different prototype:
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
VOID WINAPI runnableExport(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
Basically, at some point of the execution, hinst will be treated as lspzArgv, causing the exception. But why did the attackers delete that functionality? There are multiple benefits.
First of all, we have not seen any recent attack that used rundll. In fact, the only way that the attackers launched KONNI Rat in recent campaigns involves registering a Windows service. So the rundll32 branch wasn’t being used in real world attacks.
But there is another big reason in how sandboxes will fail in collecting the real behavior of the sample, as it just cannot execute that way.
Strings are now protected using AES
Multiple malware families protect their strings in order to defeat most basic string analysis. KONNI wasn’t an exception, and also used this technique. Old samples were using base64 for obfuscation means. Also, they were using a custom alphabet. This custom alphabet was changed from time to time in order to make the decoding task more difficult:
Now, the attackers made a major change in that regard by protecting the strings using AES encryption. The algorithm followed by new Konni RAT samples could be represented as follows:
The reason behind that change is clear. As the key used for decryption is the service name, samples run by different service names will not work properly. Moreover, having only the sample without knowing the service name becomes useless, as these strings contain core information about the sample behavior.
Files are also protected using AES
KONNI Rat makes use of various support files when it is executed. One of these files is the .ini file, which contains the primary C&C server, but there are others like the .dat file that is supposed to be dropped eventually, and temporal files that are used to send some basic information about the computer.
Our tests reveal that all of these files are dropped and protected using AES. Cleverly, they reused the algorithm used for string protection, making the file layout identical to the protected strings layout, as they appear in raw memory:
As can be seen from the diagram, the file itself contains the IV and the encrypted data. The key used is extracted from its original filename. In some cases, the names match with the service name, so the keys used in the .ini and the .dat files are the result of applying a SHA256 to the service name as well.
Also, files sent to the C&C server are protected using AES. The IV is generated using a QueryPerformanceCounter API CALL. Filenames are generated concatenating 2 letters that represent the data with the current timestamp, followed by the extension. Furthermore, they will use this newly generated name as AES key, so they send this name through the request to the C&C server.
In that regard, as the filename is generated automatically using the timestamp, identical files will produce different request contents, as they were encrypted using that filename. Network signatures could also fail to detect the malicious activity, due to that.
Other obfuscation techniques
As we found some samples that were protected just by the means that we described before, we also have found others that were making use of an unidentified packer (UPDATE: There is a strong correlation between this packer and VMPROTECT v3, as you would see in the following paragraphs. Later deeper analysis tasks suggest that this is probably the packer that was used in this ocasion). We would like to share some of our notes regarding that packer, as others could find it useful in identification and attribution tasks.
Contiguous instruction obfuscation
The flow of the obfuscated program will make use of series of push-call pairs of instructions, where the pushed values will indicate the actions that the program will take. An image can better explain that:
In particular, we find it interesting that the attackers have placed random bytes between these pairs. This silly trick causes wrong code interpretation for decompilers that will assume that bytes after the push instruction are part of the next instruction. The image below shows how IDA fails in analyzing the code:
Obfuscated program flow
The used packer will obfuscate the original program flow. This is accomplished in various steps. The first required step is to find the Image Base value, placed in a fixed location and the RIP (Instruction Pointer) value.
Once the packer knows these two values, it will start jumping from one place to another, making analysis harder. For that, it will store in some register value of the next address to jump in registers. The value of these registers is calculated right after the jmp instruction, using structures like POP [reg] - JMP [reg] or ADD [reg1, reg2] - JMP [reg1]. Note that decompilers will fail in displaying the real flow, as the jumping address is determined by a somehow undefined register.
The combination of these simple techniques ends in the packer being now in control of the flow, but statically the decompiler cannot represent the path that the code will follow. Finally, the packer will execute a big amount of junk instructions and eventually will execute the real interesting code. For instance, the original code will take no more than 20 instructions between GetProcAddress calls in IAT building tasks. but the packed code executes more than 30,000 instructions.
According to our threat intel data, most recent attacks are not making use of that packer anymore.
As we have seen, KONNI Rat is far from being abandoned. The authors are constantly making code improvements. In our point of view, their efforts are aimed at breaking the typical flow recorded by sandboxes and making detection harder, especially via regular signatures as critical parts of the executable are now encrypted.
Malwarebytes users are protected against this attack.