Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/analyze/crack_aix.rb
21537 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Auxiliary::PasswordCracker
8
include Msf::Exploit::Deprecated
9
moved_from 'auxiliary/analyze/jtr_aix'
10
11
def initialize
12
super(
13
'Name' => 'Password Cracker: AIX',
14
'Description' => %(
15
This module uses John the Ripper or Hashcat to identify weak passwords that have been
16
acquired from passwd files on AIX systems. These utilize DES hashing.
17
DES is format 1500 in Hashcat.
18
),
19
'Author' => [
20
'theLightCosine',
21
'hdm',
22
'h00die' # hashcat integration
23
],
24
'License' => MSF_LICENSE, # JtR itself is GPLv2, but this wrapper is MSF (BSD)
25
'Actions' => [
26
['john', { 'Description' => 'Use John the Ripper' }],
27
['hashcat', { 'Description' => 'Use Hashcat' }],
28
['auto', { 'Description' => 'Auto-selection of cracker' }]
29
],
30
'DefaultAction' => 'auto',
31
'Notes' => {
32
'Stability' => [CRASH_SAFE],
33
'SideEffects' => [],
34
'Reliability' => []
35
}
36
)
37
38
register_options(
39
[
40
OptBool.new('INCREMENTAL', [false, 'Run in incremental mode', true]),
41
OptBool.new('WORDLIST', [false, 'Run in wordlist mode', true])
42
]
43
)
44
end
45
46
def show_command(cracker_instance)
47
return unless datastore['ShowCommand']
48
49
if @cracker_type == 'john'
50
cmd = cracker_instance.john_crack_command
51
elsif @cracker_type == 'hashcat'
52
cmd = cracker_instance.hashcat_crack_command
53
end
54
print_status(" Cracking Command: #{cmd.join(' ')}")
55
end
56
57
def check_results(passwords, results, hash_type, method)
58
passwords.each do |password_line|
59
password_line.chomp!
60
next if password_line.blank?
61
62
fields = password_line.split(':')
63
# If we don't have an expected minimum number of fields, this is probably not a hash line
64
next unless fields.count >= 3
65
66
cred = { 'hash_type' => hash_type, 'method' => method }
67
if @cracker_type == 'john'
68
cred['username'] = fields.shift
69
cred['core_id'] = fields.pop
70
4.times { fields.pop } # Get rid of extra :
71
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
72
elsif @cracker_type == 'hashcat'
73
cred['core_id'] = fields.shift
74
cred['hash'] = fields.shift
75
cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it
76
next if cred['core_id'].include?("Hashfile '") && cred['core_id'].include?("' on line ") # skip error lines
77
78
# we don't have the username since we overloaded it with the core_id (since its a better fit for us)
79
# so we can now just go grab the username from the DB
80
cred['username'] = framework.db.creds(workspace: myworkspace, id: cred['core_id'])[0].public.username
81
end
82
results = process_cracker_results(results, cred)
83
end
84
85
results
86
end
87
88
def run
89
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
96
97
hash_types_to_crack = ['descrypt']
98
jobs_to_do = []
99
100
# build our job list
101
hash_types_to_crack.each do |hash_type|
102
job = hash_job(hash_type, @cracker_type)
103
if job.nil?
104
print_status("No #{hash_type} found to crack")
105
else
106
jobs_to_do << job
107
end
108
end
109
110
# bail early of no jobs to do
111
if jobs_to_do.empty?
112
print_good("No uncracked password hashes found for: #{hash_types_to_crack.join(', ')}")
113
return
114
end
115
116
# array of arrays for cracked passwords.
117
# Inner array format: db_id, hash_type, username, password, method_of_crack
118
results = []
119
120
# generate our wordlist and close the file handle. max length of DES is 8
121
wordlist = wordlist_file(8)
122
unless wordlist
123
print_error('This module cannot run without a database connected. Use db_connect to connect to a database.')
124
return
125
end
126
127
wordlist.close
128
print_status "Wordlist file written out to #{wordlist.path}"
129
130
cleanup_files = [wordlist.path]
131
132
jobs_to_do.each do |job|
133
format = job['type']
134
hash_file = Rex::Quickfile.new("hashes_#{job['type']}_")
135
hash_file.puts job['formatted_hashlist']
136
hash_file.close
137
cracker.hash_path = hash_file.path
138
cleanup_files << hash_file.path
139
140
# dupe our original cracker so we can safely change options between each run
141
cracker_instance = cracker.dup
142
cracker_instance.format = format
143
144
if @cracker_type == 'john'
145
cracker_instance.fork = datastore['FORK']
146
end
147
148
# first check if anything has already been cracked so we don't report it incorrectly
149
print_status "Checking #{format} hashes already cracked..."
150
results = check_results(cracker_instance.each_cracked_password, results, format, 'Already Cracked/POT')
151
vprint_good(append_results(tbl, results)) unless results.empty?
152
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
153
next if job['cred_ids_left_to_crack'].empty?
154
155
if @cracker_type == 'john'
156
print_status "Cracking #{format} hashes in single mode..."
157
cracker_instance.mode_single(wordlist.path)
158
show_command cracker_instance
159
cracker_instance.crack do |line|
160
vprint_status(" #{line.chomp}")
161
end
162
results = check_results(cracker_instance.each_cracked_password, results, format, 'Single')
163
vprint_good(append_results(tbl, results)) unless results.empty?
164
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
165
next if job['cred_ids_left_to_crack'].empty?
166
167
print_status "Cracking #{format} hashes in normal mode..."
168
cracker_instance.mode_normal
169
show_command cracker_instance
170
cracker_instance.crack do |line|
171
vprint_status(" #{line.chomp}")
172
end
173
results = check_results(cracker_instance.each_cracked_password, results, format, 'Normal')
174
vprint_good(append_results(tbl, results)) unless results.empty?
175
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
176
next if job['cred_ids_left_to_crack'].empty?
177
end
178
179
if datastore['INCREMENTAL']
180
print_status "Cracking #{format} hashes in incremental mode..."
181
cracker_instance.mode_incremental
182
show_command cracker_instance
183
cracker_instance.crack do |line|
184
vprint_status(" #{line.chomp}")
185
end
186
results = check_results(cracker_instance.each_cracked_password, results, format, 'Incremental')
187
vprint_good(append_results(tbl, results)) unless results.empty?
188
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
189
next if job['cred_ids_left_to_crack'].empty?
190
end
191
192
next unless datastore['WORDLIST']
193
194
print_status "Cracking #{format} hashes in wordlist mode..."
195
cracker_instance.mode_wordlist(wordlist.path)
196
# Turn on KoreLogic rules if the user asked for it
197
if @cracker_type == 'john' && datastore['KORELOGIC']
198
cracker_instance.rules = 'KoreLogicRules'
199
print_status 'Applying KoreLogic ruleset...'
200
end
201
show_command cracker_instance
202
cracker_instance.crack do |line|
203
vprint_status(" #{line.chomp}")
204
end
205
206
results = check_results(cracker_instance.each_cracked_password, results, format, 'Wordlist')
207
vprint_good(append_results(tbl, results)) unless results.empty?
208
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
209
next if job['cred_ids_left_to_crack'].empty?
210
end
211
212
# give a final print of results
213
print_good(append_results(tbl, results))
214
215
if datastore['DeleteTempFiles']
216
cleanup_files.each do |f|
217
File.delete(f)
218
end
219
end
220
end
221
end
222
223