Filed Under (News, WordPress) by DK on 18 July 2007

Adrian Pastor is a member of the BlogSecurity team and the GNUCITIZEN Group. His personal web site is available at ikwt. As always, Adrian gives us a very detailed advisory around how an attacker can enumerate valid WordPress user accounts and then launch password guessing attacks in an attempt to compromise the blog. His proof of concept brute force script is available here.

This post is the follow up to my previous work on username enumeration vulnerabilities. In this post we primarily concentrated on various identification techniques. In this post, we will explore some of the issues around the same subject which are present in the latest Wordpress build. In short, we will deal with exploitation as opposed to identification.

As you might already know, there are many tools you can use to exploit username enumeration vulnerabilities. For instance, you can use Burp, which allows you to flag user-defined responses. I personally feel that Burp waits too long between each request, making the process very slow. Now, we all have our favorite tools and tricks, but in this post I will use bash + curl. The reason for this is because both combined produce a very powerful and customizable tool. Moreover, we don’t have to be advanced coders at all in order to use bash - far from it!

Let’s discuss how we can attack Wordpress 2.2.1 login facilities. The Wordpress login page is usually easily identifiable. Unless the blog owner put extra effort to re-arrange some of the core Wordpress modules, it would be located on the following path by default:

/wordpress/wp-login.php

If you try logging in with any non-existent username and a random password the login page will return the following message:

Error: This username is invalid. Please enter a valid username.

Thus the login page leaks the fact that probed username does not exist. Hint: notice “This username is invalid”

On the other hand, if we enter a username that does exist and an invalid password, the login page would return the following message:

Error: Incorrect password

As we can see the error message is now different and suggests that the username we entered does exist on the system. As developers, we could fix this username leak on the login page by simply returning a general authentication failure message when the username and/or the password is/are wrong. Thus, attackers wouldn’t have means to find out whether a username already exists on the database unless a valid username and its corresponding password were both cracked.

i.e:

ERROR: Incorrect username and/or password.

