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, '',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='' /> ). 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';
    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.


  1. Bluehost is definitely one of the best hosting company with plans for any hosting needs.

  2. Have you inserted the code into a .js and then exploited the XSS with script src=></script ?

  3. I'm the proprietor of a little toy-making company. I diligently utilize a 3D laser scanner to organize the toys. Offer assistance, it makes a qualification to diminish the making time and brought. Best 3d scanning Vancouver, BC

  4. Great points there, thanks. And here is the relevant article, maybe someone will find it useful too