Dumping Redline Malware Configuration (YouTube)
Part 1: Dumping Dynamically Loaded Payloads
Let’s take a look at a recent sample of the .NET based malware known as Redline Stealer. We will cover some techniques on how to identify the malware and reverse engineer it. Taking a recent sample uploaded to malshare.
- Source: Malshare.com
First off we obtain this sample with a particular SHA256 hash:
Starting Host IOC: 3bd982f82a1b2f074b02fe7cc7413f1e083f19108ae2612b2b5a741a9858f7f4
Examining the binary at a glance we can see it is a 32-bit .NET assembly with an original name of BaseChannelObjectWithPropert.exe which is masquerading as a product called Change Detector.
In addition, examining this with PE-bear shows that it has a PDB string of the following:
Given this is a .NET executable, we can examine this in dnSpy. At a glance this binary appears interesting as it only has a few imports including the Diagnostics and Reflection classes. Although these may be legitimate, it does lead me to begin to think this may use unmanaged code or injection.
Looking into the main program entry point we can find that this is executing a new instance of it’s ‘MainForm()’ class.
Examining this we see it is retrieving a public method called ‘K67WB7wrc’ using the reflection class which will be loaded dynamically at runtime by using ‘GetMethod’. This is leveraging a Custom Binder and CLR to run the code.
By debugging using dnSpy with a breakpoint before this is invoked, we can see that it is attempting to run dynamically loaded code with an original name of “H5lJ05BU7EajaXhAma.c0MIdh5giS0KIBpS0s” (Namespace+Name) that resolves to a module called ‘Cerbera.dll’.
Stepping into each function for a brief period we begin to see that this is passed 3 parameters when invoked.
4576656E74526567697374726174696F6E546F6B656E4C69737457697468436F 6D73497A496B6C6E74 ChangeDetector
Eventually we make it to ‘K67WB7wrc’ attempting to be invoked which causes Cerbera.dll hosting this to be decompiled in dnSpy. Of interest is that the code is heavily obfuscated, but we do see reference to raw assembly being loaded.
To ensure we can further analyse this module without many issues, we can use dnspy’s ‘Modules’ window to dump the Cerbera DLL directly from memory.
After this, by setting a breakpoint on the raw assembly load, and running the program, it will first cause the thread to sleep, before hitting our breakpoint. At this point we have another module in memory loaded under the ‘rawAssembly’ variable and can view this in a memory window.
We can also save this entire memory region to another DLL file on disk.
At this stage we have 2 new DLLs to analyse, Cerbera, and one I’ve labeled ‘Stage2’. The SHA256 of these files are as follows:
SHA256 (Cerbera.dll): 840BE1D54AC08FDEC3556B93FF92AF7E2F6D7C909A7606C59C5AC777670E2742 SHA256 (Stage2.dll): 6EEE2F6A6FDEF5EEA8D485A86E69697335F42882FB90E54A472AA99ACFD1736D
Part 2: Investigating Cerbera and IVectorView.dll
Taking a look at Cerbera and Stage2, both appear to be .NET based DLL files.
Opening these in dnSpy reveal they have the original file names of ‘Cerbera.dll’ which was already known, and ‘IVectorView.dll’ (with version information 184.108.40.206); however, the decompiled code is quite obfuscated.
Using de4dot we can see if there’s any known obfuscator in use on these binaries.
de4dot -d Cerbera.dll Stage2.dll
Because these are either using an unsupported obfuscator or not obfuscated, this prints “Unknown obfuscator”.
Moving back to the debugging, by using a combination of stepping into and stepping out of methods (F11 and SHIFT + F11) it appears that the primary purpose for Cerbera.dll is to act as a reflective injector/loader for Stage2.dll (IvectorView.dll) after sleeping for 43731 milliseconds, before exiting. A number of operations make this possible with the payload ultimately being retrieved from resource aGHcO0I8Uaop8WK9nR.ubyN5f3fq1X99obSjG within Cerbera.dll before being dropped directly into memory within a surrogate injected process.
The surrogate process this looks to inject into is another copy of itself, and this is something we can use to our advantage. Because we can see this executable creates a new process, injects into it, and then exits, we just need to await for the code to be allocated and injected into the new process to get the next piece of the puzzle.
By allowing this to play out and inject into another process, we can then attach dnspy to the newly spawned process for debugging (in this case process 4060).
After attaching to this process we want to see if we can break on an instruction to decompile it as it exists in memory. To prevent any issues with breaking a process at the wrong time and causing it to crash, we can take a look at the process in process explorer, and examining the threads we want to wait until all aren’t using any CPU or have a cycle delta whilst in a DelayExecution state.
By timing this right we can then hit ‘Break All’ in dnspy and cause another module called ‘Happy.exe’ to be decompiled from memory, and we should be at a Thread.Sleep instruction.
Because this module is now available to us, we can go ahead and save it using File > Save Module.
Dumping the malware from memory here means that its hash will likely differ amongst different extractions in this way, but in this instance it had the below hash.
SHA256 (Happy.exe): EA6D52270F7D5AEC22FD17F1904F2DFFD566016A4362D9D5EA81C1D11337DE9E
Now that we have a copy of this we can kill all injected processes and analyse the malware from scratch.
Part 3: Investigating Happy.exe (Redline Stealer) Flow and Functionality
Examining our newly dumped Happy.exe in pestudio we can see that this has a number of interesting indicators.
In addition the version information reveals another binary name reflecting its internally developed/original name ‘Implosions.exe’.
Opening this up in dnspy we can see a number of classes which appear suspicious in naming conventions, amongst these is one that looks to be ‘Chrome’ broken up by underscores, and a theme on ‘Scanning’.
Heading down to the main Program, we can see that it kicks off an instance of Class ‘EntryPoint’ and runs the ‘Execute’ method.
At the EntryPoint class, we can find what looks to be a configured IP address and port, an ‘ID’, a ‘message’, and a ‘key’ value being set.
Network IOC: 2[.]56[.]59[.]101:17559 Configured 'ID' IOC: xxl
This is immediately more suspicious given that there looks to be almost an identifier or campaign ID and IP address configured in this executable. Further to this, as soon as it runs, this program uses NativeHelper.Hide() to attempt to load kernel32.dll and user32.dll so that the API calls ‘GetConsoleWindow’ and ‘ShowWindow’ can be used. The purpose of this is to get a handle to the malware window itself, and then subsequently set its visibility to ‘0’ (hidden) which is common to ensure that malware running isn’t shown to the end user.
The first component we can see under the ‘Program’ class after running through our Execute function is that the ‘key’ which is configured within the EntryPoint class seems to be used to decrypt a value when required, this is quite likely an attempt to hide any configured IP, Message, or ID as we can see this being used in another class ‘StringDecrypt’.
From here the program will attempt to make a connection back to the configured IP address in a loop, and everytime it fails the program thread will sleep for 5 seconds.
From here the program defines a new instance of the class ‘ScanningArgs()’ which is used to define a data contract and members which will be used to determine what information it will scan for on the operating system.
In total the following members are set:
This gives us a good idea of what the malware may be looking for, and also gives us an insight into the likely method of C2. Because data contracts are being used, we have a good chance of this using the Windows Communication Foundation (WCF) to talk to the C2 server for instructions. Looking further into the program we can see it then creates a new instance of ‘ScanResult’, decrypts the campaign ID if it is using a key, and uses the output of the initialised ‘ScanResult’ in another method defined under the ‘ResultFactory’ class called ‘sl9HSDF234’.
By examining ‘ScanResult’ we can see that this has another data contract with members which defines information about the Campaign and system information it has infected.
In total the following members are set:
- ReleaseID (campaign ID derived from the decrypted ‘ID’ field)
Examining an example of a Basic Data Contract reveals that structured data can be passed to a web service running on IIS, and depending on what is passed, operations can be performed with different data being returned. This is in essence all that’s required for a fully functioning C2 server and implant.
Moving back to the code we can see that this runs a method called ‘SeenBefore()’ from within the Program class, and the purpose of this is to check if a directory exists in the user’s Local AppData folder called ‘Yandex\YaAddon’, if it does then ‘true’ is returned, otherwise the directory is created and ‘false’ is returned.