Skip to content

Commit eeb5144

Browse files
author
Brent Cook
committed
Land rapid7#8932, Packet-level pivot support and named pipe transports
2 parents 36bbe00 + b9fdca0 commit eeb5144

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1583
-219
lines changed

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ PATH
1717
metasploit-concern
1818
metasploit-credential
1919
metasploit-model
20-
metasploit-payloads (= 1.3.1)
20+
metasploit-payloads (= 1.3.4)
2121
metasploit_data_models
2222
metasploit_payloads-mettle (= 0.2.2)
2323
msgpack
@@ -150,7 +150,7 @@ GEM
150150
activemodel (~> 4.2.6)
151151
activesupport (~> 4.2.6)
152152
railties (~> 4.2.6)
153-
metasploit-payloads (1.3.1)
153+
metasploit-payloads (1.3.4)
154154
metasploit_data_models (2.0.15)
155155
activerecord (~> 4.2.6)
156156
activesupport (~> 4.2.6)

lib/msf/base/serializer/readable_text.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ def self.dump_sessions(framework, opts={})
582582
row << 'N'
583583
end
584584

585-
if session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
585+
if session.exploit_datastore && session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
586586
row << " (#{session.exploit_datastore['LURI']})"
587587
else
588588
row << '?'
@@ -622,7 +622,7 @@ def self.dump_sessions_verbose(framework, opts={})
622622
sess_type = session.type.to_s
623623
sess_uuid = session.payload_uuid.to_s
624624
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
625-
sess_luri = session.exploit_datastore['LURI'] || ""
625+
sess_luri = session.exploit_datastore['LURI'] || "" if session.exploit_datastore
626626
sess_enc = false
627627
if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key]
628628
sess_enc = true
@@ -655,7 +655,7 @@ def self.dump_sessions_verbose(framework, opts={})
655655
out << " UUID: #{sess_uuid}\n"
656656
out << " CheckIn: #{sess_checkin}\n"
657657
out << " Registered: #{sess_registration}\n"
658-
unless sess_luri.empty?
658+
unless (sess_luri || '').empty?
659659
out << " LURI: #{sess_luri}\n"
660660
end
661661

lib/msf/base/sessions/meterpreter.rb

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ def supports_zlib?
4040
true
4141
end
4242

43+
def tunnel_to_s
44+
if self.pivot_session
45+
"Pivot via [#{self.pivot_session.tunnel_to_s}]"
46+
else
47+
super
48+
end
49+
end
50+
4351
#
4452
# Initializes a meterpreter session instance using the supplied rstream
4553
# that is to be used as the client's connection to the server.
@@ -112,6 +120,80 @@ def shell_init
112120

113121
end
114122

123+
def bootstrap(datastore = {}, handler = nil)
124+
session = self
125+
126+
init_session = Proc.new do
127+
# Configure unicode encoding before loading stdapi
128+
session.encode_unicode = datastore['EnableUnicodeEncoding']
129+
130+
session.init_ui(self.user_input, self.user_output)
131+
132+
session.tlv_enc_key = session.core.negotiate_tlv_encryption
133+
134+
unless datastore['AutoVerifySession'] == false
135+
unless session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i)
136+
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
137+
# Terminate the session without cleanup if it did not validate
138+
session.skip_cleanup = true
139+
session.kill
140+
return nil
141+
end
142+
end
143+
144+
# always make sure that the new session has a new guid if it's not already known
145+
guid = session.session_guid
146+
if guid == "\x00" * 16
147+
guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')
148+
session.core.set_session_guid(guid)
149+
session.session_guid = guid
150+
# TODO: New statgeless session, do some account in the DB so we can track it later.
151+
else
152+
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
153+
end
154+
155+
unless datastore['AutoLoadStdapi'] == false
156+
157+
session.load_stdapi
158+
159+
unless datastore['AutoSystemInfo'] == false
160+
session.load_session_info
161+
end
162+
163+
# only load priv on native windows
164+
# TODO: abastrct this too, to remove windows stuff
165+
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
166+
session.load_priv rescue nil
167+
end
168+
end
169+
170+
# TODO: abstract this a little, perhaps a "post load" function that removes
171+
# platform-specific stuff?
172+
if session.platform == 'android'
173+
session.load_android
174+
end
175+
176+
['InitialAutoRunScript', 'AutoRunScript'].each do |key|
177+
unless datastore[key].nil? || datastore[key].empty?
178+
args = Shellwords.shellwords(datastore[key])
179+
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
180+
session.execute_script(args.shift, *args)
181+
end
182+
end
183+
184+
# Process the auto-run scripts for this session
185+
if self.respond_to?(:process_autoruns)
186+
self.process_autoruns(datastore)
187+
end
188+
189+
# Tell the handler that we have a session
190+
handler.on_session(self) if handler
191+
end
192+
193+
# Defer the session initialization to the Session Manager scheduler
194+
framework.sessions.schedule init_session
195+
end
196+
115197
##
116198
# :category: Msf::Session::Provider::SingleCommandShell implementors
117199
#
@@ -255,14 +337,14 @@ def reset_ui
255337
#
256338
# Terminates the session
257339
#
258-
def kill
340+
def kill(reason='')
259341
begin
260342
cleanup_meterpreter
261343
self.sock.close if self.sock
262344
rescue ::Exception
263345
end
264346
# deregister will actually trigger another cleanup
265-
framework.sessions.deregister(self)
347+
framework.sessions.deregister(self, reason)
266348
end
267349

