This post describes the second of two vulnerabilities I found in WordPress. The first, a XSS vulnerability, was described last week. While the vulnerability discussed here is applicable in fewer cases than the previous one, it is an example of a comparatively rare class, oracle attacks, so I think merits further exposition.
An oracle attack is where an attacker can abuse a facility provided by a system to gain unauthorized access to protected information. The term originates from cryptology, and such attacks still crop up regularly; for example in banking security devices and protocols. The occurrence of an oracle attack in WordPress illustrates the need for a better understanding of cryptography, even by the authors of applications not conventionally considered to be cryptographic software. Also more forgiving primitives and better robustness principles could reduce the risk of future weaknesses.
The vulnerability is a variant of the ‘cache’ shell injection bug reported by rgodm. This is caused by an unfortunate series of design choices by the WordPress team, leading to arbitrary PHP execution. The WordPress cache stores commonly accessed information from the database, such as user profile data, in files for faster retrieval. Despite them being needed only by the server, they are still accessible from the web, which is commonly considered bad practice. To prevent the content being read remotely, the data is placed in
.php files, commented out with
//. Thus when executed by the web server, in response to a remote query, they return an empty file.
However, putting user controlled data in executable files is inherently a risky choice. If the attacker can escape from the comment then arbitrary PHP can be executed. rgodm’s shell injection bug does this by inserting a newline into the display name. Now all the attacker must do is guess the name of the
.php file which stores his cached profile information, and invoke it to run the injected PHP. WordPress puts an
index.php in the cache directory to suppress directory indexing, and filenames are generated as MD5(username ||
DB_PASSWORD) || “.php”, which creates hard to guess name. The original bug report suggested brute forcing DB_PASSWORD, the MySQL authentication password, but the oracle attack described here will succeed even if a strong password is chosen.