From 69abffaff6ec8708c41b91c30d60abd2ac41bdfa Mon Sep 17 00:00:00 2001 From: OJ Date: Thu, 16 Jan 2014 13:47:46 +1000 Subject: [PATCH] First pass of WMI support Close but more to do. --- .../meterpreter/extensions/extapi/extapi.rb | 8 +- .../post/meterpreter/extensions/extapi/tlv.rb | 7 ++ .../meterpreter/extensions/extapi/wmi/wmi.rb | 65 +++++++++++ .../ui/console/command_dispatcher/extapi.rb | 4 +- .../console/command_dispatcher/extapi/wmi.rb | 104 ++++++++++++++++++ 5 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb create mode 100644 lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb diff --git a/lib/rex/post/meterpreter/extensions/extapi/extapi.rb b/lib/rex/post/meterpreter/extensions/extapi/extapi.rb index 08408e3489..31a3cd45af 100644 --- a/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +++ b/lib/rex/post/meterpreter/extensions/extapi/extapi.rb @@ -5,6 +5,7 @@ require 'rex/post/meterpreter/extensions/extapi/window/window' require 'rex/post/meterpreter/extensions/extapi/service/service' require 'rex/post/meterpreter/extensions/extapi/clipboard/clipboard' require 'rex/post/meterpreter/extensions/extapi/adsi/adsi' +require 'rex/post/meterpreter/extensions/extapi/wmi/wmi' module Rex module Post @@ -29,10 +30,11 @@ class Extapi < Extension 'name' => 'extapi', 'ext' => ObjectAliases.new( { - 'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client), - 'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client), + 'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client), + 'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client), 'clipboard' => Rex::Post::Meterpreter::Extensions::Extapi::Clipboard::Clipboard.new(client), - 'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client) + 'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client), + 'wmi' => Rex::Post::Meterpreter::Extensions::Extapi::Wmi::Wmi.new(client) }) }, ]) diff --git a/lib/rex/post/meterpreter/extensions/extapi/tlv.rb b/lib/rex/post/meterpreter/extensions/extapi/tlv.rb index 132230e3ca..1f93c97067 100644 --- a/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/extapi/tlv.rb @@ -48,6 +48,13 @@ TLV_TYPE_EXT_ADSI_RESULT = TLV_META_TYPE_GROUP | (TLV_TYPE_E TLV_TYPE_EXT_ADSI_MAXRESULTS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 60) TLV_TYPE_EXT_ADSI_PAGESIZE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 61) +TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 65) +TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 66) +TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 67) +TLV_TYPE_EXT_WMI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 68) +TLV_TYPE_EXT_WMI_FIELDS = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69) +TLV_TYPE_EXT_WMI_VALUES = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70) + end end end diff --git a/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb b/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb new file mode 100644 index 0000000000..5cce2eade1 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb @@ -0,0 +1,65 @@ +# -*- coding: binary -*- + +module Rex +module Post +module Meterpreter +module Extensions +module Extapi +module Wmi + +### +# +# This meterpreter extension contains extended API functions for +# performing WMI queries. +# +### +class Wmi + + def initialize(client) + @client = client + end + + # + # Perform a generic wmi query against the target machine. + # + # @param query [String] The WMI query string. + # @param domain_name [String] Specify to target something other + # than 'cimv2' + # + # @returns [Hash] Array of field names with associated values. + # + def query(query, domain_name = nil) + request = Packet.create_request('extapi_wmi_query') + + request.add_tlv(TLV_TYPE_EXT_WMI_DOMAIN, domain_name) unless domain_name.blank? + request.add_tlv(TLV_TYPE_EXT_WMI_QUERY, query) + + response = client.send_request(request) + + fields = [] + fields_tlv = response.get_tlv(TLV_TYPE_EXT_WMI_FIELDS) + fields_tlv.each(TLV_TYPE_EXT_WMI_FIELD) { |f| + fields << f.value + } + + values = [] + response.each(TLV_TYPE_EXT_WMI_VALUES) { |r| + value = [] + r.each(TLV_TYPE_EXT_WMI_VALUE) { |v| + value << v.value + } + values << value + } + + return { + :fields => fields, + :values => values + } + 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 40df85f5f8..326c837d3f 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb @@ -17,6 +17,7 @@ class Console::CommandDispatcher::Extapi require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/service' require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard' require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi' + require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi' Klass = Console::CommandDispatcher::Extapi @@ -25,7 +26,8 @@ class Console::CommandDispatcher::Extapi Klass::Window, Klass::Service, Klass::Clipboard, - Klass::Adsi + Klass::Adsi, + Klass::Wmi ] include Console::CommandDispatcher diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb new file mode 100644 index 0000000000..a039a826fa --- /dev/null +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb @@ -0,0 +1,104 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter' + +module Rex +module Post +module Meterpreter +module Ui + +### +# +# Extended API WMI Querying interface. +# +### +class Console::CommandDispatcher::Extapi::Wmi + + Klass = Console::CommandDispatcher::Extapi::Wmi + + include Console::CommandDispatcher + + # Zero indicates "no limit" + DEFAULT_MAX_RESULTS = 0 + DEFAULT_PAGE_SIZE = 0 + + # + # List of supported commands. + # + def commands + { + "wmi_query" => "Perform a generic WMI query and return the results" + } + end + + # + # Name for this dispatcher + # + def name + "Extapi: WMI Querying" + end + + # + # Options for the wmi_query command. + # + @@wmi_query_opts = Rex::Parser::Arguments.new( + "-h" => [ false, "Help banner" ], + "-d" => [ true, "Specify a domain (defaults to 'CIMV2')" ] + ) + + def wmi_query_usage + print( + "\nUsage: wmi_query [-d domain]\n\n" + + "Query the target and display the results.\n\n" + + @@wmi_query_opts.usage) + end + + # + # Enumerate domain objects. + # + def cmd_wmi_query(*args) + args.unshift("-h") if args.length < 1 + + domain = nil + + @@wmi_query_opts.parse(args) { |opt, idx, val| + case opt + when "-d" + domain = val + when "-h" + wmi_query_usage + return true + end + } + + query = args.shift + + objects = client.extapi.wmi.query(query, domain) + + table = Rex::Ui::Text::Table.new( + 'Header' => query, + 'Indent' => 0, + 'SortIndex' => 0, + 'Columns' => objects[:fields] + ) + + objects[:values].each do |c| + table << c + end + + print_line + print_line(table.to_s) + + print_line("Total objects: #{objects[:results].length}") + + print_line + + return true + end + +end + +end +end +end +end +