Persistent CSRF and The Hotlink Hell

Mon, 16 Apr 2007 15:04:34 GMT

When we talk about CSRF we often assume that there is one kind only. After all, what else is in there when CSRF is all about making GET or POST requests on behalf of the victim? The victim needs to visit a page which launches the CSRF exploit. If the victim happens to have an established session with the exploited application, the attacker can perform the desired action like resetting the login credentials, for example.

However, CSRF can be as persistent as Persistent XSS (Cross-site Scripting) is and you don't need XSS to support it. Before delving into persistent CSRF's issues we need to look at a few other things that brought the idea on first place.

Hotlinking is the placing of a linked object, often an image, from one site into a web page belonging to a second site. The second site is said to have an inline link to the site where the object is located. Inline linking is also known as hotlinking, leeching, direct linking or bandwidth theft. Wikipedia

Those who have been active on the web for long enough probably know about what hotlinks are and how they have been abused to steal bandwidth. There is more into that however. Every time someone hotlinks, they instantly create a persistent CSRF hole. Here is how, as explained by a case study:

Bob hotlinked fred.com/image.jpg from his blog. Fred, who owned fred.com, saw the refers from Bob's blog going to that particular resource. Fred didn't like the idea of someone stealing his bandwidth so he decided to have some fun. With a few lines of mod_rewrite directives, Fred redirected all requests from fred.com/image.jpg to bob.com/action.php?logout. Because the resource that contained the hotlink to Fred's website appeared first in Bob's dashboard, Bob couldn't login, because every time he tried to, he got kicked out.

This simple example outlines the entire idea behind persistent CSRF. If you think that many applications are vulnerable to non-persistent CSRF, there are even more vulnerable to the persistent kind given that everyone today hotlinks in one way or another.

Web2.0 Mashups developers, in particular, needs to be very concious with persistent CSRF attacks. The whole idea behind Web2.0/3.0 (Semantic Web) is that people can share the same data while providing different interfaces which use the information in different ways. This is great in theory, but every time someone renders an image element, that is not inspected, a CSRF hole is left wide open. Let's take for example the popular Google Reader, my favourite online application. Google Reader, allows you to read feeds. These feeds can contain images, podcasts and screencasts. However, if any of these feeds contain an image that points to https://www.google.com/accounts/Logout?nui=1&service=reader&continue=http%3A%2F%2Fwww.google.com%2Freader%2F like this:

<img src="https://www.google.com/accounts/Logout?nui=1&service=reader&continue=http%3A%2F%2Fwww.google.com%2Freader%2F"/>

... upon previewing the feed, the user is automatically de-authenticated before having time to react. Everything will happen in the background. Moreover, the vector is persistent. The next time the user visits the malicious feed, they will be de-authenticated again.

Keep in mind that all I am demonstrating here is a CSRF that is mostly annoying rather then dangerous.