Let’s see what we need to do in our attack script:

  • Read a wordlist file
  • Submit a request identical to the original authentication request with each username read from the wordlist (you can use LiveHttpHeaders to view HTTP requests among many other tools)
  • Check if the login page returns: Incorrect password
  • If the such message is returned then flag it by printing the username found on the screen and to a results file
  • Continue reading wordlist file
  • In order to get a rough idea of what we’re talking about, you can take a look at the following snippet from the PoC script we have created for this article. Note: such script has been tested on Wordpress 2.2.1 but might also work on previous versions.


    if curl -s -d "log=$U&pwd=mypassword&wp-submit=Login+%C2%BB&redirect_to="
    --url "http://$1/wordpress/wp-login.php" | grep -i 'Incorrect password' > /dev/null

    What we have is the following. The ‘-s’ flag avoids printing unnecessary status info (’s’ for silent). ‘-d’ allows you to submit parameters as a POST request. $U is each username read from the wordlist. Notice we are submitting a dummy password (’mypassword’). Lastly, if we get a ‘true’ signal from grepping ‘Incorrect password’, then we know we found a valid username. If you see the source code of the script, you’ll notice that there is not much more to it, except for a ‘for’ loop that reads the wordlist file. It really is that simple!

    Sometimes however, dictionary attacks might not be necessary in order to identify existing usernames. For instance, some Wordpress templates show the author’s name on each post. Additionally, the author name can also be found within RSS feeds’ tags. Unfortunately, the author’s name shown in posts and RSS feeds is not necessarily the same as the login username. Hint: what information will be shown as the author’s name is set on the Profile/Display name publicly as menu.

    Just remember, there might be scenarios in which a dictionary attack on a functionality that is vulnerable to username enumeration is your last resort to collect usernames. As an example, there are companies and large organizations using Wordpress with several admin users whose usernames are not used to publish posts but rather to moderate other user’s posts. In such case a username enumeration vulnerability might come in handy for attempting to enumerate admin usernames.

    Here are some possible admin usernames you might want to add to your favorite usernames wordlist:

    admin, administrator, moderator, manager, root,
    <companyname>admin, blogadmin, wpmoderator, wpadmin,
    wpmanager

    There are other places where you might be able to find some usernames. A good example are Wordpress author templates which allow you to extract usernames through URLs with the following syntax: /wordpress/author/authorname/

    i.e.:

    http://www.target-domain.com/wordpress/author/admin/

    A different functionality we can attack is Wordpress 2.2.1’s signup page (”/wordpress/wp-register.php”) which is also vulnerable to username enumeration. When registering a new account we need to enter a username and email address. However, when entering either a valid or invalid email address the application will reveal whether or not the username entered exists on the system. For instance, if we entered the username “admin” and the email address “notvalidemail”, we would get the following message, thus revealing that the username entered already exists:

    ERROR: The email address isn't correct.
    ERROR: This username
    is already registered, please choose another one.

    What you want to do in this case is probe usernames using invalid email addresses. That way when you probe a username that does exist, the application won’t create a new account, therefore making the attack more stealth. You could also argue that probing existing usernames on a signup page is less obvious than doing it on a login page.

    That’s all guys. In this post I just chose Wordpress to illustrate some examples but remember that username enumeration vuls, although usually considered a low risk, might have bigger implications on sites of different nature such as financial applications. As usual, please feel free to provide feedback, which after all is what makes publishing research on blogs interesting.

    Although attackers may be able to brute force valid usernames, strong passwords will help mitigate the affects of such an attack. So in short, ensure that you choose strong 6-8 characters (should include a digit, and an upper-case character) password or passphrase. WordPress will hopefully take this advisory into consideration in a future release.

    Read some of Adrian’s other articles:

    Comments

    David Kierznowski on 18 July, 2007 at 5:43 am #

    Adrian, sometimes we underestimate the traditionl brute force approach, awesome article.

    It may be interesting to look into the default admin password generation that WordPress recommends when installing a blog. If I remember correctly its 6 characters, all lower-case with digits.


    Philipp on 18 July, 2007 at 7:17 am #

    That vulnerability is the perfect example for a blog which isn’t hardened. That attack isn’t possible when you hardened your blog. Or it’s quite harder to achieve if you have at least password protected your wp-admin area. So for all who didn’t considered harden their wp install should rethink their decision.


    David Kierznowski on 18 July, 2007 at 7:55 am #

    Phil, yes, those who implemented our hardening guide (atleast those able to) would be immune to a degree against this attack, nice point!


    Adrian Pastor on 18 July, 2007 at 11:18 am #

    David,

    Don’t take my word for it, but I think the 6 chars are a derived from a partial hash (first 6 chars of MD5 hash?) of a random value. Hopefully it’s truly random, otherwise we have

    36^6 = 2176782336 combinations

    which is a lot! :)

    Not too long ago we came across a financial app. The app would generate new passwords when clicking on “I forgot my password” that would be sent to your email. The problem is that the pwds were made of a word from either of the following groups:

    - classic musician names
    - fruits
    - colors

    plus two digits. You might think I’m kidding but this is a real story.


    David Kierznowski on 18 July, 2007 at 5:17 pm #

    Adrian, heh, I can beat that story but its for a drink at the pub evening :)


    Recommended site for WordPress security on 19 July, 2007 at 6:16 am #

    [...] it is not holding back new WordPress holes from disclosure — for example, a new article yesterday showed how to perform enumeration on WordPress installation by brute force, so that valid usernames [...]


    [...] von einem lesenswerten (englischsprachigen) Artikel ›WordPress Username Enumeration‹ in BlogSecurity ein paar kurze Anmerkungen zu Verwendung von Benutzernamen in Wordpress – [...]


    [...] O link para o texto original é este. [...]


    AskApache on 20 August, 2007 at 6:50 pm #

    Very very cool article! I created a wordpress plugin that you might want to check out and see if your method will still be useful.

    htaccess password protect wp-admin


    Comment
    Name:
    Email:
    Website:
    Message: