Skip to content

Commit 6c9f8ef

Browse files
authored
Merge pull request #1 from msutovsky-r7/collab/feat/auto_cracker_selection
Suggests additional changes for PR
2 parents f454954 + 16a5fa2 commit 6c9f8ef

File tree

8 files changed

+107
-71
lines changed

8 files changed

+107
-71
lines changed

lib/metasploit/framework/password_crackers/cracker.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ def initialize(attributes = {})
119119
public_send("#{attribute}=", value)
120120
end
121121
end
122+
123+
def get_type
124+
self.cracker
125+
end
122126

123127
# This method takes a {framework.db.cred.private.jtr_format} (string), and
124128
# returns the string number associated to the hashcat format
@@ -312,7 +316,7 @@ def binary_path
312316
end
313317
raise PasswordCrackerNotFoundError, 'No suitable john/hashcat binary was found on the system' unless path && ::File.file?(path)
314318

315-
path
319+
return path
316320
end
317321
end
318322

@@ -572,14 +576,16 @@ def show_command
572576
end
573577
cmd << hash_path
574578
end
575-
579+
576580
def get_hashcat
577581
# Look in the Environment PATH for the hashcat binary
582+
self.cracker = 'hashcat'
578583
Rex::FileUtils.find_full_path('hashcat') ||
579584
Rex::FileUtils.find_full_path('hashcat.exe')
580585
end
581586

582587
def get_john
588+
self.cracker = 'john'
583589
# Look in the Environment PATH for the john binary
584590
Rex::FileUtils.find_full_path('john') ||
585591
Rex::FileUtils.find_full_path('john.exe')

lib/msf/core/auxiliary/password_cracker.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def new_password_cracker(cracking_application)
8888
rescue Metasploit::Framework::PasswordCracker::PasswordCrackerNotFoundError => e
8989
fail_with(Msf::Module::Failure::BadConfig, e.message)
9090
end
91+
9192
# throw this to a local variable since it causes a shell out to pull the version
9293
cracker_version = cracker.cracker_version
9394
if cracker.cracker == 'john' && (cracker_version.nil? || !cracker_version.include?('jumbo'))

