Skip to content

Commit 8b8e5e4

Browse files
OJBrent Cook
authored andcommitted
First iteration of the pivot menu for meterpreter
1 parent d525b01 commit 8b8e5e4

File tree

4 files changed

+167
-16
lines changed

4 files changed

+167
-16
lines changed

lib/rex/post/meterpreter/packet_dispatcher.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,16 +561,16 @@ def initialize_inbound_handlers
561561
def dispatch_inbound_packet(packet)
562562
handled = false
563563

564-
pivot = self.find_pivot(packet.session_guid)
564+
pivot_session = self.find_pivot_session(packet.session_guid)
565565

566566
tlv_enc_key = self.tlv_enc_key
567-
tlv_enc_key = pivot.pivoted_session.tlv_enc_key if pivot
567+
tlv_enc_key = pivot_session.pivoted_session.tlv_enc_key if pivot_session
568568

569569
packet.from_r(tlv_enc_key)
570570

571571
# Update our last reply time
572572
self.last_checkin = Time.now
573-
pivot.pivoted_session.last_checkin = self.last_checkin if pivot
573+
pivot_session.pivoted_session.last_checkin = self.last_checkin if pivot_session
574574

575575
# If the packet is a response, try to notify any potential
576576
# waiters

lib/rex/post/meterpreter/pivot.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ def initialize(session_class, display_name)
1919
self.session_class = session_class
2020
self.display_name = display_name
2121
end
22+
23+
def to_row
24+
[self.id.unpack('H*')[0], display_name]
25+
end
2226
end
2327

2428
class Pivot
@@ -41,13 +45,13 @@ def request_handler(client, packet)
4145
if packet.method == 'core_pivot_session_new'
4246
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
4347
listener_id = packet.get_tlv_value(TLV_TYPE_PIVOT_ID)
44-
client.add_pivot(Pivot.new(client, session_guid, listener_id))
48+
client.add_pivot_session(Pivot.new(client, session_guid, listener_id))
4549
elsif packet.method == 'core_pivot_session_died'
4650
session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID)
47-
pivot = client.find_pivot(session_guid)
51+
pivot = client.find_pivot_session(session_guid)
4852
if pivot
4953
pivot.pivoted_session.kill('Died')
50-
client.remove_pivot(session_guid)
54+
client.remove_pivot_session(session_guid)
5155
end
5256
end
5357
true

lib/rex/post/meterpreter/pivot_container.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ module PivotContainer
1616
# Initializes the pivot association hash
1717
#
1818
def initialize_pivots
19-
self.pivots = {}
19+
self.pivot_sessions = {}
2020
self.pivot_listeners = {}
2121
end
2222

2323
#
2424
# Adds a pivot to the container that is indexed by the pivoted
2525
# session guid.
2626
#
27-
def add_pivot(pivot)
28-
self.pivots[pivot.pivoted_session.session_guid] = pivot
27+
def add_pivot_session(pivot)
28+
self.pivot_sessions[pivot.pivoted_session.session_guid] = pivot
2929
end
3030

3131
def add_pivot_listener(listener)
@@ -35,8 +35,8 @@ def add_pivot_listener(listener)
3535
#
3636
# Looks up a pivot instance based on its pivoted session guid.
3737
#
38-
def find_pivot(pivot_session_guid)
39-
return self.pivots[pivot_session_guid]
38+
def find_pivot_session(pivot_session_guid)
39+
return self.pivot_sessions[pivot_session_guid]
4040
end
4141

4242
def find_pivot_listener(listener_id)
@@ -46,24 +46,24 @@ def find_pivot_listener(listener_id)
4646
#
4747
# Removes a pivot based on its pivoted session guid.
4848
#
49-
def remove_pivot(pivot_session_guid)
50-
return self.pivots.delete(pivot_session_guid)
49+
def remove_pivot_session(pivot_session_guid)
50+
return self.pivot_sessions.delete(pivot_session_guid)
5151
end
5252

5353
def remove_pivot_listener(listener_id)
5454
return self.pivot_listeners.delete(listener_id)
5555
end
5656

5757
#
58-
# The hash of pivots.
58+
# The hash of pivot sessions.
5959
#
60-
attr_reader :pivots
60+
attr_reader :pivot_sessions
6161

6262
attr_reader :pivot_listeners
6363

6464
protected
6565

66-
attr_writer :pivots # :nodoc:
66+
attr_writer :pivot_sessions # :nodoc:
6767

6868
attr_writer :pivot_listeners # :nodoc:
6969

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

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ def commands
8383
if client.passive_service && client.sock.type? == 'tcp-ssl'
8484
c['ssl_verify'] = 'Modify the SSL certificate verification setting'
8585
end
86+
87+
c['pivot'] = 'Manage pivot listeners'
8688
end
8789

8890
if client.platform == 'windows' || client.platform == 'linux'
@@ -119,6 +121,151 @@ def name
119121
'Core'
120122
end
121123

