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