Class: Yawast::Scanner::Plugins::DNS::CAA

Inherits:
Object
  • Object
show all
Includes:
Dnsruby
Defined in:
lib/scanner/plugins/dns/caa.rb

Class Method Summary collapse

Class Method Details

.caa_info(uri) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/scanner/plugins/dns/caa.rb', line 12

def self.caa_info(uri)
  # force DNS resolver to something that works
  # this is done to ensure that ISP resolvers don't get in the way
  # at some point, should probably do something else, but works for now
  @res = Resolver.new({nameserver: ['8.8.8.8']})

  # setup a list of domains already checked, so we can skip them
  @checked = []

  # setup a counter, so we can see if we actually got anything
  @records = 0

  domain = uri.host.to_s

  chase_domain domain

  if @records.zero?
    Yawast::Shared::Output.log_hash 'vulnerabilities',
                                    'missing_caa_records',
                                    {vulnerable: true, record_count: 0}

    puts
    Yawast::Utilities.puts_vuln 'DNS CAA: No records found.'
  else
    Yawast::Shared::Output.log_hash 'vulnerabilities',
                                    'missing_caa_records',
                                    {vulnerable: false, record_count: @records}
  end
end

.chase_domain(domain) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/scanner/plugins/dns/caa.rb', line 42

def self.chase_domain(domain)
  while domain != ''
    begin
      # check to see if we've already ran into this one
      return if @checked.include? domain
      @checked.push domain

      # first, see if this is a CNAME. we do this explicitly because
      # some resolvers flatten in an odd way that prevents just checking
      # for the CAA record directly
      cname = get_cname_record(domain)
      if !cname.nil?
        Yawast::Utilities.puts_info "\t\tCAA (#{domain}): CNAME Found: -> #{cname}"
        Yawast::Shared::Output.log_value 'dns', 'caa', domain, "CNAME: #{cname}"

        chase_domain cname.to_s
      else
        print_caa_record domain
      end
    rescue => e # rubocop:disable Style/RescueStandardError
      Yawast::Utilities.puts_error "\t\tCAA (#{domain}): #{e.message}"
    end

    # strip the leading element off the domain
    domain = domain.partition('.').last
  end
end

.get_cname_record(domain) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'lib/scanner/plugins/dns/caa.rb', line 70

def self.get_cname_record(domain)
  ans = @res.query(domain, 'CNAME')

  if !ans.answer[0].nil?
    return ans.answer[0].rdata
  else
    return nil
  end
end


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/scanner/plugins/dns/caa.rb', line 80

def self.print_caa_record(domain)
  ans = @res.query(domain, 'CAA')

  if ans.answer.count.positive?
    ans.answer.each do |rec|
      # check for RDATA
      if !rec.rdata.nil?
        Yawast::Utilities.puts_info "\t\tCAA (#{domain}): #{rec.rdata}"

        Yawast::Shared::Output.log_append_value 'dns', 'caa', domain, rec.rdata
        @records += 1
      else
        Yawast::Utilities.puts_error "\t\tCAA (#{domain}): Invalid Response: #{ans.answer}"
      end
    end
  else
    # no answer, so no records
    Yawast::Utilities.puts_info "\t\tCAA (#{domain}): No Records Found"

    Yawast::Shared::Output.log_value 'dns', 'caa', domain, 'nil'
  end
end