Skip to content

Commit 35b94b0

Browse files
author
Tod Beardsley
committed
Land rapid7#2889, WMI support
This depends on rapid7/meterpreter#69 to actually be useful.
2 parents d27264b + 9212013 commit 35b94b0

File tree

5 files changed

+199
-4
lines changed

5 files changed

+199
-4
lines changed

lib/rex/post/meterpreter/extensions/extapi/extapi.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require 'rex/post/meterpreter/extensions/extapi/service/service'
66
require 'rex/post/meterpreter/extensions/extapi/clipboard/clipboard'
77
require 'rex/post/meterpreter/extensions/extapi/adsi/adsi'
8+
require 'rex/post/meterpreter/extensions/extapi/wmi/wmi'
89

910
module Rex
1011
module Post
@@ -29,10 +30,11 @@ def initialize(client)
2930
'name' => 'extapi',
3031
'ext' => ObjectAliases.new(
3132
{
32-
'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client),
33-
'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client),
33+
'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client),
34+
'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client),
3435
'clipboard' => Rex::Post::Meterpreter::Extensions::Extapi::Clipboard::Clipboard.new(client),
35-
'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client)
36+
'adsi' => Rex::Post::Meterpreter::Extensions::Extapi::Adsi::Adsi.new(client),
37+
'wmi' => Rex::Post::Meterpreter::Extensions::Extapi::Wmi::Wmi.new(client)
3638
})
3739
},
3840
])

lib/rex/post/meterpreter/extensions/extapi/tlv.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ module Extapi
5757
TLV_TYPE_EXT_ADSI_MAXRESULTS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 60)
5858
TLV_TYPE_EXT_ADSI_PAGESIZE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 61)
5959

60+
TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 65)
61+
TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 66)
62+
TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 67)
63+
TLV_TYPE_EXT_WMI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 68)
64+
TLV_TYPE_EXT_WMI_FIELDS = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69)
65+
TLV_TYPE_EXT_WMI_VALUES = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70)
66+
TLV_TYPE_EXT_WMI_ERROR = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 71)
67+
6068
end
6169
end
6270
end
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# -*- coding: binary -*-
2+
3+
module Rex
4+
module Post
5+
module Meterpreter
6+
module Extensions
7+
module Extapi
8+
module Wmi
9+
10+
###
11+
#
12+
# This meterpreter extension contains extended API functions for
13+
# performing WMI queries.
14+
#
15+
###
16+
class Wmi
17+
18+
def initialize(client)
19+
@client = client
20+
end
21+
22+
#
23+
# Perform a generic wmi query against the target machine.
24+
#
25+
# @param query [String] The WMI query string.
26+
# @param root [String] Specify root to target, otherwise defaults
27+
# to 'root\cimv2'
28+
#
29+
# @returns [Hash] Array of field names with associated values.
30+
#
31+
def query(query, root = nil)
32+
request = Packet.create_request('extapi_wmi_query')
33+
34+
request.add_tlv(TLV_TYPE_EXT_WMI_DOMAIN, root) unless root.blank?
35+
request.add_tlv(TLV_TYPE_EXT_WMI_QUERY, query)
36+
37+
response = client.send_request(request)
38+
39+
# Bomb out with the right error messa
40+
error_msg = response.get_tlv_value(TLV_TYPE_EXT_WMI_ERROR)
41+
raise error_msg if error_msg
42+
43+
fields = []
44+
fields_tlv = response.get_tlv(TLV_TYPE_EXT_WMI_FIELDS)
45+
46+
# If we didn't get any fields back, then we didn't get any results.
47+
# The reason is because without results, we don't know which fields
48+
# were requested in the first place
49+
return nil unless fields_tlv
50+
51+
fields_tlv.each(TLV_TYPE_EXT_WMI_FIELD) { |f|
52+
fields << f.value
53+
}
54+
55+
values = []
56+
response.each(TLV_TYPE_EXT_WMI_VALUES) { |r|
57+
value = []
58+
r.each(TLV_TYPE_EXT_WMI_VALUE) { |v|
59+
value << v.value
60+
}
61+
values << value
62+
}
63+
64+
return {
65+
:fields => fields,
66+
:values => values
67+
}
68+
end
69+
70+
attr_accessor :client
71+
72+
end
73+
74+
end; end; end; end; end; end
75+

lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Console::CommandDispatcher::Extapi
1717
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/service'
1818
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard'
1919
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi'
20+
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi'
2021

2122
Klass = Console::CommandDispatcher::Extapi
2223

@@ -25,7 +26,8 @@ class Console::CommandDispatcher::Extapi
2526
Klass::Window,
2627
Klass::Service,
2728
Klass::Clipboard,
28-
Klass::Adsi
29+
Klass::Adsi,
30+
Klass::Wmi
2931
]
3032

3133
include Console::CommandDispatcher
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# -*- coding: binary -*-
2+
require 'rex/post/meterpreter'
3+
4+
module Rex
5+
module Post
6+
module Meterpreter
7+
module Ui
8+
9+
###
10+
#
11+
# Extended API WMI Querying interface.
12+
#
13+
###
14+
class Console::CommandDispatcher::Extapi::Wmi
15+
16+
Klass = Console::CommandDispatcher::Extapi::Wmi
17+
18+
include Console::CommandDispatcher
19+
20+
# Zero indicates "no limit"
21+
DEFAULT_MAX_RESULTS = 0
22+
DEFAULT_PAGE_SIZE = 0
23+
24+
#
25+
# List of supported commands.
26+
#
27+
def commands
28+
{
29+
"wmi_query" => "Perform a generic WMI query and return the results"
30+
}
31+
end
32+
33+
#
34+
# Name for this dispatcher
35+
#
36+
def name
37+
"Extapi: WMI Querying"
38+
end
39+
40+
#
41+
# Options for the wmi_query command.
42+
#
43+
@@wmi_query_opts = Rex::Parser::Arguments.new(
44+
"-h" => [ false, "Help banner" ],
45+
"-r" => [ true, "Specify a different root object (defaults to 'root\\CIMV2')" ]
46+
)
47+
48+
def wmi_query_usage
49+
print(
50+
"\nUsage: wmi_query <query string> [-r root]\n\n" +
51+
"Query the target and display the results.\n\n" +
52+
@@wmi_query_opts.usage)
53+
end
54+
55+
#
56+
# Enumerate WMI objects.
57+
#
58+
def cmd_wmi_query(*args)
59+
args.unshift("-h") if args.length < 1
60+
61+
root = nil
62+
63+
@@wmi_query_opts.parse(args) { |opt, idx, val|
64+
case opt
65+
when "-r"
66+
root = val
67+
when "-h"
68+
wmi_query_usage
69+
return true
70+
end
71+
}
72+
73+
query = args.shift
74+
75+
objects = client.extapi.wmi.query(query, root)
76+
77+
if objects
78+
table = Rex::Ui::Text::Table.new(
79+
'Header' => query,
80+
'Indent' => 0,
81+
'SortIndex' => 0,
82+
'Columns' => objects[:fields]
83+
)
84+
85+
objects[:values].each do |c|
86+
table << c
87+
end
88+
89+
print_line
90+
print_line(table.to_s)
91+
92+
print_line("Total objects: #{objects[:values].length}")
93+
else
94+
print_status("The WMI query yielded no results.")
95+
end
96+
97+
print_line
98+
99+
return true
100+
end
101+
102+
end
103+
104+
end
105+
end
106+
end
107+
end
108+

0 commit comments

Comments
 (0)