Wladimir PalantWladimir Palant
Nice idea! There is also a nice side-effect that you didn't mention. Conventional CSRF will leave traces in the logs because it will send Referer headers showing to the site the attack originated from. But if somebody is hotlinking to you and you make an HTTP redirect the Referer header will only show the site that contains the image, not the actual attacker. There are a few forums that annoy me by hotlinking to my images, maybe I should start being evil ;)
pdppdp
Wladimir, yes you are right. That will most definitely hide the referrer.
christ1anchrist1an
Nothing new of course but interesting though. Belongs to those things people tend to forget about.
pdppdp
CSRF in hotlinks is nothing new indeed, but we are changing the entire idea slightly so it fits to what is applicable today
zenozeno
If you think that many applications are vulnerable to non-persistent CSRF, there are even more vulnerable to the persistent kind. - PDP
I think you are confused in this sentence. An application vulnerable to CSRF is vulnerable regardless of the vector. The way in which the request is triggered to the vulnerable application has nothing to do being more or less vulnerable for persistent or non persistent. Regarding the RSS vector this was also discussed in my blackhat talk and whitepaper as a great CSRF vector. Paper: http://www.cgisecurity.com/papers/HackingFeeds.pdf Blackhat Slides: http://www.cgisecurity.com/papers/RSS-Security.ppt
DelixeDelixe
Seems fairly simple to fix for most CSRF. Just include a session variable in the GET/POST request and you won't be able to use CSRF attacks.
LuckyLucky
Long ago there were those who advocated that any web resource that TOOK AN ACTION should be activated by a POST, not a GET. I think this was one of the reasons. GETs should only display plain text, or the results of a query, but only POSTs can make changes. Not that it would be bulletproof, but it makes the attackers work a little harder.
Loup-VertLoup-Vert
Trying to think of ways to protect against this on (using your example's nomenclature) bob.com. I think this would be a way to protect against automated action, though it comes at cost of convenience to the user: Remove single-click actions. So, this page:
bob.com/action.php?logout
Would be replaced with this page:
bob.com/action.php?trylogout
Which dynamically creates a new link to actually logout:
bob.com/action.php?trylogout&token=randomjunk
If there's no token=randomjunk, trylogout flops. If I understand this attack correctly (I'm fairly new at web application security), then the intermediary page prevents the attack. Do you concur?
Anonymous CowardAnonymous Coward
Clever... and potentially very, very annoying.
santa claussanta claus
Great eye-opener! Fantastic Stuff!!
pdppdp
zeno, usually we make differentiations between persistent and non-persistent XSS. Usually, we find persistent XSS a lot more dangerous then non-persistent XSS. The same thing is applicable to CSRF. What is so confusing about it? Lucky, you are right but GET is easier to handle. For example, look how JSON and On-demand JavaScript operate:
<script type="text/javascript" src="http://example.com?updateInfo.asp?name=John&callback=myFunc">
the script above will update the name to John and return the updated record. Expect to see more of these REST interfaces. Anonymous Coward, thanks santa claus, thanks
zenozeno
usually we make differentiations between persistent and non-persistent XSS. Usually, we find persistent XSS a lot more dangerous then non-persistent XSS. The same thing is applicable to CSRF. What is so confusing about it?
CSRF isn't persistent verses non persistent like you are stating. It is a server side logical flaw PERIOD. It is exploited/triggered by a client side request. The way the request is embedded into the client may be via persistent/non persistent XSS, however it isn't persistent/non persistent CSRF.
pdppdp
zeno, I don't agree. There are a persistent and non-persistent CSRF vectors. What is persistency first of all? Isn't persistent XSS a vector that reoccurs every time a user arrives on a given web resource? The same is applicable to CSRF too.
Persistent CSRF is a vector that reoccurs every time a user visits a resource.
For example, the POC that I provided for Google Reader is persistent because every time the user visits the feed the exploit will be launched. IMHO, this is a persistent CSRF.
zenozeno
Yes the vector in which the attack is being embedded is persistent. That does NOT mean that the server side is more vulnerable as you stated. Quoting pdp
If you think that many applications are vulnerable to non-persistent CSRF, there are even more vulnerable to the persistent kind.
again
we find persistent XSS a lot more dangerous then non-persistent XSS. The same thing is applicable to CSRF. What is so confusing about it?
It simply means the attacker has a longer opportunity to launch the attack. This is NO different than if I embedded an img tag into a website. I'm not taking advantage of a persistent CSRF vuln in the site, I'm making the vector in which I launch the CSRF vuln persistent. One of the reasons I've chimed in is that the statement is inaccurate.
pdppdp
zeno,
That does NOT mean that the server side is more vulnerable as you stated.
of course it is more vulnerable. Think about it, the attacker does not need to social engineer the user every time the need to do something. The attack will happen on its own. Usually persistent XSS is rated as medium to high risk. The same thing should apply to persistent CSRF imho.
reznrezn
Hi PDP. This is an interesting topic that has been on my mind lately. I agree with the other commenter that 'Persistent CSRF' is a meaningless pharse. We are arguing semantics here, but this is what I am thinking. An application is 'vulnerable' to CSRF by just working in a browser. This is simply a fact of life of the architecture of HTTP and browsers. Cookies will be sent by the browser when it makes requests. Period. Maybe the browser tries to limit the requests it makes, but when it makes them, if it has cookies, they will be sent. There is nothing an application can do to prevent this. An application may have serious CSRF vulnerabilities if it allows for any type of state change to happen without taking some kind of precautions - like including a nonce, captcha, or some other device designed to make sure that the legitamate user actually is the one initiating these requests. What you describe is a persistent vector for CSRF. Just because I can send your browser to a URL, does not mean that the URL will do anything. It is independent of the actual CSRF problem that will be exploited. In persistent XSS, if you fix the problem by using proper input validation or output encoding, then you have fixed the problem. With persistent CSRF (as you call it), both the vector (the image src that is under an attackers control) and the actual CSRF vuln (the request that gets submitted) need to be fixed independently. The interesting thing is that the commercial web application scanners have recently started looking for places where they can control the source of an image tag, and they call any such situation "CSRF". I disagree, for the reasons stated above. It is simply a vector through which CSRF -may- be exploited. By itself, however, it is not a CSRF vulnerability. It is a 'force the user's browser to do a GET' vulnerability. They are not the same thing.
austinaustin
i had this problem, here is how i got around it: if the source refered to my site, and wasnt a part of the site i have set aside for media...dont allow it. another step is to get the headers from any image before putting it out (in php) if it redirects, block it. this way they cant redirect a valid image back to my server