Impact
The SQL injection vulnerability can be exploited as an unauthenticated attacker via CSRF or as a user of the role Publisher. An attacker is able to execute stacked SQL queries which means it is possible to manipulate arbitrary database entries and even execute shell commands when the H2 database is used.
Technical Analysis
dotCMS has a feature called Push Publishing which allows remotely publishing content from one server to another, e.g. from a test environment to a productive environment. Also, a user can add multiple contents to a bundle and push this bundle instead of pushing the content separately. An attacker can exploit this feature by pushing a bundle to the publishing queue and injecting SQL syntax.
A classical SQL Injection
The unpushed bundles can be viewed through the view_unpushed_bundles.jsp
file. The following code snippet shows the entry point for an attacker: the vulnerable function deleteEndPointById()
is called. As a prerequisite, an unpushed bundle needs to be present in the publishing queue because otherwise, the execution will not reach the function call in line 7. However, as a publisher, we can simply push a bundle to the queue. The unsanitized user input is received in line 6 through the HTTP GET or POST parameter delEp that is passed to the function deleteEndPointById()
as argument id
.
html/portlet/ext/contentlet/publishing/view_unpushed_bundles.jsp
The function deleteEndPointById()
then calls the function completeDiscardConflicts()
. It passes along the unsanitzied user input as parameter id
.
com.dotcms.publisher.endpoint.business.PublishingEndPointAPIImpl
The trace can be followed to the function discardConflicts()
(see the following Listing) where the user input is concatenated into a DELETE
query via the parameter endpointId
in line 5. No input sanitization or prepared statement is used and an attacker can inject arbitrary SQL syntax into the existing SQL query.
com.dotcms.integritycheckers.AbstractIntegrityChecker
The following Listing shows the function executeStatement()
of the class DotConnect
where the tainted string SQL
is executed with java.sql.Statement.execute
. Interesting to mention is that this function allows the execution of stacked queries. This means we can successively execute arbitrary SQL commands. Unfortunately, we do not directly receive the output of the executed command. However, until here we can read the contents of the database through blind exploitation either time-based or error-based or manipulate arbitrary database entries.
com.dotmarketing.common.db.DotConnect
The initial JSP file that can be used to trigger the SQL injection is not protected by CSRF tokens. As a result, this SQL injection vulnerability can be exploited by an unauthenticated attacker if he tricks a publisher to visit an attacker-controlled website.
Exploiting H2 SQL Injection
DotCMS is shipped with the H2 database by default. After some research, we found out that H2 allows the definition of functions aliases and therefore the execution of Java code. The following listing shows a sample query that creates a function alias called REVERSE
. It contains our Java code payload. We can then call this alias with the CALL
statement and our Java payload is executed.
In order to achieve Remote Code Execution, an attacker could for example execute system commands via java.lang.Runtime.exec()
.
However, we were confronted with a last challenge. dotCMS has a URL filter that does not allow curly braces ({}
or URL encoded %7b%7d
) in the URL. We could successfully bypass this limitation as the CREATE ALIAS
directive expects a String as function source code. That means we do not need the $
signs and can use built-in SQL functions to encode our payload.
Timeline
Date | What |
2019/05/27 | Vulnerability reported to dotCMS via security@dotcms.com |
2019/06/06 | Vendor acknowledged vulnerability and addressed issue in release 5.1.6. |
2019/06/06 | Vendor published release 5.1.6. |
Summary
In this post, we analyzed a nested SQL injection vulnerability in dotCMS 5.1.5 which can be triggered through a JSP file. An attacker needs Publisher permissions to create an unpushed bundle and can then inject arbitrary SQL commands. We found that it is possible to leverage the issue into Remote Code Execution if the dotCMS instance relies on the H2 database. However, if other databases are used Remote Code Execution might be still possible since the attacker can create a new admin user or overwrite serialized objects in the database which might allow code execution if being deserialized. We would like to thank the dotCMS security team for the professional communication and for the very fast resolution of the issue.
Related Posts
- Exploiting Hibernate Injections
- Joomla! 3.7.5 - Takeover in 20 Seconds with LDAP Injection
- Backend SQL Injection in BigTree CMS 4.4.6
- Joomla! 3.8.3: Privilege Escalation via SQL Injection
- CubeCart 6.1.12 - Admin Authentication Bypass
- Pre-Auth Takeover of OXID eShops
- Breaking Into Your Company's Internal Network - SuiteCRM 7.11.4