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) >
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
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.
Most helpful comment
Here's a rudimentary patch:
But that doesn't fix the other fundamental issues in this code:
Evidently,
shell_command_tokencan returnnil.This method doesn't support Windows targets. I have no idea whether that was intentional.
whichsucks.command -vis probably better supported and more consistent thanwhich.Even if
whichdidn't suck, this code doesn't work as intended: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: