The last two days were pretty exciting from a web application security perspective. It’s only been the first few days of the year and we have easily found one of the worst holes in it - and then proceeded to make it worse. The Adobe PDF reader XSS was more than just a simple flaw in a commonly used software. The hole was a chance to analyze our own reaction to the problem. There were a lot of false steps here, and I think we should look carefully at a lot of the mis-perceptions and kneejerk reactions.
The first and most common mis-perception was that the anchor tag was sent to the server. That caused a rash of comments like “I’ll just stop it with my web application firewall” or “I’ll block it with an apache rule” etc. That’s dangerous thinking. No one bothered to test to make sure that would work before telling others that that’s what they should do. The only people who were the word of caution were people who already knew that wouldn’t work. That alone scares me.
Next was the “you can detect badguys using mod_rewrite” people. Here are two sample rules:
SetEnvIf Request_URI “\.pdf$” requested_pdf=pdf
Header add Content-Disposition “Attachment” env=requested_pdf
and
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://([-a-z0-9]+\.)?example\.com[NC]
RewriteRule .*\.(pdf)$ http://www.example.com/images/noexternal.gif [R,NC,L]
Be careful using either of those. REQUEST_URI can contain anything: http://example.com/file.pdf?whatever#vectorgoeshere For that example the request URI will be ..pathto..file.pdf?whatever which does not match “\.pdf$”. Likewise the second one has issues, including the fact that referrers are not always present (Zonelabs Zone Alarm Pro, and both Norton Internet Security and Norton Personal Firewall). Also, referrers are spoofable using Flash.
Next was the token crowd. This probably has the most legs in terms of being able to still allow the customer to retain the user experience of viewing the PDF doc on the website. However it has one fatal flaw. Here’s the algorithm:
IF the URL doesn’t contain token_query, then:
calculate X=encrypt_with_key(server_time, client_IP_address)
redirect to file.pdf?token_query=X
ELSE IF the URL contains token_query, and
decrypt(token_query).IP_address==client_IP_address and
decrypt(token_query).time>server_time-10sec
serve the PDF resource as an in-line resource
ELSE
serve the PDF resource as a “save to disk” resource via a proper choice of the Content-Type header (and/or an attachment, via Content-Disposition).
Now let’s ignore the potential issues with Content-disposition browser compatibility for a moment and think about the basic premise that this pseudo code is working on. It is making an assumption that an attacker will never have the same IP address as the user. That’s just not the case. This isn’t as rare as just a few universities and ISPs. This also happens in lots of corporate networks (rogue user on the internal network), it happens with lots of internet cafe’s, it happens with AOL (~5MM users) and it happens with TOR users. So while, yes, I agree it is better than nothing it is hardly a rock solid solution for anyone on a shared IP.
In the end, Adobe issued an alert and told everyone to upgrade (which everyone should always do, but as we all know they rarely will). Browser companies didn’t chime in at all, even though they could easily fix the issue. The network security folks changed the content type. The application guys told us how to stop PDFs from working in browsers. And at the end of the day, where has that left us? There are still a lot of exploitable browsers out there. Like I said, it has been an interesting last few days.