AppSec : Discrepency of behaviour between Markdown and Discord's preview bot allows clickjacking
Working from a known bug
I've come accross a bug that has been fix since which consisted of spamming Markdown's pipe characters '|'
in between two urls. This would trigger the preview to generate an embbed for the second url and not the second.
Example of pipe glitched message
http://lenoctambule.dev |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| _ _ _ _ _ _ http://youtube.com
This bug seems overly long and definitely could do some digging because the mechanism does not seem to be understood as it still has not been fixed.
So my goal is just to reverse engineer the embedding mechanism and craft a payload that is significantly shorter and it's even better if we manage to make it malicious. :3
Reverse engineering
I've tried manually fuzzing for possible weird interactions between the Preview Bot and Markdown that could lead to the embedding bug that we've seen previously. And one of the characters that exhibit strange behaviour with URLs is the backticks '`'
used for inline code blocks as seen below.
Example of strange behaviour
http://www.youtube.com`this_is_weird`
The Discord regex used to dispatch embedding tasks to preview bots by detecting URLs seems to correctly parse the URL and visit youtube.com but not the blue link above it which seem to include invalid characters inside of the host part of the URL.Thus, why the message above will correctly generate an embedding for youtube.com but the "raw" URL is just malformed and will lead nowhere.
We can easily guess why it behaves that way because the bug can only occur if the regex used to dispatch embeddings correctly follows the RFC1034 regarding domain names but not the one that handles wrapping it into <a>
tags
Making it malicious
Given the fact that the regex used for "blue linking" does not follow the RFC, there are many more places where it does not behave in the standard way. So in order to make it malicious, we can probably take advantage of that fact.
RFC1738's Section 3.1 specifies that we should be able to pass credentials in the URL (eg. http://login:password@website.com
). We'll not use it as intended obviously and use it instead to make the blue-link URL land us somewhere. To do so we'll add the @ after a quote block '`a`'
in order to tell our browser that the domain actually starts here.
And voila ! a fake imbed that is probably hundreds of characters shorter than the pipe based bug.
Example of fake embed
https://youtube.com`.`@www.google.com/?
And this will be rendered like this :
Final touches
However, this is still not satisfying as the blue link is still obvious and homographic domain names are not cheap. So in order to catter to this, we'll use Markdown formatting in order to modify the appearance of our blue link by using [<text>](<url>)
.
Our main issue though is that the engineers at Discord have thought about this and decided to ignore links where <text>
is a URL. So instead, to bypass this we'll divide and conquer by splitting the URL into two parts where the first will contain the first letter and the second the rest of our URL.
Which will give us the following malicious link :
[h]( https://paypal.com`@youtu.be/dQw4w9WgXcQ` )[ttps://paypal.com/free-money]( https://paypal.com`@youtu.be/dQw4w9WgXcQ` )
And this will generate the follwing link which honestly even I, It's creator, would fall for if I don't pay attention.
See ? No homograph domain name needed :D
Where it actually leads to :DD
Disclosure
The vulnerability has been disclosed to Discord. The bug has been considered a duplicate and no fix has been planned as they have no legal liability if it is exploited. As if it can't fixed, the bug should be publicly known.