Merge branch 'feature/MSP-9716/mssql_crack' into staging/electro-release

bug/bundler_fix
James Lee 2014-06-20 12:39:07 -05:00
commit 35c0ef0c68
No known key found for this signature in database
GPG Key ID: 2D6094C7CEA0A321
6 changed files with 119 additions and 61 deletions

View File

@ -7,7 +7,7 @@ group :db do
# Needed for Msf::DbManager
gem 'activerecord', '>= 3.0.0', '< 4.0.0'
# Metasploit::Credential database models
gem 'metasploit-credential', git: 'github-metasploit-credential:rapid7/metasploit-credential.git', tag: 'v0.4.3-electro-release'
gem 'metasploit-credential', git: 'github-metasploit-credential:rapid7/metasploit-credential.git', tag: 'v0.4.8-electro-release'
# Database models shared between framework and Pro.
gem 'metasploit_data_models', '~> 0.17.2.pre.metasploit.pre.data.pre.models.pre.search'
# Needed for module caching in Mdm::ModuleDetails

View File

@ -1,9 +1,9 @@
GIT
remote: github-metasploit-credential:rapid7/metasploit-credential.git
revision: b861156ed09cd4069541c60a611d89e302389d4c
tag: v0.4.3-electro-release
revision: b7234221ce41e311947e3e32c03aa7b6474f4f4f
tag: v0.4.8-electro-release
specs:
metasploit-credential (0.4.3.pre.electro.pre.release)
metasploit-credential (0.4.8.pre.electro.pre.release)
metasploit-concern (~> 0.1.0)
metasploit-model (>= 0.24.1.pre.semantic.pre.versioning.pre.2.pre.0, < 0.25)
metasploit_data_models (>= 0.17.2.pre.metasploit.pre.data.pre.models.pre.search, < 0.18)

View File

@ -115,7 +115,7 @@ module Metasploit
# @return [Array] An array set up for {::IO.popen} to use
def crack_command
cmd_string = binary_path
cmd = [ cmd_string, '--session=' + john_session_id, '--nolog', '--dupe-suppression' ]
cmd = [ cmd_string, '--session=' + john_session_id, '--nolog' ]
if config.present?
cmd << ( "--config=" + config )

View File

