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/auxiliary/gather/censys_search.rb
Views: 11623
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report78CENSYS_SEARCH_API = 'search.censys.io'.freeze910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Censys Search',15'Description' => %q{16The module uses the Censys REST API to access the same data accessible17through the web interface. The search endpoint allows queries using18the Censys Search Language against the Hosts dataset. Setting the19CERTIFICATES option will also retrieve the certificate details for each20relevant service by querying the Certificates dataset.21},22'Author' => [23'Nixawk', # original Metasploit module24'e2002e', # rework to use the API v225'Christophe De La Fuente' # rework to use the API v226],27'References' => [28['URL', 'https://search.censys.io']29],30'License' => MSF_LICENSE,31'Notes' => {32'Stability' => [CRASH_SAFE],33'SideEffects' => [],34'Reliability' => []35}36)37)3839register_options([40OptString.new('CENSYS_UID', [true, 'The Censys API UID']),41OptString.new('CENSYS_SECRET', [true, 'The Censys API SECRET']),42OptString.new('QUERY', [true, 'The Censys search query']),43OptBool.new('CERTIFICATES', [false, 'Query infos about certificates', false])44])45end4647def basic_auth_header48auth_str = datastore['CENSYS_UID'].to_s + ':' + datastore['CENSYS_SECRET'].to_s49'Basic ' + Rex::Text.encode_base64(auth_str)50end5152def search(keyword)53begin54@cli = Rex::Proto::Http::Client.new(CENSYS_SEARCH_API, 443, {}, true)55@cli.connect5657response = @cli.request_cgi(58'method' => 'GET',59'uri' => "/api/v2/hosts/search?q=#{keyword}",60'headers' => { 'Authorization' => basic_auth_header }61)62res = @cli.send_recv(response)63rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e64fail_with(Failure::Unreachable, "#search: HTTP Connection Failed: #{e}")65end66fail_with(Failure::Unreachable, '#search: HTTP Connection Failed') unless res6768records = ActiveSupport::JSON.decode(res.body)69if records['code'] == 20070parse_record(records['result'])71else72fail_with(Failure::UnexpectedReply, "Error returned by '/api/v2/hosts/search': code=#{records['code']}, status=#{records['status']}, error=#{records['error']}")73end74end7576def get_certificate_details(cert_fingerprint)77return if cert_fingerprint.nil?7879begin80response = @cli.request_cgi(81'method' => 'GET',82'uri' => "/api/v1/view/certificates/#{cert_fingerprint}",83'headers' => { 'Authorization' => basic_auth_header }84)85res = @cli.send_recv(response)86rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT87print_error('#get_certificate_details - HTTP Connection Failed')88return89end90return unless res9192cert_details = ActiveSupport::JSON.decode(res.body)93subject = cert_details.dig('parsed', 'subject_dn')94return unless subject9596issuer = cert_details.dig('parsed', 'issuer_dn')97cert_details = subject98cert_details << " (Issuer: #{issuer})" if issuer99cert_details100end101102def parse_record(records)103unless records&.dig('hits')&.any?104print_error('The query did not return any records')105return106end107records['hits'].each do |hit|108ip = hit['ip']109services = hit['services']110ports = []111certs = []112services.each do |service|113port = service['port']114name = service['service_name']115ports << "#{port}/#{name}"116cert_details = nil117if datastore['CERTIFICATES'] && service['certificate']118cert_details = get_certificate_details(service['certificate'])119if cert_details120certs << "Certificate for #{port}/#{name}: #{cert_details}"121else122vprint_error("Unable to get certificate details for #{port}/#{name}")123end124end125if cert_details126report_service(host: ip, port: port, name: name, info: cert_details)127else128report_service(host: ip, port: port, name: name)129end130end131print_good("#{ip} - #{ports.join(',')}")132certs.each { |cert| print_status(cert) }133end134end135136# Check to see if Censys Search API host resolves properly137def censys_resolvable?138begin139Rex::Socket.resolv_to_dotted(CENSYS_SEARCH_API)140rescue RuntimeError, SocketError141return false142end143true144end145146def run147unless censys_resolvable?148fail_with(Failure::Unreachable, "Unable to resolve #{CENSYS_SEARCH_API}")149end150151search(datastore['QUERY'])152end153end154155156