I recently ran into a fairly generic XSS vector which didn't seem to be on the XSS cheatsheet. It seems to be a quirk of the way the DOM parser handles <script> tags and well, a broken JSON encoder. The vulnerability (or at least gotcha) exists when properly quoted strings are printed out inside a <script> node. A simplified exaple looks somewhat like this.
<script> var a = "</script> <script> alert('XSS !'); </script> <script>"; </script>
For some strange reason, Firefox picks up the script closing tag in the quoted string and then proceeds to process the remaining script tags as code. Try it for yourself.
I discovered this problem inside a large/deep block of JSON. Thankfully, the php JSON encoder escapes the forward slash, but the JSON spec doesn't require that explicitly AFAIK. For instance, the standard python-json module which came with Ubuntu generates bad code to embed in a script segment (so, start using "import simplejson as json").
Quoting strings anywhere is complicated enough and if you ever need to dump stuff into a javascript segment, use a json encoder - a good one & not reinvent your own.
--If I do not want others to quote me, I do not speak.
-- Phil Wayne
posted at: 01:12 | path: /insecurity | permalink |
I've sort of been toying around with AttackAPI over the weekend and interestingly, I figured out that I was vulnerable to a lot of the attack vectors that were present. But what javascript causes, javascript can fix too. So here's a quick fix to prevent an intruder from portscanning your local network for ftp or other ports.
FindProxyForURL: The proxy autoconfig file can be used to filter out requests to the naughty port scanners. The aim is to detect a bad URL, redirect it to a proxy which will log the referrer and raise the corresponding alarms. And to parse out the URL properly, I use the following regex.
var urlRegex = new RegExp( "^(([^:/?#]+):)?"+ // scheme "(" + "(//)?"+ // delim "(([^@]+)@)?" + // userinfo "([^/?#:]*)?" + // host "(:([^/?#]+))?"+ // port ")"+ "([^?#]*)"+ // path "(\\?([^#]*))?"+ // query "(#(.*))?$" // fragment );
After parsing out the URL, my very simple filter checks for a port value which is suspicious (i.e below 1024 and not 80) and redirects it to my local logging proxy which eats the request. I still haven't figured out a way of leaving a honeypot for attackers to ensure there's a human at the other end.
function FindProxyForURL(url, host) { var m = url.match(urlRegex); if(m) { var port = m[7]; if(port != "" && port != "80" && port.length < 4) return "PROXY 127.0.0.1:4242"; } else { return "PROXY 127.0.0.1:4242"; } return "DIRECT"; }
It should be perfectly possible for this technique to be extended to prevent XSS exploits with javascript land checking for common XSS attack vectors. But the essential problem is that this particular function cannot maintain context easily. The previous request cannot affect the current one, nor the current one affect the next request. Having minimal ability to learn does cause a large number of problems for a really practical solution - but if there is already such a hook, it might be possible to hook an extension into it.
--Too many people are thinking of security instead of opportunity.
-- James F. Byrnes
posted at: 01:23 | path: /insecurity | permalink |
Being a psuedo-security guy of sorts, I'd decided to jump back into insecurity land a couple of weeks back. I haven't really been into security-tech for quite a long time, having hung up my script kiddie slingshot a long time back. But of late, it has again started to look attractive - but more than mere implementation issues, I've been looking for true blue design issues.
Recently on IRC, dumbhead was defending his default password on his router, which is conveniently firewalled off from the WAN. In my attempts to prove that setup insecure, I discovered DNS Pinning. It has been truly enlightening to perform a cursory attack on a home router with a faked up nameserver (re-used my twisted.names code).
The first request immediately does an iframe with a made-up hostname to ensure that no dns caches interfere. The resolution of that host (say "mordor") looks somewhat like this.
;; QUESTION SECTION: ;mordor. IN A ;; ANSWER SECTION: mordor. 284 IN A xxx.xxx.xx.xx mordor. 284 IN A 192.168.1.1
Now there is a good probability that the first IP will be hit nearly immediately by the browser. The server is running a script which tails the access log as soon as that vhost is hit (for dynamic vhosts, install lighttpd-mod-mysql-vhost), marking the vhost in the table as "hit". A sudo'd python script hooks into the mysql table, flips that flag to "block" after running an iptables packet drop on dst port 80, src ip of the victim.
Thirty seconds after loading the first iframe, the code in there creates another iframe with src=document.location+"?xyz". Very soon, that frame loads up 192.168.1.1 in the same domain as the attacking website. I've got a default exploit sequence, which opens up port 22 for the Huawei WA1003A router which BSNL is distributing these days - but this requires the default password to be unchanged.
But the default password might not be required with the more expensive routers. If I could run my first evil iframe on port 2869 to commit the b0rkage, I would essentially be able to access the UPnP which takes a bit of SOAP to reduce the NAT into swiss cheese. But I'm a bit too lazy to actually write out those SOAP calls using XmlHttp (hah, same domain). And all that *without* a single password.
Most people have dismissed the DNS feature as unusable for hacking most websites because it sends invalid Host: headers and without cookies. But none of the routers I've looked at so far care about that or even have javascript checks for iframes (not that it will affect XHR much).
Amazingly simple, elegant. And DNS has been around for only 20 years ...
PS: thanks for providing the domain - you know who you are :)
--The Domain Name Server (DNS) is the Achilles heel of the Web.
-- Sir Tim Berners-Lee
posted at: 04:23 | path: /insecurity | permalink |