268350
#

lib/msf/base/sessions/meterpreter_options.rb

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -26,75 +26,6 @@ def initialize(info = {})
2626
], self.class)
2727
end
2828

29-
#
30-
# Once a session is created, automatically load the stdapi extension if the
31-
# advanced option is set to true.
32-
#
33-
def on_session(session)
34-
init_session = Proc.new do
35-
# Configure unicode encoding before loading stdapi
36-
session.encode_unicode = datastore['EnableUnicodeEncoding']
37-
38-
session.init_ui(self.user_input, self.user_output)
39-
40-
print_good("negotiating tlv encryption")
41-
session.tlv_enc_key = session.core.negotiate_tlv_encryption
42-
print_good("negotiated tlv encryption")
43-
44-
if datastore['AutoVerifySession']
45-
if !session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i)
46-
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
47-
# Terminate the session without cleanup if it did not validate
48-
session.skip_cleanup = true
49-
session.kill
50-
return nil
51-
end
52-
end
53-
print_good("negotiated tlv encryption")
54-
55-
# always make sure that the new session has a new guid if it's not already known
56-
guid = session.session_guid
57-
if guid == '00000000-0000-0000-0000-000000000000'
58-
guid = SecureRandom.uuid
59-
session.core.set_session_guid(guid)
60-
session.session_guid = guid
61-
# TODO: New stageless session, do some account in the DB so we can track it later.
62-
else
63-
# TODO: This session was either staged or previously known, and so we shold do some accounting here!
64-
end
65-
66-
# Call registered on_session callbacks
67-
super
68-
69-
if datastore['AutoLoadStdapi']
70-
session.load_stdapi
71-
72-
if datastore['AutoSystemInfo']
73-
session.load_session_info
74-
end
75-
76-
# only load priv on native windows
77-
if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch)
78-
session.load_priv rescue nil
79-
end
80-
end
81-
82-
if session.platform == 'android'
83-
session.load_android
84-
end
85-
86-
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
87-
unless datastore[key].empty?
88-
args = Shellwords.shellwords( datastore[key] )
89-
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
90-
session.execute_script(args.shift, *args)
91-
end
92-
end
93-
end
94-
95-
# Defer the session initialization to the Session Manager scheduler
96-
framework.sessions.schedule init_session
97-
end
9829
end
9930
end
10031
end

lib/msf/core/handler.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,10 @@ def register_session(session)
244244
framework.sessions.register(session)
245245

246246
# Call the handler's on_session() method
247-
on_session(session)
248-
249-
# Process the auto-run scripts for this session
250-
if session.respond_to?('process_autoruns')
251-
session.process_autoruns(datastore)
247+
if session.respond_to?(:bootstrap)
248+
session.bootstrap(datastore, self)
249+
else
250+
on_session(session)
252251
end
253252

254253
# If there is an exploit associated with this payload, then let's notify
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# -*- coding: binary -*-
2+
require 'thread'
3+
require 'msf/core/post_mixin'
4+
5+
module Msf
6+
module Handler
7+
###
8+
#
9+
# TODO: docs
10+
#
11+
###
12+
module ReverseNamedPipe
13+
14+
include Msf::Handler
15+
16+
#
17+
# Returns the string representation of the handler type, in this case
18+
# 'reverse_named_pipe'.
19+
#
20+
def self.handler_type
21+
"reverse_named_pipe"
22+
end
23+
24+
#
25+
# Returns the connection-described general handler type, in this case
26+
# 'reverse'.
27+
#
28+
def self.general_handler_type
29+
"reverse"
30+
end
31+
32+
#
33+
# Initializes the reverse handler and ads the options that are required
34+
# for reverse named pipe payloads.
35+
#
36+
def initialize(info={})
37+
super
38+
39+
register_options([
40+
OptString.new('PIPENAME', [true, 'Name of the pipe to listen on', 'msf-pipe']),
41+
OptString.new('PIPEHOST', [true, 'Host of the pipe to connect to', '.'])
42+
], Msf::Handler::ReverseNamedPipe)
43+
end
44+
45+
#
46+
# Closes the listener socket if one was created.
47+
#
48+
def cleanup_handler
49+
# we're just pretending to be a handler
50+
end
51+
52+
# A string suitable for displaying to the user
53+
#
54+
# @return [String]
55+
def human_name
56+
"reverse named pipe"
57+
end
58+
59+
#
60+
# Starts monitoring for an inbound connection.
61+
#
62+
def start_handler
63+
# we're just pretending to be a handler
64+
end
65+
66+
#
67+
# Stops monitoring for an inbound connection.
68+
#
69+
def stop_handler
70+
# we're just pretending to be a handler
71+
end
72+
73+
end
74+
end
75+
end
76+

lib/msf/core/payload/stager.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,6 @@ def handle_connection(conn, opts={})
165165
# If the stage should be sent over the client connection that is
166166
# established (which is the default), then go ahead and transmit it.
167167
if (stage_over_connection?)
168-
opts = {}
169-
170168
if respond_to? :include_send_uuid
171169
if include_send_uuid
172170
uuid_raw = conn.get_once(16, 1)

0 commit comments

Comments
 (0)