Andrew Nacin, lead developer of WordPress, just finished a talk at Loopconf, where he talked about a series of related WordPress security fixes that spanned two years, with the final fix included into WordPress core under the guise of emoji support.
Andrew Nacin just spoke at Loopconf about the nature of a critical software bug.
No strict mode on WordPress databases
At a base level, the problems originated in that WordPress did not enable strict mode for MySQL. If
STRICT_ALL_TABLES has been enabled, the security vulnerability that was addressed in WordPress 4.2 would not exist.
Without strict mode, MySQL allows more flexible inputs, and doesn't require the same level of precision in what it allows. For example, a long username would just truncate to the maximum allowed characters, versus be rejected.
Since MySQL can do strange things without strict mode enabled, there are obscure but significant ways for hackers to take advantage.
Defining the scope of a vulnerability
A vulnerability was disclosed to the WordPress security team about two years ago. At its core, the method for forcing MySQL truncation was by using four-byte characters, and then using tricks to store nefarious code in the database.
Nacin used an example of inserting two comments in the database with single quotes and attached four-byte characters. MySQL would truncate the four-byte characters on databases using UTF8 (and don't allow four-byte characters), and a hacker could utilize the truncated comment (or any other field, really) to add a second comment to finish the exploitation.
The initial vulnerability was fixed in 3.6.1. In 2014, an new disclosure came in from Cedric Van Bochhaven to note that there was still a vulnerability under particular circumstances.
After months of work and “tens of thousands of lines of code” for rewrites and tests, the team realized that they needed to check inputs to the database at a base level of WordPress.
In WordPress 4.2, approximately 1,000 lines of code were inserted into wpdb.php under the guise of emoji support, but were really for fixing this vulnerability.
The original report identified three requirements for the site to be exposed:
- MySQL truncating everything after a four-byte character
- It's not exposed when utf8mb4 is enabled
- It's theme dependent
It turned out that really only part of number one needed to be true. They discovered, “this could affect any two fields that would be rendered anywhere near each other.”
Between 11 default database tables and hundreds of fields, basically all parts of WordPress were vulnerable, and core itself also “extensively” relied on non-strict mode functionality.
Furthermore, they realized that even three-byte characters could cause truncation, if they aren't valid upon insertion.
So of the requirements from the original report, most were not actually required.
“We're deeper and deeper and deeper into this hole, and we have no idea how to get out.”
The team went back to a discussion from the 3.6.1 vulnerability fix, that does what Nacin calls “preflight checks” that checks many layers of WordPress to ensure allowed data is being inserted.
Checking allowed character sets was not only on the database and table level, but also on columns and fields. Furthermore, the client, the connection, and the server can have their own character sets.
Nacin defines the method for checking as both using a scalpel and a sledgehammer.
We need this to work two different ways: with a scalpel via
delete(), and with a sledgehammer via write queries via
The code has been in trunk since January, months before the release of 4.2. But it was there under the guise of emoji support, as “noone had any idea what it did because it was 1,000 lines of the database abstraction layer to just remove invalid characters.”
Because of how opaque the vulnerability and the corresponding fix were, the team was able to spend a very long time working on and fixing the issue, all without exposing the vulnerability to the general public.
When 23.9% of the internet uses WordPress, security becomes an even more enormous challenge than in other software. There was an easy fix for this all along: strict mode on MySQL.
However, it would've broken “everything.” Alternatively, exposing a vulnerability to the public without a fix that doesn't break websites makes the vulnerability that much more powerful. It takes a ridiculous effort for the WordPress core team and security team to ensure practical solutions to keep the WordPress software secure and reliable for millions of users.
By the way, if you ever find a vulnerability in WordPress or you get really excited about problems like these, you can email email@example.com to get involved.