modules/auxiliary/analyze/crack_aix.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ def initialize
2525
'Actions' => [
2626
['john', { 'Description' => 'Use John the Ripper' }],
2727
['hashcat', { 'Description' => 'Use Hashcat' }],
28+
['auto', { 'Description' => 'Auto-selection of cracker' ]}
2829
],
29-
'DefaultAction' => 'john',
30+
'DefaultAction' => 'auto',
3031
'Notes' => {
3132
'Stability' => [CRASH_SAFE],
3233
'SideEffects' => [],
@@ -45,9 +46,9 @@ def initialize
4546
def show_command(cracker_instance)
4647
return unless datastore['ShowCommand']
4748

48-
if action.name == 'john'
49+
if @cracker_type == 'john'
4950
cmd = cracker_instance.john_crack_command
50-
elsif action.name == 'hashcat'
51+
elsif @cracker_type == 'hashcat'
5152
cmd = cracker_instance.hashcat_crack_command
5253
end
5354
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -63,12 +64,12 @@ def check_results(passwords, results, hash_type, method)
6364
next unless fields.count >= 3
6465

6566
cred = { 'hash_type' => hash_type, 'method' => method }
66-
if action.name == 'john'
67+
if @cracker_type == 'john'
6768
cred['username'] = fields.shift
6869
cred['core_id'] = fields.pop
6970
4.times { fields.pop } # Get rid of extra :
7071
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
71-
elsif action.name == 'hashcat'
72+
elsif @cracker_type == 'hashcat'
7273
cred['core_id'] = fields.shift
7374
cred['hash'] = fields.shift
7475
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
@@ -86,13 +87,19 @@ def check_results(passwords, results, hash_type, method)
8687

8788
def run
8889
tbl = tbl = cracker_results_table
90+
cracker = new_password_cracker(action.name)
91+
if action.name == 'auto'
92+
@cracker_type = cracker.get_type
93+
else
94+
@cracker_type = action.name
95+
end
8996

9097
hash_types_to_crack = ['descrypt']
9198
jobs_to_do = []
9299

93100
# build our job list
94101
hash_types_to_crack.each do |hash_type|
95-
job = hash_job(hash_type, action.name)
102+
job = hash_job(hash_type, @cracker_type)
96103
if job.nil?
97104
print_status("No #{hash_type} found to crack")
98105
else
@@ -110,8 +117,6 @@ def run
110117
# Inner array format: db_id, hash_type, username, password, method_of_crack
111118
results = []
112119

113-
cracker = new_password_cracker(action.name)
114-
115120
# generate our wordlist and close the file handle. max length of DES is 8
116121
wordlist = wordlist_file(8)
117122
unless wordlist
@@ -136,7 +141,7 @@ def run
136141
cracker_instance = cracker.dup
137142
cracker_instance.format = format
138143

139-
if action.name == 'john'
144+
if @cracker_type == 'john'
140145
cracker_instance.fork = datastore['FORK']
141146
end
142147

@@ -147,7 +152,7 @@ def run
147152
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
148153
next if job['cred_ids_left_to_crack'].empty?
149154

150-
if action.name == 'john'
155+
if @cracker_type == 'john'
151156
print_status "Cracking #{format} hashes in single mode..."
152157
cracker_instance.mode_single(wordlist.path)
153158
show_command cracker_instance
@@ -189,7 +194,7 @@ def run
189194
print_status "Cracking #{format} hashes in wordlist mode..."
190195
cracker_instance.mode_wordlist(wordlist.path)
191196
# Turn on KoreLogic rules if the user asked for it
192-
if action.name == 'john' && datastore['KORELOGIC']
197+
if @cracker_type == 'john' && datastore['KORELOGIC']
193198
cracker_instance.rules = 'KoreLogicRules'
194199
print_status 'Applying KoreLogic ruleset...'
195200
end

modules/auxiliary/analyze/crack_databases.rb

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ def initialize
3434
'Actions' => [
3535
['john', { 'Description' => 'Use John the Ripper' }],
3636
['hashcat', { 'Description' => 'Use Hashcat' }],
37+
['auto', { 'Description' => 'Auto-selection of cracker' }]
3738
],
38-
'DefaultAction' => 'john',
39+
'DefaultAction' => 'auto',
3940
'Notes' => {
4041
'Stability' => [CRASH_SAFE],
4142
'SideEffects' => [],
@@ -58,9 +59,9 @@ def initialize
5859
def show_command(cracker_instance)
5960
return unless datastore['ShowCommand']
6061

61-
if action.name == 'john'
62+
if @cracker_type == 'john'
6263
cmd = cracker_instance.john_crack_command
63-
elsif action.name == 'hashcat'
64+
elsif @cracker_type == 'hashcat'
6465
cmd = cracker_instance.hashcat_crack_command
6566
end
6667
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -74,13 +75,13 @@ def check_results(passwords, results, hash_type, method)
7475
fields = password_line.split(':')
7576
cred = { 'hash_type' => hash_type, 'method' => method }
7677

77-
if action.name == 'john'
78+
if @cracker_type == 'john'
7879
next unless fields.count >= 3
7980

8081
cred['username'] = fields.shift
8182
cred['core_id'] = fields.pop
8283
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
83-
elsif action.name == 'hashcat'
84+
elsif @cracker_type == 'hashcat'
8485
next unless fields.count >= 2
8586

8687
cred['core_id'] = fields.shift
@@ -110,6 +111,12 @@ def check_results(passwords, results, hash_type, method)
110111

111112
def run
112113
tbl = tbl = cracker_results_table
114+
cracker = new_password_cracker(action.name)
115+
if action.name == 'auto'
116+
@cracker_type = cracker.get_type
117+
else
118+
@cracker_type = action.name
119+
end
113120

114121
# array of hashes in jtr_format in the db, converted to an OR combined regex
115122
hash_types_to_crack = []
@@ -128,7 +135,7 @@ def run
128135

129136
# hashcat requires a format we dont have all the data for
130137
# in the current dumper, so this is disabled in module and lib
131-
if action.name == 'john'
138+
if @cracker_type == 'john'
132139
hash_types_to_crack << 'oracle'
133140
hash_types_to_crack << 'dynamic_1506'
134141
end
@@ -143,7 +150,7 @@ def run
143150

144151
# build our job list
145152
hash_types_to_crack.each do |hash_type|
146-
job = hash_job(hash_type, action.name)
153+
job = hash_job(hash_type, cracker.cracker)
147154
if job.nil?
148155
print_status("No #{hash_type} found to crack")
149156
else
@@ -161,8 +168,6 @@ def run
161168
# Inner array format: db_id, hash_type, username, password, method_of_crack
162169
results = []
163170

164-
cracker = new_password_cracker(action.name)
165-
166171
# generate our wordlist and close the file handle.
167172
wordlist = wordlist_file
168173
unless wordlist
@@ -187,7 +192,7 @@ def run
187192
cracker_instance = cracker.dup
188193
cracker_instance.format = format
189194

190-
if action.name == 'john'
195+
if @cracker_type == 'john'
191196
cracker_instance.fork = datastore['FORK']
192197
end
193198

@@ -198,7 +203,7 @@ def run
198203
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
199204
next if job['cred_ids_left_to_crack'].empty?
200205

201-
if action.name == 'john'
206+
if @cracker_type == 'john'
202207
print_status "Cracking #{format} hashes in single mode..."
203208
cracker_instance.mode_single(wordlist.path)
204209
show_command cracker_instance
@@ -239,7 +244,7 @@ def run
239244
print_status "Cracking #{format} hashes in wordlist mode..."
240245
cracker_instance.mode_wordlist(wordlist.path)
241246
# Turn on KoreLogic rules if the user asked for it
242-
if action.name == 'john' && datastore['KORELOGIC']
247+
if @cracker_type == 'john' && datastore['KORELOGIC']
243248
cracker_instance.rules = 'KoreLogicRules'
244249
print_status 'Applying KoreLogic ruleset...'
245250
end

modules/auxiliary/analyze/crack_linux.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ def initialize
3232
'Actions' => [
3333
['john', { 'Description' => 'Use John the Ripper' }],
3434
['hashcat', { 'Description' => 'Use Hashcat' }],
35+
['auto', { 'Description' => 'Auto-selection of cracker' }]
3536
],
36-
'DefaultAction' => 'john',
37+
'DefaultAction' => 'auto',
3738
'Notes' => {
3839
'Stability' => [CRASH_SAFE],
3940
'SideEffects' => [],
@@ -58,9 +59,9 @@ def initialize
5859
def show_command(cracker_instance)
5960
return unless datastore['ShowCommand']
6061

61-
if action.name == 'john'
62+
if @cracker_type == 'john'
6263
cmd = cracker_instance.john_crack_command
63-
elsif action.name == 'hashcat'
64+
elsif @cracker_type == 'hashcat'
6465
cmd = cracker_instance.hashcat_crack_command
6566
end
6667
print_status(" Cracking Command: #{cmd.join(' ')}")
@@ -74,14 +75,14 @@ def check_results(passwords, results, hash_type, method)
7475
fields = password_line.split(':')
7576
cred = { 'hash_type' => hash_type, 'method' => method }
7677

77-
if action.name == 'john'
78+
if @cracker_type == 'john'
7879
next unless fields.count >= 3 # If we don't have an expected minimum number of fields, this is probably not a hash line
7980

8081
cred['username'] = fields.shift
8182
cred['core_id'] = fields.pop
8283
4.times { fields.pop } # Get rid of extra :
8384
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
84-
elsif action.name == 'hashcat'
85+
elsif @cracker_type == 'hashcat'
8586
next unless fields.count >= 2 # If we don't have an expected minimum number of fields, this is probably not a hash line
8687

8788
cred['core_id'] = fields.shift
@@ -101,6 +102,12 @@ def check_results(passwords, results, hash_type, method)
101102

102103
def run
103104
tbl = tbl = cracker_results_table
105+
cracker = new_password_cracker(action.name)
106+
if action.name == 'auto'
107+
@cracker_type = cracker.get_type
108+
else
109+
@cracker_type = action.name
110+
end
104111

105112
# array of hashes in jtr_format in the db, converted to an OR combined regex
106113
hash_types_to_crack = []
@@ -115,7 +122,7 @@ def run
115122

116123
# build our job list
117124
hash_types_to_crack.each do |hash_type|
118-
job = hash_job(hash_type, action.name)
125+
job = hash_job(hash_type, @cracker_type)
119126
if job.nil?
120127
print_status("No #{hash_type} found to crack")
121128
else
@@ -133,8 +140,6 @@ def run
133140
# Inner array format: db_id, hash_type, username, password, method_of_crack
134141
results = []
135142

136-
cracker = new_password_cracker(action.name)
137-
138143
# generate our wordlist and close the file handle.
139144
wordlist = wordlist_file
140145
unless wordlist
@@ -158,7 +163,7 @@ def run
158163
cracker_instance = cracker.dup
159164
cracker_instance.format = format
160165

161-
if action.name == 'john'
166+
if @cracker_type == 'john'
162167
cracker_instance.fork = datastore['FORK']
163168
end
164169

@@ -169,7 +174,7 @@ def run
169174
job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list
170175
next if job['cred_ids_left_to_crack'].empty?
171176

172-
if action.name == 'john'
177+
if @cracker_type == 'john'
173178
print_status "Cracking #{format} hashes in single mode..."
174179
cracker_instance.mode_single(wordlist.path)
175180
show_command cracker_instance
@@ -211,7 +216,7 @@ def run
211216
print_status "Cracking #{format} hashes in wordlist mode..."
212217
cracker_instance.mode_wordlist(wordlist.path)
213218
# Turn on KoreLogic rules if the user asked for it
214-
if action.name == 'john' && datastore['KORELOGIC']
219+
if @cracker_type == 'john' && datastore['KORELOGIC']
215220
cracker_instance.rules = 'KoreLogicRules'
216221
print_status 'Applying KoreLogic ruleset...'
217222
end

0 commit comments

Comments
 (0)