124+
@@pivot_opts = Rex::Parser::Arguments.new(
125+
'-t' => [true, 'Pivot listener type'],
126+
'-i' => [true, 'Identifier of the pivot to remove'],
127+
'-l' => [true, 'Host address to bind to (if applicable)'],
128+
'-n' => [true, 'Name of the listener entity (if applicable)'],
129+
'-a' => [true, 'Architecture of the stage to generate'],
130+
'-p' => [true, 'Platform of the stage to generate'],
131+
'-h' => [false, 'View help']
132+
)
133+
134+
@@pivot_supported_archs = [ARCH_X64, ARCH_X86]
135+
@@pivot_supported_platforms = ['windows']
136+
137+
def cmd_pivot_help
138+
print_line('Usage: pivot <list|add|remove> [options]')
139+
print_line
140+
print_line('Manage pivot listeners on the target.')
141+
print_line
142+
print_line(@@pivot_opts.usage)
143+
print_line
144+
print_line('Supported pivot types:')
145+
print_line(' - pipe (using named pipes over SMB)')
146+
print_line('Supported arhiectures:')
147+
@@pivot_supported_archs.each do |a|
148+
print_line(' - ' + a)
149+
end
150+
print_line('Supported platforms:')
151+
print_line(' - windows')
152+
print_line
153+
print_line("eg. pivot add -t pipe -l 192.168.0.1 -n msf-pipe -a #{@@pivot_supported_archs.first} -p windows")
154+
print_line(" pivot list")
155+
print_line(" pivot remove -i 1")
156+
print_line
157+
end
158+
159+
def cmd_pivot(*args)
160+
if args.length == 0 || args.include?('-h')
161+
cmd_pivot_help
162+
return true
163+
end
164+
165+
opts = {}
166+
@@pivot_opts.parse(args) { |opt, idx, val|
167+
case opt
168+
when '-t'
169+
opts[:type] = val
170+
when '-i'
171+
opts[:guid] = val
172+
when '-l'
173+
opts[:lhost] = val
174+
when '-n'
175+
opts[:name] = val
176+
when '-a'
177+
opts[:arch] = val
178+
when '-p'
179+
opts[:platform] = val
180+
end
181+
}
182+
183+
# first parameter is the command
184+
case args[0]
185+
when 'remove', 'del', 'delete', 'rm'
186+
unless opts[:guid]
187+
print_error('Pivot listener ID must be specified (-i)')
188+
return false
189+
end
190+
191+
unless opts[:guid] =~ /^[0-9a-f]{32}/i && opts[:guid].length == 32
192+
print_error("Invalid pivot listener ID: #{opts[:guid]}")
193+
return false
194+
end
195+
196+
listener_id = [opts[:guid]].pack('H*')
197+
unless client.find_pivot_listener(listener_id)
198+
print_error("Unknown pivot listener ID: #{opts[:guid]}")
199+
return false
200+
end
201+
202+
Pivot.remove_listener(client, listener_id)
203+
print_good("Successfully removed pivot: #{opts[:guid]}")
204+
when 'list', 'show', 'print'
205+
tbl = Rex::Text::Table.new(
206+
'Header' => 'Currently active pivot listeners',
207+
'Indent' => 4,
208+
'Columns' => ['Id', 'Detail'])
209+
210+
client.pivot_listeners.each do |k, v|
211+
tbl << v.to_row
212+
end
213+
print_line("\n#{tbl}\n")
214+
when 'add'
215+
unless opts[:type]
216+
print_error('Pivot type must be specified (-t)')
217+
return false
218+
end
219+
220+
unless opts[:arch]
221+
print_error('Architecture must be specified (-a)')
222+
return false
223+
end
224+
unless @@pivot_supported_archs.include?(opts[:arch])
225+
print_error("Unknown or unsupported architecture: #{opts[:arch]}")
226+
return false
227+
end
228+
229+
unless opts[:platform]
230+
print_error('Platform must be specified (-p)')
231+
return false
232+
end
233+
unless @@pivot_supported_platforms.include?(opts[:platform])
234+
print_error("Unknown or unsupported platform: #{opts[:platform]}")
235+
return false
236+
end
237+
238+
# currently only one pivot type supported, more to come we hope
239+
case opts[:type]
240+
when 'pipe'
241+
pivot_add_named_pipe(opts)
242+
else
243+
print_error("Unknown pivot type: #{opts[:type]}")
244+
return false
245+
end
246+
else
247+
print_error("Unknown command: #{args[0]}")
248+
end
249+
end
250+
251+
def pivot_add_named_pipe(opts)
252+
unless opts[:lhost]
253+
print_error('Pipe host must be specified (-l)')
254+
return false
255+
end
256+
257+
unless opts[:name]
258+
print_error('Pipe name must be specified (-n)')
259+
return false
260+
end
261+
262+
# reconfigure the opts so that they can be passed to the setup function
263+
opts[:pipe_host] = opts[:lhost]
264+
opts[:pipe_name] = opts[:name]
265+
Pivot.create_named_pipe_listener(client, opts)
266+
print_good("Successfully created #{opts[:type]} pivot.")
267+
end
268+
122269
def cmd_sessions_help
123270
print_line('Usage: sessions <id>')
124271
print_line

0 commit comments

Comments
 (0)