CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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