@ -34,7 +34,7 @@ module Auxiliary::JohnTheRipper
OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]),
OptBool.new('USE_DB_INFO', [false, 'Use looted database schema info to seed the wordlist', true]),
OptBool.new('USE_DEFAULT_WORDLIST', [false, 'Use the default metasploit wordlist', true]),
OptBool.new['USE_HOSTNAMES', [false, 'Seed the wordlist with hostnames from the workspace', true]],
OptBool.new('USE_HOSTNAMES', [false, 'Seed the wordlist with hostnames from the workspace', true]),
OptBool.new('USE_ROOT_WORDS', [false, 'Use the Common Root Words Wordlist', true])
], Msf::Auxiliary::JohnTheRipper
)
@ -59,7 +59,7 @@ module Auxiliary::JohnTheRipper
# @return [nilClass] if there is no active framework db connection
# @return [Metasploit::Framework::JtR::Cracker] if it successfully creates a JtR Cracker object
def new_john_cracker
return nil unless framework.db.active?
return nil unless framework.db.active
Metasploit::Framework::JtR::Cracker.new(
config: datastore['CONFIG'],
john_path: datastore['JOHN_PATH'],
@ -75,11 +75,10 @@ module Auxiliary::JohnTheRipper
# @return [nilClass] if there is no active framework db connection
# @return [Rex::Quickfile] if it successfully wrote the wordlist to a file
def wordlist_file
return nil unless framework.db.active?
return nil unless framework.db.active
wordlist = Metasploit::Framework::JtR::Wordlist.new(
custom_wordlist: datastore['CUSTOM_WORDLIST'],
mutate: datastore['MUTATE'],
pot: datastore['POT'],
use_creds: datastore['USE_CREDS'],
use_db_info: datastore['USE_DB_INFO'],
use_default_wordlist: datastore['USE_DEFAULT_WORDLIST'],

View File

@ -5,6 +5,7 @@
require 'msf/core'
require 'msf/core/auxiliary/jtr'
class Metasploit3 < Msf::Auxiliary
@ -28,62 +29,78 @@ class Metasploit3 < Msf::Auxiliary
end
def run
@wordlist = Rex::Quickfile.new("jtrtmp")
@formats = Set.new
cracker = new_john_cracker
@wordlist.write( build_seed().flatten.uniq.join("\n") + "\n" )
@wordlist.close
print_status("Cracking MSSQL Hashes")
crack("mssql")
print_status("Cracking MSSQL05 Hashes")
crack("mssql05")
#generate our wordlist and close the file handle
wordlist = wordlist_file
wordlist.close
print_status "Wordlist file written out to #{wordlist.path}"
cracker.wordlist = wordlist.path
cracker.hash_path = hash_file
end
def crack(format)
hashlist = Rex::Quickfile.new("jtrtmp")
ltype= "#{format}.hashes"
myloots = myworkspace.loots.where('ltype=?', ltype)
unless myloots.nil? or myloots.empty?
myloots.each do |myloot|
begin
mssql_array = CSV.read(myloot.path).drop(1)
rescue Exception => e
print_error("Unable to read #{myloot.path} \n #{e}")
end
mssql_array.each do |row|
hashlist.write("#{row[0]}:0x#{row[1]}:#{myloot.host.address}:#{myloot.service.port}\n")
end
@formats.each do |format|
# dupe our original cracker so we can safely change options between each run
cracker_instance = cracker.dup
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
cracker_instance.crack do |line|
print_status line.chomp
end
hashlist.close
print_status("HashList: #{hashlist.path}")
print_status("Trying Wordlist: #{@wordlist.path}")
john_crack(hashlist.path, :wordlist => @wordlist.path, :rules => 'single', :format => format)
print_status "Cracking #{format} hashes in single mode..."
cracker_instance.rules = 'single'
cracker_instance.crack do |line|
print_status line.chomp
end
print_status("Trying Rule: All4...")
john_crack(hashlist.path, :incremental => "All4", :format => format)
print_status "Cracking #{format} hashes in incremental mode (All4)..."
cracker_instance.rules = nil
cracker_instance.wordlist = nil
cracker_instance.incremental = 'All4'
cracker_instance.crack do |line|
print_status line.chomp
end
print_status("Trying Rule: Digits5...")
john_crack(hashlist.path, :incremental => "Digits5", :format => format)
print_status "Cracking #{format} hashes in incremental mode (Digits5)..."
cracker_instance.incremental = 'Digits5'
cracker_instance.crack do |line|
print_status line.chomp
end
cracked = john_show_passwords(hashlist.path, format)
print_status("#{cracked[:cracked]} hashes were cracked!")
cracked[:users].each_pair do |k,v|
print_good("Host: #{v[1]} Port: #{v[2]} User: #{k} Pass: #{v[0]}")
report_auth_info(
:host => v[1],
:port => v[2],
:sname => 'mssql',
:user => k,
:pass => v[0]
)
print_status "Cracked Passwords this run:"
cracker_instance.each_cracked_password 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
username = fields.shift
core_id = fields.pop
password = fields.join(':') # Anything left must be the password. This accounts for passwords with : in them
print_good password_line
create_cracked_credential( username: username, password: password, core_id: core_id)
end
end
end
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: ['mssql', 'mssql05', 'mssql12']).each do |hash|
# Track the formats that we've seen so we do not attempt a format that isn't relevant
@formats << hash.jtr_format
hash.cores.each do |core|
user = core.public.username
hash_string = "0x#{hash.data}"
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end
end
hashlist.close
print_status "Hashes Written out to #{hashlist.path}"
hashlist.path
end
end

View File

@ -35,17 +35,57 @@ class Metasploit3 < Msf::Auxiliary
return
end
service_data = {
address: ip,
port: rport,
service_name: 'mssql',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: datastore['PASSWORD'],
private_type: :password,
username: datastore['USERNAME']
}
if datastore['USE_WINDOWS_AUTHENT']
credential_data[:realm_key] = Metasploit::Credential::Realm::Key::ACTIVE_DIRECTORY_DOMAIN
credential_data[:realm_value] = datastore['DOMAIN']
end
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Credential::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]
unless is_sysadmin == 0
login_data[:access_level] = 'admin'
end
create_credential_login(login_data)
#Grabs the Instance Name and Version of MSSQL(2k,2k5,2k8)
instancename= mssql_query(mssql_enumerate_servername())[:rows][0][0].split('\\')[1]
print_status("Instance Name: #{instancename.inspect}")
version = mssql_query(mssql_sql_info())[:rows][0][0]
version_year = version.split('-')[0].slice(/\d\d\d\d/)
mssql_hashes = mssql_hashdump(version_year)
unless mssql_hashes.nil?
report_hashes(mssql_hashes,version_year)
unless is_sysadmin == 0
mssql_hashes = mssql_hashdump(version_year)
unless mssql_hashes.nil?
report_hashes(mssql_hashes,version_year)
end
end
end
@ -57,8 +97,10 @@ class Metasploit3 < Msf::Auxiliary
when "2000"
hashtype = "mssql"
when "2005", "2008", "2012", "2014"
when "2005", "2008"
hashtype = "mssql05"
when "2012", "2014"
hashtype = "mssql12"
end
this_service = report_service(