CVE-2019 – 18346 Cross-Site Request Forgery (CSRF) vulnerability in DAViCal CalDAV Server
At HackDefense, we were evaluating various calendaring solutions, and during installation and configuration of DAViCal we discovered three (severe) vulnerabilities. We reported these vulnerabilities to the vendor. Unfortunately, the DAViCal project itself was not able to fix these vulnerabilities. As DAViCal is an open source project we decided to contribute patches for these vulnerabilities ourselves. DAViCal has accepted our patches in the 1.1.9.2 release. If you use DAViCal as a calendaring server, we recommend upgrading to version 1.1.9.2 immediately to remediate the issues we’ve discovered.
All three vulnerabilities exist in the web-based management pages that come with DAViCal. We have written three separate advisories to describe the vulnerabilities:
-
CVE-2019-18345
— Reflected Cross-Site Scripting CVE-2019-18346
– (this advisory) Cross-Site Request ForgeryCVE-2019-18347
– Persistent Cross-Site Scripting
CVE Reference | CVE-2019-18346 |
CVSS score | 8.8 |
CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
About DAViCal
DAViCal is a server for calendar sharing. It is an implementation of the CalDAV protocol which is designed for storing calendaring resources on a remote shared server. It can be used by various e‑mail and calendaring clients to centrally store and share calendars.
It includes a web-based management application. It was in these pages that we discovered this vulnerability.
Affected systems
DAViCal CalDAV Server 1.1.8 and prior
Overview
The application has no protection against CSRF attacks. If an authenticated user visits an attacker-controlled webpage (for example, in another browser tab), the attacker can send arbitrary requests in the name of the user to the application, including requests that result in a state change.
For example, if an attacker includes the following HTML code on his/her site and an authenticated DAViCal administrator visits, a new administrative account “hacker” (password also “hacker”) will automatically be created in the background, giving the attacker full access to the calendaring application:
Impact
In a successful CSRF attack, the attacker can change the e‑mail address and password on a victim’s account, which results in a full account takeover. If the compromised user has a privileged (administrator) role within the application, then the attacker is also able to add a new administrator user.
Solution
Update to version 1.1.9.2
Technical solution details
The most robust way to defend against CSRF attacks is to include a CSRF token within relevant requests. The idea is that you assign a unique token to a user’s session, this token can be regenerated whenever but this usually happens when a new session is created (e.g.when the user logs out and logs back in). This token is then required to be sent along with the rest of the data you want to submit. Prior to performing the action the called route is supposed to perform(let’s say you want to update your user information) the application will check if a CSRF token is present and whether it’s the right one. Once those two checks pass the application will continue executing.
So the first task was to write a library that would generate a CSRF token and attach it to the session. That’s all pretty basic, the only thing I had to take into account is that the current requirement for DAViCal is PHP 5.6.0 and up so I had to keep backwards compatibility in mind. The token is generated by a random number generator (which one is decided by the current PHP version) and then assigned to the user. Once that was done the only thing left is to make sure every information altering request verifies the CSRF token.
The modern way most web frameworks will handle this is by using middleware. Let’s say you map a route to a function in your code,you can then put a CSRF middleware in the middle of that ‘mapping’. So let’s say you’ve got the following mapping:
‘/user/information/update’> updateUserInformation();
You’d then tell your framework to use a CSRF middleware which would change the flow to:
‘/user/information/update’> checkCSRF(); > updateUserInformation();
DAViCal however is quite an old project (the copyright states 2006 as starting year) and we don’t have the luxury of a framework handling these things for us. The easiest solution is to find every place a POST
request is made and manually verifying the token at those places. But I was keen to find out if there was a more central place I could put the CSRF verifying function. As every developer will know, getting to know and understand someone else’s code can be quite a tough one. I found myself using xdebug
quite a lot to figure out the flow of the application until something quite obvious became apparent. There is a PHP file in the project called ‘always.php’ which always runs. This file can be used to launch a function on every page load. This is where I added a function to check the CSRF token on POST requests (which are used in DAViCal to alter information).
The final act was adding the CSRF tokens to all the forms in DAViCal which could be easily found by searching for </form>
. Which concluded the fix for the CSRF vulnerability in DAViCal.
Responsible Disclosure timeline
4-Jan-2019 | Reported to the DAViCal CalDAV Server project (no response) |
21-Jan-2019 | Reported to the DAViCal CalDAV Server project again |
22-Jan-2019 | Report acknowledged |
28-May-2019 | Asked for an update regarding these vulnerabilities |
29-May-2019 | The DAViCal project responded that they did not have resources to implement a fix for these vulnerabilities |
31-May-2019 | Partnered up with Niels van Gijzen to contribute a patch |
24-Oct-2019 | CVE-2019-18345, CVE-2019-18346 and CVE-2019-18347 were assigned to these vulnerabilities |
25-Oct-2019 | Released a patch that fixes these vulnerabilities |
29-Nov-2019 | DAViCal verified the patch |
03-Dec-2019 | DAViCal released version 1.1.9.1 including our patch |
11-Dec-2019 | DAViCal released version 1.1.9.2 correcting a small oversight |