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