Keep Backup Daily <= 2.1.1 - Authenticated (Admin+) Limited Path Traversal via 'kbd_path' Parameter
Description
The Keep Backup Daily plugin for WordPress is vulnerable to Limited Path Traversal in all versions up to, and including, 2.1.1 via the `kbd_open_upload_dir` AJAX action. This is due to insufficient validation of the `kbd_path` parameter, which is only sanitized with `sanitize_text_field()` - a function that does not strip path traversal sequences. This makes it possible for authenticated attackers, with Administrator-level access and above, to list the contents of arbitrary directories on the server outside of the intended uploads directory.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=2.1.1What Changed in the Fix
Changes introduced in v2.1.3
Source Code
WordPress.org SVN## Vulnerability Summary The **Keep Backup Daily** plugin for WordPress is vulnerable to **Limited Path Traversal** in versions up to and including 2.1.1. The flaw exists in the AJAX handler for the `kbd_open_upload_dir` action. The plugin accepts a user-provided directory path via the `kbd_path` p…
Show full research plan
Vulnerability Summary
The Keep Backup Daily plugin for WordPress is vulnerable to Limited Path Traversal in versions up to and including 2.1.1. The flaw exists in the AJAX handler for the kbd_open_upload_dir action. The plugin accepts a user-provided directory path via the kbd_path parameter and fails to properly validate or restrict it to the intended uploads directory.
The parameter is processed using sanitize_text_field(), which removes tags and extra whitespace but does not strip path traversal sequences like ../. As a result, an authenticated administrator can supply a path such as ../../../../ to list the contents of arbitrary directories on the server that the web server user has permissions to read.
Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
kbd_open_upload_dir(registered viawp_ajax_kbd_open_upload_dir) - Vulnerable Parameter:
kbd_path - Authentication: Required (Administrator level or higher).
- Preconditions: The attacker must be logged in as an administrator to reach the
wp_ajax_hook. - Vector:
POST /wp-admin/admin-ajax.phpwithaction=kbd_open_upload_dir&kbd_path=...
Code Flow
Although the specific function body for kbd_open_upload_dir is in the truncated portion of the provided source, we can reconstruct the flow based on the vulnerability description and surrounding code patterns:
- Hook Registration: The plugin registers the AJAX action:
add_action('wp_ajax_kbd_open_upload_dir', 'kbd_open_upload_dir');(inferred) - Input Handling: The function
kbd_open_upload_dirretrieves input:$path = sanitize_text_field($_POST['kbd_path']); - Vulnerable Sink: The
$pathis passed into a directory listing function, likelyscandir()or a wrapper like the plugin's ownkdb_list_zipfiles($mydirectory)(found ininc/kbd_cron.php). - Lack of Validation: The code fails to check if the resulting absolute path resides within
wp_upload_dir(). - Output: The contents of the directory are returned to the user, likely as a JSON object or an HTML list.
Nonce Acquisition Strategy
The kbd_open_upload_dir action likely requires a security nonce. Based on WordPress standards and the plugin's structure, the nonce is likely localized using wp_localize_script.
Strategy:
- Identify the Page: The "Export" and "Settings" pages are the most likely to load the script responsible for this AJAX action.
- Create Setup Page: If necessary, create a post/page to trigger script loading, though since this is an Admin+ vulnerability, navigating to the plugin settings is sufficient.
- Navigation: Use
browser_navigateto go to the plugin settings:http://localhost:8080/wp-admin/options-general.php?page=kbd_settings. - Extract Nonce: Use
browser_evalto find the localized object. Common identifiers for this plugin would bekbd_ajax,kbd_vars, orkbd_data.- Search Pattern: Look for
wp_localize_scriptcalls in the full source (not provided, but usually inregister_kbd_styles). - Eval Command:
browser_eval("window.kbd_ajax?.nonce")orbrowser_eval("window.kbd_data?.nonce").
- Search Pattern: Look for
- Fallback: If no localized nonce is found, check the HTML source for hidden inputs:
jQuery('input[name="kbd_nonce"]').val().
Exploitation Strategy
Step 1: Authentication
Authenticate as a WordPress Administrator and capture cookies.
Step 2: Nonce Extraction
Navigate to the plugin settings page to extract the nonce.
- URL:
/wp-admin/options-general.php?page=kbd_settings - Method:
browser_navigatefollowed bybrowser_eval.
Step 3: Traversal Request
Send a crafted AJAX request to list the root directory.
- Request Tool:
http_request - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: The nonce parameter nameaction=kbd_open_upload_dir&kbd_path=../../../../&security=[NONCE]securityis a common default; replace with the actual key found in Step 2).
Step 4: Verification
The response should contain a listing of the server's root directory (e.g., bin, etc, home, var).
Test Data Setup
- User: Create an administrator user.
wp user create attacker admin@example.com --role=administrator --user_pass=password
- Plugin Activation: Ensure "Keep Backup Daily" is active.
wp plugin activate keep-backup-daily
- Settings Initialization: Visit the settings page once to ensure any default options/paths are generated.
browser_navigate("http://localhost:8080/wp-admin/options-general.php?page=kbd_settings")
Expected Results
A successful exploit will return a directory listing of the path specified in kbd_path.
Example Vulnerable Response (JSON):
{
"success": true,
"data": [
".",
"..",
"etc",
"home",
"root",
"var",
"wp-config.php"
]
}
If the plugin returns HTML, look for <li> or <a> tags containing file names from the traversal target.
Verification Steps
- Examine Response: Verify that the
http_requestresponse body contains directory entries that are clearly from the filesystem root (e.g.,/etc,/var) or the WordPress root (if traversed only that far). - Filesystem Match: Compare the output with the actual filesystem contents using WP-CLI:
wp eval "print_r(scandir('/'));"
- Confirm Path: If the response shows the contents of
/etc, the traversal is confirmed.
Alternative Approaches
- Blind Traversal: If the output is not directly returned, attempt to trigger an error by providing an invalid path or a path that exists but is inaccessible, and check for differences in response time or status codes.
- Different Traversal Sinks: Check if
kbd_pathis used in other actions, such as a file deletion or download action (e.g.,kbd_force_downloadininc/functions.php). Ifkbd_force_downloaduses a path parameter without validation, it could lead to Arbitrary File Download (AFD). - Check
kbd_download: The functionkbd_download()ininc/functions.phpcallskbd_force_download(). Investigate ifkbd_force_downloadaccepts a file path via$_GET['file'](referenced in truncatedinc/kbd_cron.php) that might also be vulnerable to traversal.
Summary
The Keep Backup Daily plugin is vulnerable to limited path traversal through the 'kbd_path' parameter in its AJAX handlers. Authenticated administrators can bypass directory restrictions to list the contents of arbitrary directories on the server because the input is only processed with basic text sanitization that fails to block traversal sequences like '../'.
Vulnerable Code
// From inc/functions.php (approx. line 834 in version 2.1.2) $kbd_path = sanitize_kbd_data($_POST['kbd_path']); $kbd_path= str_replace('\\', '/', $kbd_path); $kbd_path= str_replace('\\', '/', $kbd_path); kbd_get_dir_list_html($kbd_path, 'sub');
Security Fix
@@ -578,6 +578,9 @@ add_action( 'wp_ajax_update_kbd_bkup_alias', 'update_kbd_bkup_alias' ); function update_kbd_bkup_alias() { + if ( ! current_user_can('manage_options') ) { + wp_send_json_error('Insufficient permissions.'); + } global $wpdb, $kbd_backup_aliases, $kbd_db_prefix; // this is how you get access to the database if(isset($_POST['key']) && $_POST['key']!='' && isset($_POST['val']) && $_POST['val']!=''){ @@ -834,6 +837,13 @@ $kbd_path = sanitize_kbd_data($_POST['kbd_path']); $kbd_path= str_replace('\\', '/', $kbd_path); $kbd_path= str_replace('\\', '/', $kbd_path); + + $allowed_directory = realpath(WP_CONTENT_DIR . '/uploads'); + $real_path = realpath($kbd_path); + + if ($real_path === false || strpos($real_path, $allowed_directory) !== 0) { + wp_send_json_error('Invalid directory path.'); + } kbd_get_dir_list_html($kbd_path, 'sub');
Exploit Outline
The exploit requires an authenticated WordPress user with Administrator privileges. 1. Login to the WordPress admin panel. 2. Access the plugin settings page (usually under Settings > Keep Backup Daily) to extract a valid security nonce and verify the plugin's AJAX structure. 3. Send a POST request to /wp-admin/admin-ajax.php using the action 'kbd_open_upload_dir'. 4. In the request body, provide the 'kbd_path' parameter containing a directory traversal payload, such as '../../../../'. 5. The server response will contain a directory listing of the target path (e.g., the server root or WordPress root directory), allowing the attacker to discover sensitive file names and system structure.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.