I notified the WordPress Team upon a non-critical cryptographic flaw in their multi-site feature which can provide an attacker a vector for impersonation in certain special circumstances. It sounds like a very good vulnerability when I state impersonation but it’s non-critical, I will explain further in the article. WordPress multi-site allows you to take manage multiple blogs (with different domains) in one place. This can be attractive to businesses with multiple installations of wordpress, it can also segment multiple teams that you may be managing which is helpful. The vulnerability was reported on 26th September in which they replied on the 28th. This research was for my job at insinia in which I was looking at possible attack vectors in a default installation of WordPress. I discovered many things on WordPress but have decided first to simply talk about the flaw that I found for simplicity and making things less cluttered.
WordPress has two different ways of being activated for multisite and a single site. Hashing on a default installation of WordPress on a single site has some flexibility, it chooses between a number of different algorithms according to strength and availability, a bit like how TLS negotiates between server and client on chosen algorithm. PHPass is used by WordPress for hashing passwords, the last resort is to use md5 but has many other choices before then. The activation key on a site site, is suitably random, using the wp_rand() and wp_generate_password() functions to generate with other variables a reasonably random output (although randomness I understand is a arguement to have in security). If we contrast with multisites sign up flow, we can start to see some problems which will be problematic in the future. If we look at how the activation key is generated for a users blog signup (also with user signups).
$key = substr( md5( time() . rand() . $domain ), 0, 16 );
The first thing I notice is that md5 is used straight out whatever we do here. This is available to see in line 672 of the current version (4.7) of function wpmu_signup_blog(), unlike other operations like our password hashing in WordPress single site, multisite configurations are by default weaker on activation keys because of the default use of md5. The other parts to this key are also not secure in modern day standards, especially to a business standard. time() is used which is a less accurate microtime(). We get sent an accurate form of time() through HTTP headers that allows us to predict the value to a reasonable value even if the server is misconfigured be it timezone or time overall itself. The rand() function has been proven to be weak and is advised by the PHP developers to not be used in cryptographic operations. Another problem that rand() has is it can only go up to 32767 in Windows, for an attacker 0-32767 is viable in exploitation. The final part is either $domain or $email which is obviously not hard for an attacker to input into.
What can we viably do, is validate an accounts email without any access to that email. Multisite also has the option to allow users to register from a specific domain which we could bypass by using this attack. Unless there is manual verification or users in which emails are not sent and are self registered this attack could work quite well in social engineering aswell, such as registering firstname.lastname@example.org onto a wordpress and being able to verify it. I produced a PoC in a Windows environment to see how well the attack would peform and weakened my chances by increasing my time range by 2 seconds each way (-/+). I found that first result gave me 14,000 requests were needed for this attack to be bruteforced (essentially only rand() providing some form of protection), others produced much higher values but still viable for an attacker, I concluded that playing security russian roulette isn’t really ideal and decided to email the WordPress security team. For reference it’s the second cmd that has the request values, the first Window is generating the values for a test, but it doesn’t really matter that you know what it does to be honest.
This did not involve using statistical attacks with rand() or anything fancy which is why the values are still relatively high, the attack increments from 0 to guess the rand() value.
WordPress 4.7 and below have predictable values in certain environments (Windows) to which only 14,000 requests (probably could be avereged lower) are needed to be able to activate a account to which you have no access to email through bruteforce. The multisite activation key generation is insufficient in todays ever changing security standards with the use of broken algorithm md5 and implementation of time() and rand() which severely weakens the ability to create high randomness even in Linux environments where it is different. The WordPress security team should look at moving the multisite registering functions on like they have with single site registering. I have peformed responsible disclosure and waited till a fix has been put in place and published.
26th September 2016 – Vulnerability Found and Exploited. WordPress Security Team Contacted.
28th September 2016 – Security Team Member From WordPress Replies With Acceptance of Vuln.
4rd January 2017 – Security Team Outline A Suitable Fix.
11th January 2017 – WordPress Release 4.7.1 Security Release.