CVE-2019 – 18347 Persistent Cross-Site Scripting (XSS) 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
— Cross-Site Request ForgeryCVE-2019-18347
— (this advisory) Persistent Cross-Site Scripting
CVE Reference | CVE-2019-18347 |
CVSS score | 9.9 |
CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/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 does not validate user input like email addresses, usernames and display names. In addition, the web application does not encode these user input when echoing them to in the web pages. An attack with a low privileged account can exploit these issues to execute a Persistent Cross-site Scripting (XSS) attack.
POC URL: http://davical.host/admin.php?action=edit&t=principal&id=1
Place a XSS payload in the username or fullname field:
Impact
An attacker can use XSS to send a malicious JavaScript to an unsuspecting user. The end user’s browser has no way to know that the script should not be trusted, and will execute the script. Because the browser thinks the script came from a trusted source, the malicious JavaScript can access session tokens (without the HttpOnly
flag) or other sensitive information retained by the browser and used with that site in the context of the victim.
If the user is administrator, the attacker can for example change the password of the user to take over the account and gain full access to the application.
In this case, because the Javascript is stored in the database and included in pages others can open, it can be used by one user to attack other users on the same system.
Combined with a CSRF attack (see CVE-2019 – 18346) it is possible to attack users from the outside as well, if an authenticated DAViCal user visits the attacker’s web site.
Solution
Update to version 1.1.9.2
Technical solution details
XSS vulnerabilities are a problem with dynamically generated websites that use user input. If user input is not correctly sanitized you could very well end up with a user pushing some Javascript to your frontend.
XSS isn’t a vulnerability that’s hard to grasp or circumvent but it’s awfully easy to make a mistake like that. One thing you’ll hear over and over again is never to trust user input. Always sanitize it when it comes in and it’s best to still not trust it then. Characters like <
, >
and "
should never be rawly echoed to the frontend. The use cases for echoing user input back to the frontend are endless. From a simple Greetings, $username
to editing personal user information with the form having all the fields already filled in. So when someone has a quote in their name, you shouldn’t echo the raw quote but "
.
These days web frameworks handle a lot of sanitation for us. Laravel for example uses simple brackets to echo variables to the user all these variables are escaped first: {{ $username }}
. Twig does something similar by using a pipe like syntax: {{ $username | escape}}
.
These days when developing your application you need to make sure you sanitize everything you output to the user. But since DAViCal is an established project it’s not doable to sift through the code to look for functions that output text to the frontend. Another problem was that DAViCal dynamically adds GET
parameters to echoed urls. This is why I chose to sanitize both incoming variables and their names. In the DAViCal always.php
I added a function that loops through the $_GET
and $_POST
array recursively (as arrays can contain arrays and so forth) and run the names and variables through htmlspecialchars()
except for the password field which of course should be able to have special characters in them.
The reason you don’t do it this way in new applications is because now if for some reason someone has another way of interacting with your application (by API calls for example) you’d have to sanitize your input on both sides. Moreover, APIs that pass JSON objects around for example, don’t need to have script tags encoded as it means nothing to them and JSON objects are encoded in a different way. In this case however, DAViCal doesn’t have other entry points which you can use to insert data in the database. So sanitizing all input once will suffice!
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 |