Skip to content

Commit

Permalink
Create 2023-11-13-Discourse CVE-2023-47119 - Building a CVE POC from …
Browse files Browse the repository at this point in the history
…commits changes.md
  • Loading branch information
BaadMaro authored Nov 13, 2023
1 parent 08be465 commit b88979a
Showing 1 changed file with 171 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---

layout: post

title: Discourse CVE-2023-47119 - Building a CVE POC from commits changes

categories: [Web]

tags: [Discourse]

author:

name: BaadMaro

link: https://baadmaro.github.io

image: /assets/img/posts/discourse-cve.jpg

---

# Introduction

I was checking for some Discourse vulnerabilities, and I saw that a new CVE was dropped on `11/10/2023` [CVE-2023-47119](https://nvd.nist.gov/vuln/detail/CVE-2023-47119)

The details didn't mention any POC, so I did some analysis based on the source code commits changes to understand the vulnerability and how it is possible to exploit it.

The article includes details, lab setup and a demo.

A GitHub repository was created for the POC https://github.com/BaadMaro/CVE-2023-47119 Feel free to contribute with reports, escalations, and links to other POCs too.

# CVE-2023-47119

CVE-2023-47119 is a new Discourse vulnerability affecting versions prior to version 3.1.3 of the `stable` branch and version 3.2.0.beta3 of the `beta` and `tests-passed` branches. Some links can inject arbitrary HTML tags when rendered through the Onebox engine.

The severity is `Medium 5.3` which is understandable as the vulnerability is only HTML injection and it needs a bypass for the [XSS filter](https://github.com/discourse/discourse/blob/main/docs/SECURITY.md#xss) used by Discourse to cause a bigger impact.

Checking the CVE details [CVE-2023-47119](https://nvd.nist.gov/vuln/detail/CVE-2023-47119), we can see the commits added for the fix for example this one : https://github.com/discourse/discourse/commit/628b293ff53fb617b3464dd27268aec84388cc09

The interesting part is the fix for the `github_issue_onebox.rb` file which reveals our target.

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/08cbed3c-2600-499e-9cf6-68a263b9c56a)

As we can see :
- The bug is affecting `/lib/onebox/engine/github_issue_onebox.rb`
- An escape was added to the value of GitHub issue label.
- If we check the details of the file, we can see an emoji converter that converts the emoji code to an image. The code is described in `/app/helpers/emoji_helper.rb` which is a call for `/app/models/emoji.rb`

```ruby
module EmojiHelper
def emoji_codes_to_img(str)
raw(Emoji.codes_to_img(str))
end
end
```

```ruby
def self.codes_to_img(str)
return if str.blank?

str =
str.gsub(/:([\w\-+]*(?::t\d)?):/) do |name|
code = $1

if code && Emoji.custom?(code)
emoji = Emoji[code]
"<img src=\"#{emoji.url}\" title=\"#{code}\" class=\"emoji\" alt=\"#{code}\" loading=\"lazy\" width=\"20\" height=\"20\">"
elsif code && Emoji.exists?(code)
"<img src=\"#{Emoji.url_for(code)}\" title=\"#{code}\" class=\"emoji\" alt=\"#{code}\" loading=\"lazy\" width=\"20\" height=\"20\">"
else
name
end
end
```

The function returns an image HTML element for known emojis, and if it doesn't exist, it retursn the same text used.

In `/lib/onebox/engine/github_issue_onebox.rb` before the fix, we can see the emoji function is used in label part :

```ruby
labels = raw["labels"].map { |l| { name: Emoji.codes_to_img(l["name"]) } }
```

The label is an identifier used by Github issues to specify, for example the type of issue.

In Discourse, the onboxe engine used for topic details and replies have a custom engine for GitHub issues which pulls the issue details via URL and converts them to a better view.

# Lab setup

To build Discourse 3.1.3 which is a vulnerable version, I used the docker compose file by bitnami
https://hub.docker.com/r/bitnami/discourse/
- docker-compose.yml : https://raw.githubusercontent.com/bitnami/containers/main/bitnami/discourse/docker-compose.yml
- Modify the 2 images tag to 3.1.3 or any other vulnerable version `docker.io/bitnami/discourse:3.1.3`
- Change host to your preferred config like 0.0.0.0 or your internal network IP address `DISCOURSE_HOST=0.0.0.0`
- You can also modify the port 80
- After modifying the file, run `docker-compose up -d`
- Few minutes you'll be able to see the discourse web server at your host port 80
- App default login `user:bitnami123`

You can also use the official docker https://github.com/discourse/discourse_docker

# Demo

To control the label name, we can create a repository with an issue and modify the label name assigned to the issue.

Example

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/0642ad14-f655-49f0-a829-dddc7077a239)

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/0fafa829-0a29-4e57-96da-0b30cc169e75)

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/48505b56-c263-4bae-8960-7d0812cccaf1)

In this example, the issue label was "bug". We can now try including an emoji like `:smile:`

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/6211c4ca-f0c1-4857-87a2-1168dce2cf3e)

```html
<span style="display:inline-block;margin-top:2px;background-color: #B8B8B8;padding: 2px;border-radius: 4px;color: #fff;margin-left: 3px;">
bug <img src="/images/emoji/twitter/smile.png?v=12" title="smile" class="emoji" alt="smile" width="20" height="20">
</span>
```

As we can see, it's the same discussed output from the emoji function.

Now let's confirm a no-existing emoji

![image](https://github.com/BaadMaro/baadmaro.github.io/assets/72421091/ff0b01a4-7240-4acd-bcba-07a69ce5066c)

```html
<span style="display:inline-block;margin-top:2px;background-color: #B8B8B8;padding: 2px;border-radius: 4px;color: #fff;margin-left: 3px;">
bug :baadmaroemoji:
</span>
```

As the emoji function didn't find the emoji, it returned the original text.

The returned text is not sanitized (emoji format or just simple text) which is the cause of the CVE.

We can confirm by injecting an **h1** tag for example. **Having the double ":" in label name is not necessary**

![image](https://github.com/BaadMaro/CVE-2023-47119/assets/72421091/b572c978-895e-4ec5-b223-4fc0da05f17f)

![image](https://github.com/BaadMaro/CVE-2023-47119/assets/72421091/28cae5f3-89e4-4ed6-9ddf-d6f702b17457)

![image](https://github.com/BaadMaro/CVE-2023-47119/assets/72421091/cdac2e11-5932-48fb-b3a5-4a5dc83741a1)

```html
<span style="display:inline-block;margin-top:2px;background-color: #B8B8B8;padding: 2px;border-radius: 4px;color: #fff;margin-left: 3px;">
bug <h1>BaadMaro HTML Injection POC</h1>
</span>
```

# XSS Filters

https://github.com/discourse/discourse/blob/main/docs/SECURITY.md#xss

Discourse is using some mechanisms to protect against XSS :
- Node module `xss` https://jsxss.com/en/index.html
- Server side allow list sanitizer using the [Sanitize gem](https://github.com/rgrove/sanitize). See the [relevant Discourse code](https://github.com/discourse/discourse/blob/main/lib/pretty_text.rb).
- Titles and all other places where non-admins can enter code are protected either using the Handlebars library or standard Rails XSS protection.
- CSP

So to be able to escalate the CVE from HTML injection to XSS, you need a bypass for the used filters.

# Conclusion

A GitHub repository was created for the POC : https://github.com/BaadMaro/CVE-2023-47119

You can contribute to the repository with reports, escalations and links to other POCs too.

Thank you.

0 comments on commit b88979a

Please sign in to comment.