generated from cotes2020/chirpy-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create 2023-11-13-Discourse CVE-2023-47119 - Building a CVE POC from …
…commits changes.md
- Loading branch information
Showing
1 changed file
with
171 additions
and
0 deletions.
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
...023-11-13-Discourse CVE-2023-47119 - Building a CVE POC from commits changes.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |