Skip to content

Commit 45a0ac9

Browse files
committed
Land rapid7#2602, Windows Extended API
Retrieve clipboard data Retrieve window handles Retrieve service information
2 parents 0c5d748 + e5a92a1 commit 45a0ac9

File tree

12 files changed

+1048
-0
lines changed

12 files changed

+1048
-0
lines changed
97 KB
Binary file not shown.
81.5 KB
Binary file not shown.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# -*- coding: binary -*-
2+
3+
module Rex
4+
module Post
5+
module Meterpreter
6+
module Extensions
7+
module Extapi
8+
module Clipboard
9+
10+
###
11+
#
12+
# This meterpreter extension contains extended API functions for
13+
# querying and managing desktop windows.
14+
#
15+
###
16+
class Clipboard
17+
18+
def initialize(client)
19+
@client = client
20+
end
21+
22+
# Get the target clipboard data in whichever format we can
23+
# (if it's supported).
24+
def get_data(download = false)
25+
results = []
26+
27+
request = Packet.create_request('extapi_clipboard_get_data')
28+
29+
if download
30+
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD, true)
31+
end
32+
33+
response = client.send_request(request)
34+
35+
text = response.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT)
36+
37+
if text
38+
results << {
39+
:type => :text,
40+
:data => text
41+
}
42+
end
43+
44+
files = []
45+
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) { |f|
46+
files << {
47+
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
48+
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
49+
}
50+
}
51+
52+
if files.length > 0
53+
results << {
54+
:type => :files,
55+
:data => files
56+
}
57+
end
58+
59+
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
60+
if jpg
61+
results << {
62+
:type => :jpg,
63+
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX),
64+
:height => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY),
65+
:data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
66+
}
67+
end
68+
end
69+
70+
return results
71+
end
72+
73+
# Set the target clipboard data to a text value
74+
def set_text(text)
75+
request = Packet.create_request('extapi_clipboard_set_data')
76+
77+
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT, text)
78+
79+
response = client.send_request(request)
80+
81+
return true
82+
end
83+
84+
attr_accessor :client
85+
86+
end
87+
88+
end; end; end; end; end; end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# -*- coding: binary -*-
2+
3+
require 'rex/post/meterpreter/extensions/extapi/tlv'
4+
require 'rex/post/meterpreter/extensions/extapi/window/window'
5+
require 'rex/post/meterpreter/extensions/extapi/service/service'
6+
require 'rex/post/meterpreter/extensions/extapi/clipboard/clipboard'
7+
8+
module Rex
9+
module Post
10+
module Meterpreter
11+
module Extensions
12+
module Extapi
13+
14+
###
15+
#
16+
# This meterpreter extension contains an extended API which will allow for more
17+
# advanced enumeration of the victim.
18+
#
19+
###
20+
class Extapi < Extension
21+
22+
def initialize(client)
23+
super(client, 'extapi')
24+
25+
client.register_extension_aliases(
26+
[
27+
{
28+
'name' => 'extapi',
29+
'ext' => ObjectAliases.new(
30+
{
31+
'window' => Rex::Post::Meterpreter::Extensions::Extapi::Window::Window.new(client),
32+
'service' => Rex::Post::Meterpreter::Extensions::Extapi::Service::Service.new(client),
33+
'clipboard' => Rex::Post::Meterpreter::Extensions::Extapi::Clipboard::Clipboard.new(client)
34+
})
35+
},
36+
])
37+
end
38+
39+
end
40+
41+
end; end; end; end; end
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# -*- coding: binary -*-
2+
3+
module Rex
4+
module Post
5+
module Meterpreter
6+
module Extensions
7+
module Extapi
8+
module Service
9+
10+
###
11+
#
12+
# This meterpreter extension contains extended API functions for
13+
# querying and managing Windows services.
14+
#
15+
###
16+
class Service
17+
18+
def initialize(client)
19+
@client = client
20+
end
21+
22+
# Enumerate all the services on the target.
23+
def enumerate
24+
request = Packet.create_request('extapi_service_enum')
25+
response = client.send_request(request)
26+
27+
services = []
28+
29+
response.each(TLV_TYPE_EXT_SERVICE_ENUM_GROUP) { |s|
30+
services << {
31+
:name => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_NAME),
32+
:display => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME),
33+
:pid => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_PID),
34+
:status => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_STATUS),
35+
:interactive => s.get_tlv_value(TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE)
36+
}
37+
}
38+
39+
return services.sort_by { |s| s[:name].upcase }
40+
end
41+
42+
# Query some detailed parameters about a particular service.
43+
def query(service_name)
44+
request = Packet.create_request('extapi_service_query')
45+
request.add_tlv(TLV_TYPE_EXT_SERVICE_ENUM_NAME, service_name)
46+
47+
response = client.send_request(request)
48+
49+
detail = {
50+
:starttype => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE),
51+
:display => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME),
52+
:startname => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME),
53+
:path => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_PATH),
54+
:logroup => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP),
55+
:interactive => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE),
56+
:dacl => response.get_tlv_value(TLV_TYPE_EXT_SERVICE_QUERY_DACL)
57+
}
58+
59+
return detail
60+
end
61+
62+
attr_accessor :client
63+
64+
end
65+
66+
end; end; end; end; end; end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# -*- coding: binary -*-
2+
module Rex
3+
module Post
4+
module Meterpreter
5+
module Extensions
6+
module Extapi
7+
8+
TLV_TYPE_EXTENSION_EXTAPI = 0
9+
10+
TLV_TYPE_EXT_WINDOW_ENUM_GROUP = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 1)
11+
TLV_TYPE_EXT_WINDOW_ENUM_PID = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 2)
12+
TLV_TYPE_EXT_WINDOW_ENUM_HANDLE = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 3)
13+
TLV_TYPE_EXT_WINDOW_ENUM_TITLE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 4)
14+
TLV_TYPE_EXT_WINDOW_ENUM_INCLUDEUNKNOWN = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 5)
15+
16+
TLV_TYPE_EXT_SERVICE_ENUM_GROUP = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 10)
17+
TLV_TYPE_EXT_SERVICE_ENUM_NAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 11)
18+
TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 12)
19+
TLV_TYPE_EXT_SERVICE_ENUM_PID = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 13)
20+
TLV_TYPE_EXT_SERVICE_ENUM_STATUS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 14)
21+
TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 15)
22+
23+
TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 20)
24+
TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 21)
25+
TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 22)
26+
TLV_TYPE_EXT_SERVICE_QUERY_PATH = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 23)
27+
TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 24)
28+
TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 25)
29+
TLV_TYPE_EXT_SERVICE_QUERY_DACL = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 26)
30+
31+
TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 35)
32+
33+
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 40)
34+
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 41)
35+
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 42)
36+
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 43)
37+
38+
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 45)
39+
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 46)
40+
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 47)
41+
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 48)
42+
43+
end
44+
end
45+
end
46+
end
47+
end
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: binary -*-
2+
3+
module Rex
4+
module Post
5+
module Meterpreter
6+
module Extensions
7+
module Extapi
8+
module Window
9+
10+
###
11+
#
12+
# This meterpreter extension contains extended API functions for
13+
# querying and managing desktop windows.
14+
#
15+
###
16+
class Window
17+
18+
def initialize(client)
19+
@client = client
20+
end
21+
22+
# Enumerate all the windows on the target.
23+
# If the specified parent window is nil, then all top-level windows
24+
# are enumerated. Otherwise, all child windows of the specified
25+
# parent window are enumerated.
26+
def enumerate(include_unknown = false, parent_window = nil)
27+
request = Packet.create_request('extapi_window_enum')
28+
29+
if include_unknown
30+
request.add_tlv(TLV_TYPE_EXT_WINDOW_ENUM_INCLUDEUNKNOWN, true)
31+
end
32+
33+
if not parent_window.nil?
34+
request.add_tlv(TLV_TYPE_EXT_WINDOW_ENUM_HANDLE, parent_window)
35+
end
36+
37+
response = client.send_request(request)
38+
39+
windows = []
40+
41+
response.each(TLV_TYPE_EXT_WINDOW_ENUM_GROUP) { |w|
42+
windows << {
43+
:pid => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_PID),
44+
:handle => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_HANDLE),
45+
:title => w.get_tlv_value(TLV_TYPE_EXT_WINDOW_ENUM_TITLE)
46+
}
47+
}
48+
49+
windows.sort_by { |w| w[:pid] }
50+
end
51+
52+
attr_accessor :client
53+
54+
end
55+
56+
end; end; end; end; end; end
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 user interface.
12+
#
13+
###
14+
class Console::CommandDispatcher::Extapi
15+
16+
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/window'
17+
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/service'
18+
require 'rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard'
19+
20+
Klass = Console::CommandDispatcher::Extapi
21+
22+
Dispatchers =
23+
[
24+
Klass::Window,
25+
Klass::Service,
26+
Klass::Clipboard
27+
]
28+
29+
include Console::CommandDispatcher
30+
31+
#
32+
# Initializes an instance of the extended API command interaction.
33+
#
34+
def initialize(shell)
35+
super
36+
37+
Dispatchers.each { |d| shell.enstack_dispatcher(d) }
38+
end
39+
40+
#
41+
#
42+
# List of supported commands.
43+
#
44+
def commands
45+
{
46+
}
47+
end
48+
49+
#
50+
# Name for this dispatcher
51+
#
52+
def name
53+
"Extended API Extension"
54+
end
55+
56+
end
57+
58+
end
59+
end
60+
end
61+
end

0 commit comments

Comments
 (0)