Web Cache Poisoning
- 19 February 2014
If your website implements server side caching of content it is essential that you sanitise your cached content against any malicious code as this is the content that will get served to other users visiting your site until that cache is purged.
Common prevention against hackers includes sanitising against Cross Site Scripting attacks and SQL Injection Attacks, e.g. stripping <script> tags out of URL and escaping apostrophes but what about ensuring your SERVER variables are what they should be?
True Story
The website I was working on was load balanced across 4 servers, each with its own IP address:
- www.mydomain.co.uk
- Server_A – IP=88.88.88.01
- Server_B – IP=88.88.88.02
- Server_C – IP=88.88.88.03
- Server_D – IP=88.88.88.04
I wanted to ensure that when I visited www.mydomain.co.uk that I was always on Server_C for testing that some updates I did worked on that particular server. To do this I set up my Hosts file on my machine with an entry like below:
JIMTEST 88.88.88.03
Then I visited the website, started browsing and testing that the pages still worked. I never noticed at first because some page caching was in place, yet when the cache was cleared and I visited one of the pages I noticed that some of the images no longer displayed and I thought “hmmm that’s strange” so I had a look at what the path of the missing images were and noticed that they had “JIMTEST” in the path:
- http://JIMTEST/images/image1.jpg
- http://JIMTEST/images/image2.jpg
Then someone next to me on another computer also browsing the site also reported that they could no longer see the images. Then it struck a chord, the cached content had stored the $_SERVER[‘SERVER_NAME’] in the cache file (which when I was visiting because of my host file changes was now “JIMTEST”). This meant that anyone who now visited that page would also get served that same content.
This issue got introduced because of existing legacy code and new caching functionality added to the pages. Due to the factor that a several different websites shared the same database content a previous developer at some point introduced a function that replaced the string www.mydomain.co.uk with $_SERVER[‘SERVER_NAME’] to the generated content. As part of a refactoring and performance enhancing job of the website Page Caching of this content was introduced which also led to introduction of this bug.
Exploitation
Aside the UX point of view, where users visiting the site get broken images and links there is also a security issue here. A malicious user could for instance set their hosts file to a malicious domain that they have access to and point it to our IP address and then crawl the site; for example let’s say a mallicious user has access to a dodgy website www.dodgysite.com and sets host file to 88.88.88.03.
This now means that if caching had been purged or not yet set, then during the crawl the cache file image paths would now read:
- http://www.dodgysite.com/images/image1.jpg
- http:// www.dodgysite.com/images/image2.jpg
The malicious user then could do a rewrite rule on their server to redirect the particular URLS above to a Virus, Trojan or some other malicious script that would be then downloaded or executed on the user’s machine that was visiting your site.
Prevention
If you need to do something that requires checking against the current domain using $_SERVER variables then check against a whitelist of acceptable values and if it doesn’t match then default to the original domain. Have a value in the CONFIG file of the website and replace or echo using this and not $_SERVER e.g. define a constant define(‘MY_DOMAIN’,’www.myotherwebsite.com’);