Stored XSS in Schoology
Schoology is an educational platform similar to Blackboard, Moodle, and Edmodo, that aims to coordinate the educational “full stack” with built-in grading, assignments, tests, discussions, and club pages. They claim to have “7.5 million users across 60,000 schools in about 200 countries”, so take that as you will.
The bug lies in Schoology’s class and group discussion posts, which may be rich text formatted.
This editor, based on tinymce, is little more than an
iframe containing a
contenteditable body and some controls to insert elements. Example:
It turns out, you can add whatever HTML you want to this iframe, and Schoology will accept it after doing some weak filtering and sanitization.
Injecting a plain
<script> tag doesn’t work, and neither do all the filter evasion techniques I know (this might say more about my own inexperience than Schoology’s security). They appear to be disabling any
<script> tags by setting its
// <![CDATA[ ... // ]]>. I’m not entirely convinced this is secure, and there may be a way to break it.
In addition, event handlers like
onmouseover are stripped out, meaning we can’t craft a clever attack that way either.
However, those event handlers still persist within the editor itself, even if they end up stripped out when published. In addition, we can insert iframes, meaning if we don’t care about getting user data, and instead only want to cause some trouble or mine cryptocurrency, it’s possible.
Even though these handlers disappear in the final output, the HTML you submit gets rehydrated in the editor any time someone edits the post at a later date, and the event handlers stick around. This means you can attach an
onmouseoverevent to the text, and the next time anyone edits your post, they will run your payload. The bonus is that users who have the permissions to edit your post are typically high value targets: club leaders, administrators, and teachers.
iframes let you run any code you want, at the cost of accessing Schoology’s API or the user’s cookies. They are likely allowed in order to enable embedding YouTube videos, but we can use them for our own benefit, and as you’ll see, there are many potential applications for this.
Running a crypto miner like Coinhive is trivial, and because posts show up on both the user’s main dashboard as well as on the club’s page, there is plenty of time for the miner to run. After a few days of testing, I was able to collect a few cents of revenue from my club’s members :)
More worrying, by accessing
window.top, we can redirect the user anywhere we want! All we need is an iframe whose contents contains something like
window.top.location.href = "http://example.com/"
Some advertisements use this method to redirect the entire page to a spam site, but we can use this to phish users very convincingly by directing them to a faked Google OAuth page or Schoology login page. This is easily fixed by using the
sandbox property and disallowing
window.top, one can deny access to Schoology’s main page, which makes it impossible for someone to delete the post, edit it, or leave the group.
alert inside any level of nesting within an iframe will still show up in the top level window, meaning we can alert a message any time someone loads the page.
While I haven’t found any CSRF bugs in Schoology (yet), an iframe hidden in a post would be a great place put it. We can guarantee that anyone who loads it is both part of the organization and logged in.
Thank you for taking the time to contact the Schoology Help Desk regarding this issue.
Unfortunately, while we greatly appreciate any help of this nature from users, we do not currently offer a bug bounty. Thank you for providing us this information and rest assured that I’ll pass it along to our Engineering team.
If you have any questions regarding this process, please let me know. I’m happy to help!
At the time of writing, this bug has not been fixed.