Rocket.Chat · Report #1132202
Post-Auth Stored XSS with User Interaction leads to Remote Code Execution
How it was found
Summary:
Unsafe usage of the toastr library leads to Stored XSS when combined with a validation bypass in the createRoom function. Targeting an admin account leads to Remote Code Execution.
Description:
The frontend uses the toastr library to display error messages to the user. However, it is used in an unsafe way which allows XSS when user input is reflected in an API error message. This happens for example when channel info is edited and the channel's name contains invalid characters.
To abuse this, an attacker can use a validation bypass in the createRoom function: the extraData parameter is merged with the room object without proper validation, which allows an attacker to override all previous properties such as the name or the owner. The attacker can use this to create a room that contains their XSS payload in the room's name.
Triggering the XSS requires multiple steps of user interaction, because there are few API endpoints that reflect user input back. One of them is the rooms.saveRoomSettings endpoint which calls the saveRoomSettings method which in turn uses the getValidRoomName function. This function checks the room's name and reflects the user-provided value back if it is not a valid name.
The error returned by the API is unsafely handled by passing it to the toastr library without escaping it or using the library's escapeHtml option. The handleError function passes the value to the toastr library, it escapes the details property but not the message and title property.
To gain Remote Code Execution capabilities on the server, an attacker can follow these steps to take over an admin account. The attacker can then use the newly gained admin privileges to create an incoming web hook that has a script. This allows them to execute commands or get a shell on the server, because the script is executed on the server without a security boundary in place (which seems to be intended).
Note: This issue is classified as Stored XSS because the payload is stored permanently in the database, but it could be argued that it is Reflected XSS because the payload is reflected by the API which then leads to the unsafe handling and execution of the payload.
Releases Affected:
We tested on 3.12.1, but it is hard to confirm since when Rocket.Chat is vulnerable because there are many parts of the code base involved.
Steps To Reproduce (from initial installation to vulnerability):
- Set up an instance of RocketChat 3.12.1, e.g. by cloning the repo and using Docker Compose:
git clone [email protected]:RocketChat/Rocket.Chat.gitcd Rocket.Chatgit checkout tags/3.12.1docker-compose up -d- Configure the instance with default settings
- Create a normal (non-admin) user with username
attackerand passwordattacker - Log in as the
attackeruser - Open the browser's developer tools and execute the following line of code:
Meteor.call('createChannel', 'valid-name', [], false, {}, { name: 'edit me <img src onerror=alert(origin)>' }) - Invite the admin to the newly created channel
- Log out and log in as an admin
- Edit the title of the newly created channel (e.g. change
metoyou) - Click the save button
- A dialog should pop up that shows the site's origin (e.g. http://localhost:3000), confirming that the XSS payload has been executed (this is only for the demo, the payload can be arbitrary JavaScript code)
- (The demo ends here but it is trivial to get RCE capabilities when having access to an admin account, as explained before)
Supporting Material/References:
The attached video shows the exploitation of the vulnerability with the attacker's view on the right and the victim's view (admin) on the left.
Suggested mitigation
- Restrict and validate the
extraDataparameter when creating a room - Use the
toastrlibrary with theescapeHtmloption or sanitize the message and title manually - Set a
Content-Security-Policyheader that prevents payload execution- preventing inline scripts might not be enough here because users can upload files
- a nonce-based CSP would fit best
Disclosure Policy
All reported issues are subject to a 90 day disclosure deadline. After 90 days elapse, parts of the bug report will become visible to the public.
Don't hesitate to ask if you have any questions or need further help with this issue.
Impact
An attacker can use this vulnerability to target an admin user and take over their account, which is already a high impact. The attacker can then use certain features that are available to admins in order to gain Remote Code Execution capabilities.
This gives them complete control over the Rocket.Chat instance and exposes all attached components, e.g. the database or any external system whose credentials are stored within Rocket.Chat settings. An attacker can read, change, or delete all items in the database, impacting confidentiality, integrity, and availability.