Image Photo Gallery Final Tiles Grid <= 3.6.7 - Missing Authorization to Authenticated (Contributor+) Gallery Management
Description
The Image Photo Gallery Final Tiles Grid plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 3.6.7. This is due to the plugin not properly verifying that a user is authorized to perform actions on gallery management functions. This makes it possible for authenticated attackers, with Contributor-level access and above, to delete, modify, or clone galleries created by any user, including administrators.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:LTechnical Details
<=3.6.7Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14455 (Image Photo Gallery Final Tiles Grid) ## 1. Vulnerability Summary The **Image Photo Gallery Final Tiles Grid** plugin (<= 3.6.7) contains a missing authorization vulnerability in its gallery management functions. While these functions are restricted to …
Show full research plan
Exploitation Research Plan: CVE-2025-14455 (Image Photo Gallery Final Tiles Grid)
1. Vulnerability Summary
The Image Photo Gallery Final Tiles Grid plugin (<= 3.6.7) contains a missing authorization vulnerability in its gallery management functions. While these functions are restricted to authenticated users via WordPress AJAX handlers, they fail to verify the user's specific capabilities (e.g., manage_options) or ownership of the gallery. This allows any authenticated user with Contributor-level permissions or higher to manipulate (delete, modify, or clone) any gallery on the system, including those created by administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Authentication: Contributor-level session required.
- Vulnerable Actions (Inferred):
ftg_delete_galleryftg_save_galleryftg_duplicate_gallery(orftg_clone_gallery)
- Parameters:
action: The specific gallery management action.idorgallery_id: The ID of the target gallery to manipulate.ftg_nonce(or similar): The AJAX nonce required for the request.
- Preconditions: A gallery must exist (created by an admin) and its ID must be known (IDs are sequential integers).
3. Code Flow (Inferred)
- The plugin registers AJAX handlers in an admin-focused class (likely
FinalTilesGridAdminorFTGclass). add_action( 'wp_ajax_ftg_delete_gallery', array( $this, 'delete_gallery' ) );is registered.- The
delete_galleryfunction (and others) likely callscheck_ajax_referer( 'ftg_admin_nonce', 'nonce' )(or similar). - The Flaw: The function proceeds to perform database operations (e.g.,
$wpdb->delete(...)) based on a providedidparameter without checkingif ( current_user_can( 'manage_options' ) ). - Since Contributors can access
wp-admin, they can load the scripts that contain the nonce and then fire these AJAX actions.
4. Nonce Acquisition Strategy
The plugin localizes admin data for its JavaScript gallery manager.
- Identify Shortcode/Admin Page: The plugin's admin interface is usually under
wp-admin/admin.php?page=final-tiles-grid-gallery-lite. - Action: Log in as the Contributor.
- Navigate: Go to the plugin's dashboard (if the menu is visible) or create a post and see if the plugin's scripts load.
- Browser Eval: Use
browser_evalto extract the nonce from the global JavaScript object.- Variable Name (Inferred):
FinalTilesGridAdminorftg_vars. - Key (Inferred):
nonceorftg_admin_nonce. - Command:
browser_eval("window.FinalTilesGridAdmin?.nonce || window.ftg_vars?.nonce")
- Variable Name (Inferred):
5. Exploitation Strategy
We will attempt to delete a gallery created by the administrator using a Contributor account.
Step 1: Discover Gallery ID
Galleries are stored in a custom table (likely wp_final_tiles_grid_galleries). IDs are usually visible in the admin UI or can be guessed (starting from 1).
Step 2: Perform the Deletion
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=ftg_delete_gallery&id=[TARGET_ID]&nonce=[EXTRACTED_NONCE]
- Action:
ftg_delete_gallery(inferred action name). - id: The ID of the administrator's gallery.
- nonce: The nonce obtained in Section 4.
6. Test Data Setup
- Users:
- Create an Administrator (
admin_user). - Create a Contributor (
attacker_user).
- Create an Administrator (
- Gallery:
- As
admin_user, create a new gallery titled "Admin Secret Gallery". - Note the ID of the created gallery (e.g.,
1).
- As
- Page:
- As
admin_user, create a page containing the gallery shortcode:[final_tiles_grid id='1'].
- As
7. Expected Results
- Response: The AJAX endpoint should return a success status (likely
{"success":true}or1). - Outcome: The gallery with the specified ID is removed from the database.
- Access Control Failure: The request succeeds despite being initiated by a Contributor who should not have gallery management permissions.
8. Verification Steps
After sending the exploit request, verify the gallery is gone via WP-CLI:
# Check if the gallery exists in the custom table
wp db query "SELECT * FROM wp_final_tiles_grid_galleries WHERE id = [TARGET_ID];"
# Alternatively, check if the gallery list is empty or missing the ID
# (Plugin specific CLI command if available, otherwise raw SQL)
9. Alternative Approaches
If ftg_delete_gallery is not the correct action name or requires different parameters:
- Clone Action: Try
action=ftg_duplicate_gallery&id=[TARGET_ID]. This is less destructive but still proves the authorization bypass. - Modify Action: Try
action=ftg_save_gallery&id=[TARGET_ID]&title=Hacked. - Parameter Discovery: If
idfails, trygallery_id. Ifnoncefails, look for_wpnonceorftg_nonce. - Admin Page Scraping: If
browser_evalfails, usehttp_requestto GET the admin pagewp-admin/admin.php?page=final-tiles-grid-gallery-liteand regex the source for the nonce.
Summary
The Image Photo Gallery Final Tiles Grid plugin for WordPress fails to implement capability checks on its AJAX gallery management functions. This allows authenticated users with Contributor-level access and above to delete, modify, or clone any gallery on the site, regardless of ownership, by providing a valid nonce and the target gallery ID.
Vulnerable Code
// In FinalTilesGridAdmin class or similar registration // Actions registered for all authenticated users in admin context add_action( 'wp_ajax_ftg_delete_gallery', array( $this, 'delete_gallery' ) ); add_action( 'wp_ajax_ftg_save_gallery', array( $this, 'save_gallery' ) ); --- // Example vulnerable handler public function delete_gallery() { // Nonce check ensures request integrity but not authorization check_ajax_referer( 'ftg_admin_nonce', 'nonce' ); $id = intval( $_POST['id'] ); // Vulnerability: No check for current_user_can('manage_options') or similar capability global $wpdb; $wpdb->delete($wpdb->prefix . 'final_tiles_grid_galleries', array('id' => $id)); wp_send_json_success(); }
Security Fix
@@ -120,6 +120,10 @@ public function delete_gallery() { check_ajax_referer( 'ftg_admin_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); + } + $id = intval( $_POST['id'] ); global $wpdb; $wpdb->delete($wpdb->prefix . 'final_tiles_grid_galleries', array('id' => $id));
Exploit Outline
1. Authentication: Log in to the WordPress site as a Contributor (or any role with wp-admin access). 2. Nonce Retrieval: Navigate to any admin page where the plugin scripts are loaded or inspect the page source to find the localized JavaScript object containing the AJAX nonce (e.g., `window.ftg_vars.nonce` or `window.FinalTilesGridAdmin.nonce`). 3. Target Identification: Identify the ID of the gallery to be manipulated. Since IDs are typically sequential integers, they can be easily enumerated or found in the admin UI. 4. Payload Delivery: Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=ftg_delete_gallery` (or `ftg_save_gallery`), `id=[Target Gallery ID]`, and `nonce=[Retrieved Nonce]`. 5. Verification: Confirm the action was successful by checking the gallery list or database; the plugin will process the management action despite the user lacking administrative permissions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.