Decrypting Adwind jRAT jBifrost trojan

This is a post on how to dissect the AdWind / jRAT / jBifrost Java trojan that has been around for quite a while and is still actively distributed in multiple variants. jRAT is nothing new and it has been decrypted before, but it’s still an interesting excercise.

I retreived a more or less recent AdWind variant from late 2016 (SHA256: 5b4a70e51095ca9ee19bbf81ef434d421ee5695474bc7f81e40955359d8afec8) and decided to take a look at it. AdWind is a Java based trojan that is delivered as a jar file. Jar files are basically zip files and so you can extract them easily:

mv AdWind.jar AdWind.zip
unzip AdWind.zip

This leaves you with a bunch of files and directories:


-rw-r--r-- 1 michael michael  368 Nov 23 12:43 drop.box
-rw-r--r-- 1 michael michael  256 Nov 23 12:43 mega.download
drwxr-xr-x 2 michael michael 4,0K Jan  9 17:11 META-INF
drwxr-xr-x 3 michael michael 4,0K Jan  9 11:46 NtH
drwxr-xr-x 2 michael michael 4,0K Jan  9 11:46 operational
-rw-r--r-- 1 michael michael 1,5K Nov 23 12:43 sky.drive
drwxr-xr-x 3 michael michael 4,0K Jan  9 11:46 VRL
drwxr-xr-x 2 michael michael  16K Jan  9 11:46 w
drwxr-xr-x 3 michael michael 4,0K Jan  9 11:46 YG

There are some interesting things here: Multiple, obviously obfuscated directories NtH, VRL, etc. There are also some files: drop.box, mega.download and sky.drive. Running the file command to determine types results in:


root@sixtyseven:/home/michael/Disassembly/Malware/AdWind/unzip# file *
drop.box:      data
mega.download: data
META-INF:      directory
NtH:           directory
operational:   directory
sky.drive:     Java serialization data, version 5
VRL:           directory
w:             directory
YG:            directory

So we have a serialized object in sky.drive and some unknown types of data in drop.box and mega.download.

Let’s have quick glance at sky.drive:

root@sixtyseven:/home/michael/Disassembly/Malware/AdWind/unzip# hexdump -C sky.drive 
00000000  ac ed 00 05 73 72 00 14  6a 61 76 61 2e 73 65 63  |....sr..java.sec|
00000010  75 72 69 74 79 2e 4b 65  79 52 65 70 bd f9 4f b3  |urity.KeyRep..O.|
00000020  88 9a a5 43 02 00 04 4c  00 09 61 6c 67 6f 72 69  |...C...L..algori|
00000030  74 68 6d 74 00 12 4c 6a  61 76 61 2f 6c 61 6e 67  |thmt..Ljava/lang|
00000040  2f 53 74 72 69 6e 67 3b  5b 00 07 65 6e 63 6f 64  |/String;[..encod|
00000050  65 64 74 00 02 5b 42 4c  00 06 66 6f 72 6d 61 74  |edt..[BL..format|
00000060  71 00 7e 00 01 4c 00 04  74 79 70 65 74 00 1b 4c  |q.~..L..typet..L|
00000070  6a 61 76 61 2f 73 65 63  75 72 69 74 79 2f 4b 65  |java/security/Ke|
00000080  79 52 65 70 24 54 79 70  65 3b 78 70 74 00 03 52  |yRep$Type;xpt..R|
00000090  53 41 75 72 00 02 5b 42  ac f3 17 f8 06 08 54 e0  |SAur..[B......T.|
000000a0  02 00 00 78 70 00 00 04  c1 30 82 04 bd 02 01 00  |...xp....0......|
000000b0  30 0d 06 09 2a 86 48 86  f7 0d 01 01 01 05 00 04  |0...*.H.........|
...

The strings java.secruity.KeyRep and RSA stick out. Having a glance at the data files yields nothing of interested. But since there is a RSA Key in this serialized Java object, we can guess that the other files contain encrypted data. We will see if that is true later. Now let us have a look at the Java classes. Since this JAR has a META-INF directory which contains a Manifest file, we open the MANIFEST.MF with a text editor and find:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.0
X-COMMENT: xoaJkjDXkreSrqSxraHXFVSmOyICVLsJAvAGBQgscBVBBPiZxEYcSdizcGF
 WlBRdIMFgTIielKs
Class-Path:
Created-By: nnVCxJGeoqGWcmyXUYYcuGPvxTTOfZhfeagUXONAz
Main-Class: operational.JRat

The main class is operational.JRat. We find this file in the folder operational.

file JRat.class 
JRat.class: compiled Java class data, version 50.0 (Java 1.6)

Time for some disassembly and decompilation!

For a first glance at an unknown binary I often use Radare2 since it disassembles nearly everything.

This is the main method of the JRat class:

/ (fcn) sym.operational_JRat.main 12
|   sym.operational_JRat.main ();                                                                      
|           0x000001b7      bb0002         new w/manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskyz
|           0x000001ba      59             dup
|           0x000001bb      b70003         invokespecial w/manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskyz/<init>()V ;[1]
|           0x000001be      4c             astore_1 
|           0x000001bf      b1             return
|           0x000001c0      57             pop
|           0x000001c1      4c             astore_1
\           0x000001c2      b1             return 

It simply loads another method with a quite obfuscated and inconvinient long class name consisting of the repeating pattern maninthesky and the letter z.

Since this new class is part of the package w let us have a look at the corresponding folder. Things start to get ugly:


root@sixtyseven:/home/michael/Disassembly/Malware/AdWind/unzip/w# ls
manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskyaa.class
manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskya.class
manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskyb.class
manintheskymanintheskymanintheskymanintheskymanintheskymanintheskymmanintheskymanintheskymanintheskymanintheskyanintheskyc.class
[...]

Hm. Time to get a better overview over the structure. I used bytecodeviewer to open up the original JAR. BytecodeViwer contains multiple disassemblers and decompilers that might help here.

BytecodeViewer original jar

Bytecodeviewer is pretty nice: It allows you to browse the JAR looking at different decompilations, bytecode, hexcode or whatever at the same time. Opening the maninthesky class that ends with the letter z we see a first decompilation. This is helpfull but still cumbersome to read. We can make things easier if we convert the classes and files to a more readable format.

So after opening the malicious JAR in BytecodeViewer you can do “File -> Decompile & Save All Classes”. Then chose a disassembler. I chose Krakatau, which gives good results but leaves out some classes since it couldn’t find some imports. We can add these few classes later manually.

Having decompiled (nearly) all classes, we can rename them and replace strings to produce more readable versions. Using rename and sed we can produce more readable versions of the files. E.g. in the w folder, do

rename 's/maninthesky//g' *.java

and

for i in *.java; do sed -i 's/maninthesky//g' ${i}; done;

to rename all files and replace the content. You might have to execute these commands two times to clean up everything and it might ruin some variable names in the sample but we can reconstruct this manually if needed.

After cleaning up, we can finally browse the project files in a more readable manner. The z class now basically looks like this:


package w;

public class z {
    public z()
    {
        super();
        w.y a = new w.y(new w.q(w.n.j((String)null, w.i.h_super) ).b()); //sky.drive
        byte[] a0 = w.k.H(w.n.j((String)null, w.i.h_void)); //mega.download
        byte[] a1 = w.k.H(w.n.j((String)null, w.i.h_this)); //drop.box
        w.l a2 = new w.l(); //l contains decryption methods
        
        a2.B(a0); //we feed mega.download
        a2.O(a1); //we feed drop.box
        
        w.s a3 = new w.s((java.io.InputStream)a2.C(a.F())); //Feed the RSAPrivateKey in sky.drive to the decryption routine in l
        
        w.h a4 = a3.k("PRIVATE_PASSWORD");
        w.h a5 = a3.k("PASSWORD_CRYPTED");
        w.h a6 = a3.k("SERVER_PATH");
      
        w.y a7 = new w.y(new w.q(w.n.j((String)null, a4)).b());
        [...]
        java.io.InputStream a12 = w.n.j((String)null, a5);
        [...]
        byte[] a16 = w.k.H(a12);
        [...]
        byte[] a22 = w.k.H(w.n.j((String)null, a6)); //SERVER_PATH
        w.l a23 = new w.l();
        a23.B(a16);
        a23.O(a22);
        [...]
        w.sa a25 = a23.C(a7.F()); 
        [...]
        a27.E(a25);
        [...]
    }
}
               

It is much more readable. Starting from z we can dive down and see what we find. Most classes are just wrappers for some standard Java stuff, others contain more interesting pieces of code. e.g. in i you can find the filenames sky.drive, drop.box und mega.download, so that might be interesting. As we learn from examining z, these info is fed to an object of class l. Looking at class l we see a decryption routine C:

//This loads var1 as private key and decrypts the content of mega.download
    public sa C(Object var1) throws GeneralSecurityException {
      
      pa var2;
      
      //pa.v javax.crypto.Cipher.init with key var1 und i.
      (var2 = (new aa()).s("RSA")).v((RSAPrivateKey) var1, this.i_enum); 
      
      //get an instance of javax.crypto.Cipher with type AES
      pa var3 = (new aa()).s("AES"); 
      
      //var2.Y is a wrapper for the internal ciper.doFinal method and decrypts whatever is in this.ba_break
      byte[] var5 = var2.Y(this.ba_break);

      //we specify that var5 is an AES key
      SecretKeySpec var6 = new SecretKeySpec(var5, "AES");
      
      //pa.v javax.crypto.Cipher.init with key var6 und i var.
      var3.v(var6, this.i_enum);
      
      //then we decrypt ba_void
      byte[] var7 = var3.Y(this.ba_void);
      
      //and we return a java.io.ByteArrayInputStream (sa) with the decrypted content
      return new sa((Object)null, var7);
   }

Basically, method C does this:

  1. It opens the RSAPrivateKey KeyRepository class, which is serialized in sky.drive
  2. It uses the RSA key from this class to decrypt an AES key which is stored in drop.box
  3. It uses the decrypted AES key to decrypt the data in mega.download - which will turn out to be a properties file pointing to more interesting files.

If we follow the sourcecode a little further, we will find this decryption routine in several places of the malware. Since the decryption is just a chaining of standard routines it is not too hard to write a decrypter for it.

Here is a piece of Java code that decrypts the AdWind files.

Warning: Only execute the decrypter in a seperated environment. It deserializes the object given as RSA KeyRep and might be highjacked from malicious code itself.

Using this decrypter, we can decrypt the files and get the properties file:

java -jar AdWindDecryptor.jar 
-a mega.download\
-r sky.drive\
-i drop.box\ 
-o properties.ini

This is the decrypted properties.ini:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Support: https://jrat.io</comment>
<entry key="SERVER_PATH">/VRL/uW/Y.c</entry>
<entry key="PASSWORD_CRYPTED">/YG/Lab/vvv.Ttm</entry>
<entry key="PRIVATE_PASSWORD">/NtH/s/NU.xtr</entry>
</properties>

Not too interesting at first glance, just a few paths to new files we already had access to before. It also points us to a site where we could buy a jRAT version (no thanks). Since these variable names are tempting, let us try to use the decrypter once again:

  • Using PASSWORD_CRYPTED as crypted AES key,
  • PRIVATE_PASSWORD as RSA Key Rep and
  • SERVER_PATH as something we want to decrypt.

(Looking at the decompiled code more closely we can already figure out that this will work and what we are about to decrypt here.)

After going through the decryption routine once again, we finally get to the core of the malware: The server.jar. This is the file that contains the actual RAT code and that we can use for further analysis. And hey, we don’t have to pay for it!

BytecodeViewer original jar

Without going into too much analysis of the server.jar, we see that its config files in server/ressources are also encrypted. We can try to use the decryptor once again and make an educated guess of how we should provide it with the files. Checking size and type we find:

-rw-rw-r-- 1 michael michael 6,0K Nov 23 12:43 config.json
-rw-rw-r-- 1 michael michael 1,5K Nov 23 12:43 Key1.json
-rw-rw-r-- 1 michael michael  256 Nov 23 12:43 Key2.json

and

config.json: data
Key1.json:   Java serialization data, version 5
Key2.json:   data

So we conclude:

  • Key1.json is again a serialized Java Key Rep object, so this is our RSA Key
  • Key2.json is the smallest of the files with a size of 256 byte, which matches the size of the encrypted AES keys before. So it is very likely the encrypted AES key.
  • We can guess that config.json is what we want to decrypt.

Using

java -jar AdWindDecryptor.jar 
-r Key1.json -a Key2.json -i config.json -o config-decrypted.json

we decrypt the encrypted config file:

{"NETWORK":[{"PORT":1663,"DNS":"***"},{"PORT":5836,"DNS":"***"}],"INSTALL":true,"MODULE_PATH":"nJn/rKQ/E.s","PLUGIN_FOLDER":"qhAcQBGGpDA","JRE_FOLDER":"X O X O X O X O","JAR_FOLDER":"Javax","JAR_EXTENSION":"txt, jpg","ENCRYPT_KEY":"WiWWIMklVZjDdqDxHIlPkCVsm","DELAY_INSTALL":2,"NICKNAME":"X O X O X O X O","VMWARE":true,"PLUGIN_EXTENSION":"txt, jpg","WEBSITE_PROJECT":"https://jrat.io","JAR_NAME":"Javac" 
[...]

That’s it. We can retreive the malware configuration by using the same decryption routine over and over. And if you are actually a victim of AdWind / jRAT / jBifrost this might be a good starting point to figure out who is attacking you.

For comments / corrections / questions, contact me on Twitter.