diff --git a/data/meterpreter/ext_server_extapi.x64.dll b/data/meterpreter/ext_server_extapi.x64.dll new file mode 100755 index 0000000000..021232b335 Binary files /dev/null and b/data/meterpreter/ext_server_extapi.x64.dll differ diff --git a/data/meterpreter/ext_server_extapi.x86.dll b/data/meterpreter/ext_server_extapi.x86.dll new file mode 100755 index 0000000000..d932645c99 Binary files /dev/null and b/data/meterpreter/ext_server_extapi.x86.dll differ diff --git a/lib/rex/post/meterpreter/extensions/extapi/extapi.rb b/lib/rex/post/meterpreter/extensions/extapi/extapi.rb index bc941a8cdd..55bd9ffdbb 100644 --- a/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +++ b/lib/rex/post/meterpreter/extensions/extapi/extapi.rb @@ -2,6 +2,8 @@ # -*- coding: binary -*- require 'rex/post/meterpreter/extensions/extapi/tlv' +require 'rex/post/meterpreter/extensions/extapi/window/window' +require 'rex/post/meterpreter/extensions/extapi/service/service' module Rex module Post @@ -12,11 +14,7 @@ module Extapi ### # # This meterpreter extension contains an extended API which will allow for more -# advanced enumeration of the victim. This includes detail of: -# * Active/open windows -# * Services -# * Clipboard -# ... and more. +# advanced enumeration of the victim. # ### class Extapi < Extension @@ -28,69 +26,15 @@ class Extapi < Extension [ { 'name' => 'extapi', - 'ext' => self + 'ext' => ObjectAliases.new( + { + 'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client), + 'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client) + }) }, ]) end - # Enumerate all the top-level windows on the target - def window_enum() - request = Packet.create_request('extapi_window_enum') - response = client.send_request(request) - - windows = [] - - response.each(TLV_TYPE_EXT_WINDOW_ENUM_GROUP) { |w| - windows << { - :pid => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_PID), - :handle => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_HANDLE), - :title => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_TITLE) - } - } - - return windows.sort_by { |w| w[:pid] } - end - - # Enumerate all the services on the target. - def service_enum() - request = Packet.create_request('extapi_service_enum') - response = client.send_request(request) - - services = [] - - response.each(TLV_TYPE_EXT_SERVICE_ENUM_GROUP) { |s| - services << { - :name => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_NAME), - :display => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME), - :pid => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_PID), - :status => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_STATUS), - :interactive => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE) - } - } - - return services.sort_by { |s| s[:name].upcase } - end - - # Query some detailed parameters about a particular service. - def service_query(service_name) - request = Packet.create_request('extapi_service_query') - request.add_tlv(TLV_TYPE_EXT_SERVICE_ENUM_NAME, service_name) - - response = client.send_request(request) - - detail = { - :starttype => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE), - :display => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME), - :startname => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME), - :path => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_PATH), - :logroup => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP), - :interactive => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE), - :dacl => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DACL) - } - - return detail - end - end end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/extapi/service/service.rb b/lib/rex/post/meterpreter/extensions/extapi/service/service.rb new file mode 100644 index 0000000000..f4f7bda2f0 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/extapi/service/service.rb @@ -0,0 +1,67 @@ +#!/usr/bin/env ruby +# -*- coding: binary -*- + +module Rex +module Post +module Meterpreter +module Extensions +module Extapi +module Service + +### +# +# This meterpreter extension contains extended API functions for +# querying and managing Windows services. +# +### +class Service + + def initialize(client) + @client = client + end + + # Enumerate all the services on the target. + def service_enum() + request = Packet.create_request('extapi_service_enum') + response = client.send_request(request) + + services = [] + + response.each(TLV_TYPE_EXT_SERVICE_ENUM_GROUP) { |s| + services << { + :name => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_NAME), + :display => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME), + :pid => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_PID), + :status => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_STATUS), + :interactive => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE) + } + } + + return services.sort_by { |s| s[:name].upcase } + end + + # Query some detailed parameters about a particular service. + def service_query(service_name) + request = Packet.create_request('extapi_service_query') + request.add_tlv(TLV_TYPE_EXT_SERVICE_ENUM_NAME, service_name) + + response = client.send_request(request) + + detail = { + :starttype => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE), + :display => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME), + :startname => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME), + :path => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_PATH), + :logroup => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP), + :interactive => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE), + :dacl => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DACL) + } + + return detail + end + + attr_accessor :client + +end + +end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/extapi/window/window.rb b/lib/rex/post/meterpreter/extensions/extapi/window/window.rb new file mode 100644 index 0000000000..d219f32f11 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/extapi/window/window.rb @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +# -*- coding: binary -*- + +module Rex +module Post +module Meterpreter +module Extensions +module Extapi +module Window + +### +# +# This meterpreter extension contains extended API functions for +# querying and managing desktop windows. +# +### +class Window + + def initialize(client) + @client = client + end + + # Enumerate all the top-level windows on the target + def window_enum() + request = Packet.create_request('extapi_window_enum') + response = client.send_request(request) + + windows = [] + + response.each(TLV_TYPE_EXT_WINDOW_ENUM_GROUP) { |w| + windows << { + :pid => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_PID), + :handle => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_HANDLE), + :title => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_TITLE) + } + } + + windows.sort_by { |w| w[:pid] } + end + + attr_accessor :client + +end + +end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb index 4facb7fc6f..a67b38b764 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb @@ -1,5 +1,6 @@ # -*- coding: binary -*- require 'rex/post/meterpreter' + module Rex module Post module Meterpreter @@ -12,8 +13,17 @@ module Ui ### class Console::CommandDispatcher::Extapi + require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/window' + require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/service' + Klass = Console::CommandDispatcher::Extapi + Dispatchers = + [ + Klass::Window, + Klass::Service + ] + include Console::CommandDispatcher # @@ -21,162 +31,24 @@ class Console::CommandDispatcher::Extapi # def initialize(shell) super + + Dispatchers.each { |d| shell.enstack_dispatcher(d) } end # - # Options for the window_enum command. - # - @@window_enum_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner" ] - ) - - # - # Options for the service_enum command. - # - @@service_enum_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner" ] - ) - - # - # Options for the service_query command. - # - @@service_query_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner" ] - ) - # # List of supported commands. # def commands { - "window_enum" => "Enumerate all current open windows", - "service_enum" => "Enumerate all registered Windows services", - "service_query" => "Query more detail about a specific Windows service" } end - - def cmd_window_enum(*args) - - @@window_enum_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print( - "\nUsage: window_enum [-h]\n\n" + - "Enumerate the top-level windows on the current desktop.\n\n" + - "Enumeration returns the Process ID and Window Handle for each top-level\n" + - "window found. The Window Handle can be used for further calls to the\n" + - "railgun API.\n\n") - return true - end - } - - windows = client.extapi.window_enum() - - print_line() - print_line(" PID | Handle | Window title") - print_line("-------------------------------------------------------------") - - windows.each do |w| - print_line(sprintf("%8d | %10d | %s", w[:pid], w[:handle], w[:title])) - end - - print_line() - print_line("Total top-level Windows: #{windows.length}") - print_line() - - return true - end - - def cmd_service_enum(*args) - @@service_enum_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print( - "\nUsage: service_enum [-h]\n\n" + - "Enumerate services installed on the target.\n\n" + - "Enumeration returns the Process ID, Status, and name of each installed\n" + - "service that is discovered. The 'Int?' value indicates if the service is\n" + - "able to interact with the desktop.\n\n") - return true - end - } - - status_map = { - 1 => "STOPPED", - 2 => "STRT_PEN", - 3 => "STOP_PEN", - 4 => "RUNNING", - 5 => "CONT_PEN", - 6 => "PAUS_PEN", - 7 => "PAUSED" - } - - services = client.extapi.service_enum() - - print_line() - print_line(" Int? | PID | Status | Name (Display Name)") - print_line("-------------------------------------------------------------") - - services.each do |s| - print_line(sprintf("%5s | %8d | %8s | %s (%s)", - s[:interactive] ? "Yes" : "No", - s[:pid], status_map[s[:status]], - s[:name], s[:display])) - end - - print_line() - print_line("Total services: #{services.length}") - print_line() - - return true - end - - def cmd_service_query(*args) - args << "-h" if args.length == 0 - - @@service_query_opts.parse(args) { |opt, idx, val| - case opt - when "-h" - print( - "\nUsage: service_query [-h] \n" + - " : The name of the service to query.\n\n" + - "Gets details information about a particular Windows service, including\n" + - "binary path, DACL, load order group, start type and more.\n\n") - return true - end - } - - service_name = args.shift - - start_type_map = { - 0 => "Boot", - 1 => "System", - 2 => "Automatic", - 3 => "Manual", - 4 => "Disabled" - } - - detail = client.extapi.service_query(service_name) - - print_line() - print_line("Name : #{service_name}") - print_line("Display : #{detail[:display]}") - print_line("Account : #{detail[:startname]}") - print_line("Start Type : #{start_type_map[detail[:starttype]]}") - print_line("Path : #{detail[:path]}") - print_line("L.O. Group : #{detail[:logroup]}") - print_line("Interactive : #{detail[:interactive] ? "Yes" : "No"}") - print_line("DACL : #{detail[:dacl]}") - print_line() - - end - # # Name for this dispatcher # def name - "Extapi" + "Extended API Extension" end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb new file mode 100644 index 0000000000..446aea9c80 --- /dev/null +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb @@ -0,0 +1,147 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter' + +module Rex +module Post +module Meterpreter +module Ui + +### +# +# Extended API window management user interface. +# +### +class Console::CommandDispatcher::Extapi::Service + + Klass = Console::CommandDispatcher::Extapi::Service + + include Console::CommandDispatcher + + # + # List of supported commands. + # + def commands + { + "service_enum" => "Enumerate all registered Windows services", + "service_query" => "Query more detail about a specific Windows service" + } + end + + # + # Name for this dispatcher + # + def name + "Extapi: Service Management" + end + # + # Options for the service_enum command. + # + @@service_enum_opts = Rex::Parser::Arguments.new( + "-h" => [ false, "Help banner" ] + ) + + # + # Query a single service for more detail. + # + def cmd_service_enum(*args) + @@service_enum_opts.parse(args) { |opt, idx, val| + case opt + when "-h" + print( + "\nUsage: service_enum [-h]\n\n" + + "Enumerate services installed on the target.\n\n" + + "Enumeration returns the Process ID, Status, and name of each installed\n" + + "service that was enumerated. The 'Int' value indicates if the service is\n" + + "able to interact with the desktop.\n\n") + return true + end + } + + status_map = { + 1 => "Stopped", + 2 => "Starting", + 3 => "Stopping", + 4 => "Running", + 5 => "Continuing", + 6 => "Pausing", + 7 => "Paused" + } + + services = client.extapi.service.service_enum() + + print_line() + print_line(" PID | Status | Int | Name (Display Name)") + print_line("----------+------------+-----+-------------------------------") + + services.each do |s| + print_line(sprintf(" %8d | %-10s | %s | %s (%s)", + s[:pid], status_map[s[:status]], + s[:interactive] ? "Y" : "N", + s[:name], s[:display])) + end + + print_line() + print_line("Total services: #{services.length}") + print_line() + + return true + end + + # + # Options for the service_query command. + # + @@service_query_opts = Rex::Parser::Arguments.new( + "-h" => [ false, "Help banner" ] + ) + + # + # Query a single service for more detail. + # + def cmd_service_query(*args) + args << "-h" if args.length == 0 + + @@service_query_opts.parse(args) { |opt, idx, val| + case opt + when "-h" + print( + "\nUsage: service_query [-h] \n" + + " : The name of the service to query.\n\n" + + "Gets details information about a particular Windows service, including\n" + + "binary path, DACL, load order group, start type and more.\n\n") + return true + end + } + + service_name = args.shift + + start_type_map = { + 0 => "Boot", + 1 => "System", + 2 => "Automatic", + 3 => "Manual", + 4 => "Disabled" + } + + detail = client.extapi.service.service_query(service_name) + + print_line() + print_line("Name : #{service_name}") + print_line("Display : #{detail[:display]}") + print_line("Account : #{detail[:startname]}") + print_line("Start Type : #{start_type_map[detail[:starttype]]}") + print_line("Path : #{detail[:path]}") + print_line("L.O. Group : #{detail[:logroup]}") + print_line("Interactive : #{detail[:interactive] ? "Yes" : "No"}") + print_line("DACL : #{detail[:dacl]}") + print_line() + + end + +end + +end +end +end +end + + diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb new file mode 100644 index 0000000000..f5889edb4e --- /dev/null +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb @@ -0,0 +1,84 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter' + +module Rex +module Post +module Meterpreter +module Ui + +### +# +# Extended API window management user interface. +# +### +class Console::CommandDispatcher::Extapi::Window + + Klass = Console::CommandDispatcher::Extapi::Window + + include Console::CommandDispatcher + + # + # List of supported commands. + # + def commands + { + "window_enum" => "Enumerate all current open windows" + } + end + + # + # Name for this dispatcher + # + def name + "Extapi: Window Management" + end + + # + # Options for the window_enum command. + # + @@window_enum_opts = Rex::Parser::Arguments.new( + "-h" => [ false, "Help banner" ] + ) + + # + # Enumerate top-level windows. + # + def cmd_window_enum(*args) + + @@window_enum_opts.parse(args) { |opt, idx, val| + case opt + when "-h" + print( + "\nUsage: window_enum [-h]\n\n" + + "Enumerate the top-level windows on the current desktop.\n\n" + + "Enumeration returns the Process ID and Window Handle for each top-level\n" + + "window found. The Window Handle can be used for further calls to the\n" + + "railgun API.\n\n") + return true + end + } + + windows = client.extapi.window.window_enum() + + print_line() + print_line(" PID | Handle | Window title") + print_line("---------+------------+--------------------------------------") + + windows.each do |w| + print_line(sprintf("%8d | %10d | %s", w[:pid], w[:handle], w[:title])) + end + + print_line() + print_line("Total top-level Windows: #{windows.length}") + print_line() + + return true + end + +end + +end +end +end +end +