martedì 15 gennaio 2019

A crypto-defeat story of a malware labeled as: Backdoor.MSIL.Agent - NanoCore Client

Hello Everybody,
on 14/01/2019 just another RAT has been seen in the wild.

https://www.hybrid-analysis.com/sample/38cba78c3d1650f2ad347c0254837f376fd4434904096451faee82ec31ed829a

Such sample born as obfuscated .net PE. The first step has been obviously to deobfuscate the executable, de4dot was my swiss knife.


From the entry point you can follow the calls and arrive easly to an interesting part...
Class8.smethod_16(), by using WIN APIs calls, allows the malware retrive encrypted data from the only resource it has named "1". A common story of many malwares. :)
Ok, take a look at it and keep it in mind:
Following the code, and focus at
byte[] byte_ = binaryReader.ReadBytes(binaryReader.ReadInt32());
our binaryReader is already filled with the resource and the first step is to read an int32  wich means that the our memory pointer is moved forward of 4 bytes. That is also means that the byte_ array wich have size of the first bytes ( we read "10 00 00 00" --> 0x10) is also filled with the following first 10 bytes of the resource starting after the first 4 bytes.
[spoiler]This will be important because the item will be our DES-perate decryption item! :)  [/spoiler]


Going back on dnSpy we're on the line 366 (see few pictures up) "Class8.byte_2 = Class8.smethod_19(byte_, guid_);"
Let's follow the Class8.smethod_19 method:
Very nice, the parameters byte_ and guid_ are used to prepare the Rijndael keys.
byte_ is written in the resource, and guid_ is just the guid of the exe (see at the method smethod_18 in the last picture).

Stepping back on:
 On the line 367 we have a call to a function, and you can guess what such function does...

public static void smethod_0(byte[] byte_0)
 {
  DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
  descryptoServiceProvider.BlockSize = 64;
  descryptoServiceProvider.Key = byte_0;
  descryptoServiceProvider.IV = byte_0;
  Class22.icryptoTransform_0 = descryptoServiceProvider.CreateEncryptor();
  Class22.icryptoTransform_1 = descryptoServiceProvider.CreateDecryptor();
 }

Yes, DES algo with same key and same IV related to the Class8.smethod_19(byte_, guid_) we seen before. We can put it togheter by writing a tiny (super dirty) c# console aplication here is the source:

using System;
using System.Security.Cryptography;

using System.Reflection;

using System.Runtime.InteropServices;


namespace testz
{
 class Program
 {
  public static void Main(string[] args)
  

      byte[] byte_3 ={ 0x39 ,0x5C ,0x38 ,0xAC ,0x45 ,0x65 ,0x1A ,0xEB ,0x26 ,0x5C ,0x00 ,0xC0 ,0xC9 ,0xA1 ,0xD2 ,0x03};
   
   Assembly assembly_1 = Assembly.LoadFile(args[0]);
          Guid guid_0 = new Guid(((GuidAttribute)assembly_1.GetCustomAttributes(typeof(GuidAttribute), false)[0]).Value);
  
   Console.WriteLine("Hello World!");
   Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(guid_0.ToByteArray(), guid_0.ToByteArray(), 8);
   
   byte[] IV;
   
   
   
   RijndaelManaged asddd = new RijndaelManaged{ IV = rfc2898DeriveBytes.GetBytes(16),Key = rfc2898DeriveBytes.GetBytes(16)  };
   byte[] test= new byte[64];
   
          ICryptoTransform asdsss= asddd.CreateDecryptor();
   test= asdsss.TransformFinalBlock(byte_3, 0, byte_3.Length);
   
   DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
  descryptoServiceProvider.BlockSize = 64;
  descryptoServiceProvider.Key = test;
  descryptoServiceProvider.IV = descryptoServiceProvider.Key;
  Console.Writeln(String.Concat(Array.ConvertAll(test, x => x.ToString("X2"))));
   
   
   Console.Write("Press any key to continue . . . ");
   
   Console.ReadKey(true);
  }
 }
}

And here we are! Yayyy!! We have the DES key: 0x72 0x20 0x18 0x78 0x8C 0x29 0x48 0x97
But the question is: what binary data do we decrypt with it? Let's step back to the resource we were.
our reader pointer were at 0x14 position of the resource.

Once again, another array of 4 bytes int32 dimension, so we have an array size of 0x15fa0 filled by the following resource starting from 0x18.

Let's check our theory by using CryptoTester as below:


Decryption succeded! ....but, i was expecting a more readible data then 01 9B DE 01 00 ED BD...no magic numbers, no blob data, is that a fail? Go back and take a look on the dnSpy and follow the smethod_13() on line 369. the array3 which will contain our decrypted data is filled by the Class22.smethod_2 method.
Following we'll land here:


And here we are! the decrypted data is just a compressed data (deflate). We did the right things, any doubt?! :P
The resource file contains the client settings (keylogger:bool, persistance:bool, hostaddress:string and a lot of others informations) togheter with another MZ  file which is the clientplugin.dll referenced, but not "contained", in the original sample.

I think that the same decryption is valid for most of NanoCore client versions/variants maybe, so feel free to use my code.

I wanna thank Michael Gillespie for his amazing CryptoTester ("saving my soul from hell").
Huge thanks also to Karsten Hahn (without knowing, he inspired me to share things).

Cheers!
Re Solver






Nessun commento:

Posta un commento