Metasploit-framework: [-] Session manipulation failed: undefined method `strip' for nil:NilClass

Created on 20 Sep 2019  路  5Comments  路  Source: rapid7/metasploit-framework

Steps to reproduce

How'd you do it?

1.msf5 exploit(linux/ssh/exagrid_known_privkey) > show options

Module options (exploit/linux/ssh/exagrid_known_privkey):

Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS x.x.x.x yes The target address range or CIDR identifier
RPORT 22 yes The target port

Payload options (cmd/unix/interact):

Name Current Setting Required Description


Exploit target:

Id Name


0 Universal

msf5 exploit(linux/ssh/exagrid_known_privkey) > run

[-] 180.250.166.130:22 SSH - Failed authentication
[+] Successful login
[*] Command shell session 7 opened (x.x.x.x:39715 -> x.x.x.x:22) at 2019-09-20 10:46:18 +0000

shell
[*] Trying to find binary(python) on target machine
[-] Session manipulation failed: undefined method strip' for nil:NilClass ["/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:326:inbinary_exists'", "/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:282:in cmd_shell'", "/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:604:inrun_builtin_cmd'", "/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:592:in run_single'", "/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:761:in_interact_stream'", "/rahasia/git/metasploit-framework/lib/msf/base/sessions/command_shell.rb:745:in _interact'", "/rahasia/git/metasploit-framework/lib/rex/ui/interactive.rb:51:ininteract'", "/rahasia/git/metasploit-framework/lib/msf/ui/console/command_dispatcher/core.rb:1364:in cmd_sessions'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:523:inrun_command'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:474:in block in run_single'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:ineach'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:in run_single'", "/rahasia/git/metasploit-framework/lib/msf/ui/console/command_dispatcher/exploit.rb:215:incmd_exploit'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:523:in run_command'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:474:inblock in run_single'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:in each'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/dispatcher_shell.rb:468:inrun_single'", "/rahasia/git/metasploit-framework/lib/rex/ui/text/shell.rb:151:in run'", "/rahasia/git/metasploit-framework/lib/metasploit/framework/command/console.rb:48:instart'", "/rahasia/git/metasploit-framework/lib/metasploit/framework/command/base.rb:82:in start'", "./msfconsole:49:in

'"]
msf5 exploit(linux/ssh/exagrid_known_privkey) >

  1. msf5 exploit(linux/ssh/exagrid_known_privkey) > version
    Framework: 5.0.47-dev-acb351ac44
    Console : 5.0.47-dev-acb351ac44
    msf5 exploit(linux/ssh/exagrid_known_privkey) > uname -a
    [*] exec: uname -a

Linux ubuntu-s-4vcpu-8gb-fra1-01 4.15.0-52-generic #56-Ubuntu SMP Tue Jun 4 22:49:08 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

bug confirmed library

Most helpful comment

Here's a rudimentary patch:

diff --git a/lib/msf/base/sessions/command_shell.rb b/lib/msf/base/sessions/command_shell.rb
index 72393cb53c..72c6bd1e7f 100644
--- a/lib/msf/base/sessions/command_shell.rb
+++ b/lib/msf/base/sessions/command_shell.rb
@@ -323,7 +323,7 @@ class CommandShell
   #
   def binary_exists(binary)
     print_status("Trying to find binary(#{binary}) on target machine")
-    binary_path = shell_command_token("which #{binary}").strip
+    binary_path = shell_command_token("which #{binary}").to_s.strip
     if binary_path.eql?("#{binary} not found")
       print_error(binary_path)
       return nil

But that doesn't fix the other fundamental issues in this code:

  #
  # Check if there is a binary in PATH env
  #
  def binary_exists(binary)
    print_status("Trying to find binary(#{binary}) on target machine")
    binary_path = shell_command_token("which #{binary}").strip
    if binary_path.eql?("#{binary} not found")
      print_error(binary_path)
      return nil
    else
      print_status("Found #{binary} at #{binary_path}")
      return binary_path
    end
  end

Evidently, shell_command_token can return nil.

This method doesn't support Windows targets. I have no idea whether that was intentional.

which sucks. command -v is probably better supported and more consistent than which.

Even if which didn't suck, this code doesn't work as intended:

root@kali:/# which asdf
root@kali:/# 

Even if this code worked as intended, it may run into issues with non-English locales.

Here's an arguably better implementation, taken from lib/msf/core/post/common.rb :

  #
  # Checks if the `cmd` is installed on the system
  # @return [Boolean]
  #
  def command_exists?(cmd)
    if session.platform == 'windows'
      # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/where_1
      # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/if
      cmd_exec("cmd /c where /q #{cmd} & if not errorlevel 1 echo true").to_s.include? 'true'
    else
      cmd_exec("command -v #{cmd} && echo true").to_s.include? 'true'
    end
  rescue
    raise "Unable to check if command `#{cmd}' exists"
  end

