Obtaining XSS Using Moodle Features and Minor Bugs
A while ago I came across some interesting techniques for exploiting self-XSS in combination with other issues, so when I noticed the following in a Moodle security announcement I was very interested:
Authenticated user[sic] are allowed to add HTML blocks containing scripts to their Dashboard and this is normally not a security issue because personal dashboard is visible to this user only.
Double Session Cookies
The method I came up with takes advantage of the way that PHP and browsers treat multiple cookies with the same name.
I found that if two session cookies are sent in a request to Moodle, the first session cookie which appears in the Cookie header is used, while the second is ignored. So, in the request below, the session cookie highlighted in bold is used to identify the logged in user, while the other session cookie of the same name is ignored:
GET /my/ HTTP/1.1
Cookie: MoodleSession=0ab0af2b5369369af1fae6b097cf64f7; MoodleSession=d879cda2c1b27a4eefa02e7a48a63d73
This is a result of PHP’s behaviour for handling multiple cookies, which leads to only the first cookie being present in the $_COOKIE superglobal.
Chrome and Firefox¹ will generate a request containing duplicate cookies, such as the one above, when different values of the same cookie are set with different paths. So, say there are two cookies are set in the browser:
- a cookie named MoodleSession with a path of / containing a session identifier associated with Alice’s account; and
- a cookie named MoodleSession with a path of /my/ containing a session identifier associated with Bob’s account.
This will lead to only Alice’s session cookie being sent in requests to paths outside of /my/, and both session cookies being sent in requests to /my/, which is the path of the user’s dashboard in Moodle. It appears that both Chrome and Firefox will send cookies with more restrictive paths first, so Bob’s session cookie will be the one sent first, and hence used by Moodle, when the browser requests /my/. A user of this browser will see all of the site as though they are logged in as Alice, apart from /my/, which will show Bob’s dashboard.
First the attacker embeds a script such as the one from the GitHub repository, part of which is shown below, in their dashboard. This is most easily done by adding a new HTML block and using an intercepting proxy such as BurpSuite.
This script will check if a cookie named poisoned is set in the browser. If it is not, it will set this cookie, and requests a session cookie belonging to the attacker account from the cookie.php script² which it then puts in the MoodleSession cookie with a path of /my/. The script then causes a logout from the attacker account, which does not invalidate the newly set session cookie as it involves requests to path outside of /my/.
If the poisoned cookie is present then the script will execute the final XSS payload, which I will discuss later.
The attacker now targets their victim user, in this case the owner of the admin account, with a simple login CSRF payload such as the one below which logs the victim in to the attacker account.
This will cause the victim to view the dashboard of the attacker account, and the script from the previous subsection to be run in their browser. The victim will then have the poisoned cookie and a session cookie belonging to the attacker account set in their browser with a path of /my/, following which they will be logged out.
The next time the victim logs in to the admin account in the same browser, they will be able to browse all of the Moodle installation apart from their dashboard, including the admin panel, as normal. However, the request to /my/ to load their dashboard will return the dashboard of the attacker account with the included script. This script performs the second stage of the attack due to the presence of the poisoned cookie in the browser.
3. Final payload
Using the Impersonation Functionality
Initially, Moodle only fixed the CSRF on the login form, though this still allowed the issue to be exploited using Moodle’s impersonation functionality instead. Rather than exploiting login CSRF, an attacker would have to convince an administrator to impersonate their account, causing the administrator to view the attacker’s dashboard. The exact same scripts are then used to exploit this issue.
2018–08–18: Issue reported to Moodle with details of exploiting using login CSRF.
2018–08–25: Details of exploiting using impersonation functionality added to issue.
2018–10–25: Asked to create a separate ticket for the exploitation using the impersonation functionality.
2018–11–12: Login CSRF patched (Moodle versions 3.1.15, 3.3.9, 3.4.6, 3.5.3). CVE-2018–16854 and MSA-18-0020 assigned.
¹ Other browsers untested.
³ Again this needs to be returned with the Access-Control-Allow-Origin: * header.