The vulnerability in the GOTMLS plugin was originally reported by stealthcopter to the Patchstack bug bounty program for WordPress. We are collaborating with the researcher to release the content of this security advisory article.
This blog post is about the GOTMLS plugin vulnerability. If you’re a GOTMLS user, please update the plugin to at least version 4.23.56.
All paid Patchstack users are protected from this vulnerability. Sign up for the free Community account first, to scan for vulnerabilities and apply protection for only $5 / site per month with Patchstack.
For plugin developers, we have security audit services and Enterprise API for hosting companies.
About the GOTMLS Plugin
The plugin GOTMLS (free version), which has over 200,000 active installations, is known as the more popular “Anti-Malware Security and Brute-Force Firewall” plugin in WordPress.
This WordPress plugin has some features, one of which is to run a Complete Scan to automatically remove known security threats, backdoor scripts, and database injections. Another feature available is firewall and brute-force protection.
The security vulnerability
This plugin suffers from multiple vulnerabilities and could allow any unauthenticated user to gain a remote code execution on the WordPress site.
The vulnerability chain begins with unprotected API functions that leak sensitive data, including server time. This allows brute forcing of an insufficiently random value used for a nonce. This nonce is used to authenticate to additional API functions that allow updating of malware definitions. These regexes can be abused to selectively delete source code resulting in code execution. The described vulnerability was fixed in version 4.23.56 and assigned CVE-2024-22144.
Unauthenticated API Access
Allowing unauthenticated access to critical API functions in a plugin creates a significant security risk, as it permits any user, to access and potentially manipulate sensitive functionalities, laying the groundwork for potential exploitation and unauthorized actions. Plugins should restrict publicly accessible APIs to only those that are strictly necessary.
Interestingly, the plugin exposes several functions to unauthenticated users via the admin-ajax.php
file, by adding an actions prefix with wp_ajax_nopriv_
. This allows anyone to access the GOTMLS_
functions provided which start with the letter l
, giving us direct access to 4 sensitive functions such as load_update
, log_session
, logintime
and lognewkey
.
--------------------- CUTTED HERE ---------------------
$ajax_functions = array('load_update', 'log_session', 'empty_trash', 'fix', 'logintime', 'lognewkey', 'position', 'scan', 'View_Quarantine', 'whitelist');
// ...
foreach ($ajax_functions as $ajax_function) {
add_action("wp_ajax_GOTMLS_$ajax_function", "GOTMLS_ajax_nopriv");
add_action("wp_ajax_nopriv_GOTMLS_$ajax_function", substr($ajax_function, 0, 1) == "l"?"GOTMLS_ajax_$ajax_function":"GOTMLS_ajax_nopriv");
}
--------------------- CUTTED HERE ---------------------
The logintime
function exposes the server’s micro time value, information which can be used for the next part of the vulnerability to calculate and brute force a valid nonce due to insufficient randomness.
Insufficient Randomness in Nonce Generation
It is a dangerously common anti-pattern to create what appears to be a random hash using predictable or known inputs (remember predictable input gives predictable output). This can leave systems vulnerable to bad actors who could directly guess or brute force these values.
The code snippet below illustrates how the plugin was generating nonces:
--------------------- CUTTED HERE ---------------------
$nonce = md5(substr(number_format(microtime(true), 9, '-', '/'), 6).GOTMLS_installation_key.GOTMLS_plugin_path);
--------------------- CUTTED HERE ---------------------
In this instance, GOTMLS_plugin_path
was predictable and GOTMLS_installation_key
was known as it is generated from the site URL. The server also leaked its current micro time to 4 decimal places. This means that a brute force approach would only need to try a few million hashes before it could successfully guess a valid nonce.
A key aspect of nonce security is ensuring that they are tied to specific sessions. This practice adds an additional layer of security, as it associates each nonce with a unique user session, making it significantly more difficult for attackers to exploit. In this plugin, nonces are stored globally and reused between different users.
Another interesting quirk in the code allowed for the validation of an array of nonces. This significantly reduced the number of requests required to brute force a value. The limitation here is PHP’s max_input_vars
which typically restricts the number of variables in HTTP requests to 1000.
Code Execution by Injecting Malicious Malware Rules
Once a valid nonce is obtained, the plugin gives you more access including all the Ajax functions, not just those beginning with the letter l
. These are more sensitive administrative API functions that can be accessed and manipulated.
One such function allows for the update of PHP serialized, base64 encoded malware definitions. By injecting custom regexes into these definitions, it is possible to manipulate the plugin to scan its own source code and delete specific strings, leaving behind an exploitable code fragment eval($_REQUEST['mt']);
. This process leads to fully unauthenticated RCE. The way this selective code deletion functions is demonstrated in the gif below:
The patch
The patch includes fixes that disrupt the exploit chain at multiple points, preventing unauthenticated remote code execution. The full patch code changes can be seen here. Some of the points from the patch attempt:
**Nonce Validation** – The GOTMLS_get_nonce
function now only accepts a single nonce, not an array, allowing validation of one nonce at a time. It is also no longer possible to use this function to invalidate existing nonces.
**Nonce Creation** – Added user and context identifiers ($uid
and $context
) to the GOTMLS_get_nonce
function. It is also no longer possible to create new nonces without authentication.
**Information Leakage** – The unauthenticated endpoints GOTMLS_log_session and GOTMLS_logintime
no longer leak the server’s current micro time.
**Malware Definitions Update** – The GOTMLS_ajax_load_update
endpoint, which updates malware definitions, now includes a user check to ensure only admins can perform updates, using the custom function GOTMLS_user_can
. These updates significantly increase the difficulty of brute-forcing a valid nonce, making it currently impractical without exploiting additional vulnerabilities.
Conclusion
The vulnerabilities discussed here underscore the importance of securing all aspects of a plugin, especially those designed for security purposes. For developers, it is crucial to ensure that every function and API endpoint is secured with appropriate authentication and validation mechanisms to prevent exploitation. It is highly recommended to avoid creating your own security functions and to utilize those already built into WordPress, such as nonce creation and validation. These have been tested and approved by a larger community, making them more reliable than creating your own from scratch.
Timeline
Help us make the Internet a safer place
Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.
- If you’re a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
- If you’re a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.