Two Vulnerabilities in Oxford's WebLearn System
Posted 2015/02/27. Last updated 2015/02/27.
Introduction
When I came to Oxford for my PhD (or "DPhil" as it is called here), I found out that course materials, assignments, and announcements are all handled through a system called WebLearn, which in many respects is similar to the Moodle and Blackboard platforms that I've used elsewhere. Unlike these platforms, however, WebLearn is developed in-house by Oxford's IT department, but it is powered by an open-source project, called Sakai, written mostly in Java. Given that my focus is security (though not web-application security), and that I enjoy finding bugs, I thought I'd poke around and see what's broken. By combining a Cross-Site Request Forgery (CSRF) vulnerability and a Referrer leak, I was able to update other people's statuses provided they just clicked on my link.
Part 1 - CSRF with a Caveat
WebLearn has a profile section which allows you to add "connections" and post profile statuses on your "wall" and the wall of others (who do not necessarily need to be your connection). This makes it an attractive target! Firing up the web developer console to monitor the network requests while posting a few test "profile updates" indicates that the format of the URL is consistently of the form https://base-url/GUID/?fixed-params&random=RANDOM
. The RANDOM
part changes with every request, but the Globally Unique Identifier part of the URL is the same, and some further testing illustrates that this is a unique identifier for each user account. The POST request also contains 3 hidden parameters, one for the submission, one for the message to be posted, and one of the form idX_hf_0
, where X
is between 1 and 2 hexadecimal digits.
These three values (X
, RANDOM
, and GUID
) should be enough for CSRF protection, though, right? Well... It turns out that the RANDOM
nonce and the hexadecimal digit X
are not really used, so they can be set to any value or even be omitted. As for the GUID
, read on.
Part 2 - Recovering the GUID
Even though GUIDs appear all over the place on WebLearn, and even if one's profile page is visible to others, it appears that public GUIDs are different from the GUIDs that are used in the requests mentioned above. But don't despair! It turns out that even if the URL displayed is different, the profile tool is in an iframe
which contains the correct GUID as part of its URL. Of course, you cannot ask someone to open the tool in a new tab and give you the 32 hyphen-separated hex digits, so we need a better solution.
What if the GUID leaked somehow? Once again, WebLearn has some protections, but they are insufficient. Specifically, clicking a link on your wall has different behaviors based on the protocol: even though going to an HTTP site does not reveal anything, going over HTTPS leaks the full profile URL (containing the GUID) in the Referer [sic] header.
The Exploit in Practice
Combining the two vulnerabilities means that if you post a link to an HTTPS website you control on someone's wall and they click it, you can automatically update their profile status! I asked my friend Matt to try it out for me with the results shown below. Success! Though this is indeed a hard vulnerability to exploit (even if you get the GUID elsewhere, the "victims" must have visited their wall in their current session), I have removed the exploit code (and all traces of it) as explained below.
Responsible Disclosure
I notified the WebLearn team on 17 October 2014, with the vulnerability acknowledged on the 23rd. Given that the issue reported is hard to exploit, I expected a shrug-off, but to their credit, the WebLearn team asked me to wait as they contacted Sakai and were patching issues on their end. I followed up on 18 January 2015, and after some discussion, I was informed that Profile statuses would be disabled in the next release, which ended up being the 23rd of February.
The fix simply removed the "status" part of the profile tool (which says "CSRF IS BAD on Monday" in the picture above), but did not address the heart of the issue. Since the wall is not disabled, I can still get the Referrer as above, and with a simple change to the code, I can post on other people's walls as them. That being said, I have not made the exploit code public given that the vulnerability is not really patched, though the code is trivial to reproduce.
Conclusion
Though a static GUID is not the best way to prevent CSRF attacks (see OWASP for better alternatives), it would still work provided that it is not recoverable or guessable. Because of the way WebLearn is built, preventing the referrer leak seems like an easier solution, for instance using W3C's Referrer Policy, which Firefox has recently implemented and Chrome and Safari have supported for a while. Of course, actually using the random parameters present in requests could also help!
I believe that I have done my due diligence for responsible disclosure having waited for over 4 months and having kept in touch with the WebLearn team to ensure a timely fix. Given the difficulty in exploiting the vulnerability and how institution-specific it is, I am happy that the WebLearn team considered it seriously, even if the fix was unsatisfactory. Though it is unclear to me what the value of the status/wall tool is, it reinforces the idea that the more complicated an application is, the harder it is to secure it, especially if you accept user-generated content. And, as always, don't click suspicious links, etc.!