All 5 comments

Thanks. This looks like a legit bug. The binary_exists method is terrible.

Here's a rudimentary patch:

diff --git a/lib/msf/base/sessions/command_shell.rb b/lib/msf/base/sessions/command_shell.rb
index 72393cb53c..72c6bd1e7f 100644
--- a/lib/msf/base/sessions/command_shell.rb
+++ b/lib/msf/base/sessions/command_shell.rb
@@ -323,7 +323,7 @@ class CommandShell
   #
   def binary_exists(binary)
     print_status("Trying to find binary(#{binary}) on target machine")
-    binary_path = shell_command_token("which #{binary}").strip
+    binary_path = shell_command_token("which #{binary}").to_s.strip
     if binary_path.eql?("#{binary} not found")
       print_error(binary_path)
       return nil

But that doesn't fix the other fundamental issues in this code:

  #
  # Check if there is a binary in PATH env
  #
  def binary_exists(binary)
    print_status("Trying to find binary(#{binary}) on target machine")
    binary_path = shell_command_token("which #{binary}").strip
    if binary_path.eql?("#{binary} not found")
      print_error(binary_path)
      return nil
    else
      print_status("Found #{binary} at #{binary_path}")
      return binary_path
    end
  end

Evidently, shell_command_token can return nil.

This method doesn't support Windows targets. I have no idea whether that was intentional.

which sucks. command -v is probably better supported and more consistent than which.

Even if which didn't suck, this code doesn't work as intended:

root@kali:/# which asdf
root@kali:/# 

Even if this code worked as intended, it may run into issues with non-English locales.

Here's an arguably better implementation, taken from lib/msf/core/post/common.rb :

  #
  # Checks if the `cmd` is installed on the system
  # @return [Boolean]
  #
  def command_exists?(cmd)
    if session.platform == 'windows'
      # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/where_1
      # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/if
      cmd_exec("cmd /c where /q #{cmd} & if not errorlevel 1 echo true").to_s.include? 'true'
    else
      cmd_exec("command -v #{cmd} && echo true").to_s.include? 'true'
    end
  rescue
    raise "Unable to check if command `#{cmd}' exists"
  end

May not be a good idea to post public IPs of hosts possible vulnerable to exploits on the Internet either.

[*] Command shell session 7 opened (134.209.242.221:39715 -> 180.250.166.130:22) at 2019-09-20 10:46:18 +0000

It looks like the same assumption occurs in several places within lib/msf/base/sessions/command_shell.rb :

# grep shell_command_token lib/msf/base/sessions/command_shell.rb | fgrep -v "def shell_command_token" | fgrep -v to_s
    binary_path = shell_command_token("which #{binary}").strip
        result = shell_command_token("cat /dev/null > #{dst}")
        result = shell_command_token("echo -ne '#{chunk_repr}' >> #{dst}")
          shell_command_token("rm -rf #{dst}")
        shell_command_token(@cleanup_command) rescue nil
    shell_command_token_win32(cmd,timeout)
    shell_command_token_unix(cmd,timeout)

This resulted in at least one other issue #11725 and associated patch #12131.

I've fixed the original issue in #12404 .

There are a tonne of other bugs in the command_shell lib. I consider these to be someone else's problem.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wvu-r7 picture wvu-r7  路  3Comments

Sonya2010 picture Sonya2010  路  3Comments

ejholmes picture ejholmes  路  3Comments

notdodo picture notdodo  路  3Comments

adrianmihalko picture adrianmihalko  路  3Comments