Land #2889, WMI support
This depends on rapid7/meterpreter#69 to actually be useful.bug/bundler_fix
commit
35b94b04bf
|
@ -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)
|
||||
})
|
||||
},
|
||||
])
|
||||
|
|
|
@ -57,6 +57,14 @@ 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)
|
||||
TLV_TYPE_EXT_WMI_ERROR = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 71)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# -*- 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 root [String] Specify root to target, otherwise defaults
|
||||
# to 'root\cimv2'
|
||||
#
|
||||
# @returns [Hash] Array of field names with associated values.
|
||||
#
|
||||
def query(query, root = nil)
|
||||
request = Packet.create_request('extapi_wmi_query')
|
||||
|
||||
request.add_tlv(TLV_TYPE_EXT_WMI_DOMAIN, root) unless root.blank?
|
||||
request.add_tlv(TLV_TYPE_EXT_WMI_QUERY, query)
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
# Bomb out with the right error messa
|
||||
error_msg = response.get_tlv_value(TLV_TYPE_EXT_WMI_ERROR)
|
||||
raise error_msg if error_msg
|
||||
|
||||
fields = []
|
||||
fields_tlv = response.get_tlv(TLV_TYPE_EXT_WMI_FIELDS)
|
||||
|
||||
# If we didn't get any fields back, then we didn't get any results.
|
||||
# The reason is because without results, we don't know which fields
|
||||
# were requested in the first place
|
||||
return nil unless fields_tlv
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# -*- 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" ],
|
||||
"-r" => [ true, "Specify a different root object (defaults to 'root\\CIMV2')" ]
|
||||
)
|
||||
|
||||
def wmi_query_usage
|
||||
print(
|
||||
"\nUsage: wmi_query <query string> [-r root]\n\n" +
|
||||
"Query the target and display the results.\n\n" +
|
||||
@@wmi_query_opts.usage)
|
||||
end
|
||||
|
||||
#
|
||||
# Enumerate WMI objects.
|
||||
#
|
||||
def cmd_wmi_query(*args)
|
||||
args.unshift("-h") if args.length < 1
|
||||
|
||||
root = nil
|
||||
|
||||
@@wmi_query_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-r"
|
||||
root = val
|
||||
when "-h"
|
||||
wmi_query_usage
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
query = args.shift
|
||||
|
||||
objects = client.extapi.wmi.query(query, root)
|
||||
|
||||
if objects
|
||||
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[:values].length}")
|
||||
else
|
||||
print_status("The WMI query yielded no results.")
|
||||
end
|
||||
|
||||
print_line
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue