@@ -3,6 +3,7 @@ class MetasploitModule < Msf::Auxiliary
3
3
include Msf ::Auxiliary ::Report
4
4
include Msf ::Exploit ::Remote ::LDAP
5
5
include Msf ::OptionalSession ::LDAP
6
+ include Rex ::Proto ::MsDnsp
6
7
include Rex ::Proto ::Secauthz
7
8
8
9
ADS_GROUP_TYPE_BUILTIN_LOCAL_GROUP = 0x00000001
@@ -417,31 +418,37 @@ def find_enrollable_vuln_certificate_templates
417
418
allowed_sids = parse_acl ( security_descriptor . dacl ) if security_descriptor . dacl
418
419
next if allowed_sids . empty?
419
420
420
- service = report_service ( {
421
- host : ca_server [ :dnshostname ] [ 0 ] ,
422
- port : 445 ,
423
- proto : 'tcp' ,
424
- name : 'AD CS' ,
425
- info : "AD CS CA name: #{ ca_server [ :name ] [ 0 ] } "
426
- } )
427
-
428
- report_note ( {
429
- data : ca_server [ :dn ] [ 0 ] . to_s ,
430
- service : service ,
431
- host : ca_server [ :dnshostname ] [ 0 ] ,
432
- ntype : 'windows.ad.cs.ca.dn'
433
- } )
434
-
435
- report_host ( {
436
- host : ca_server [ :dnshostname ] [ 0 ] ,
437
- name : ca_server [ :dnshostname ] [ 0 ]
438
- } )
439
-
440
- ca_server_key = ca_server [ :dnshostname ] [ 0 ] . to_sym
421
+ ca_server_fqdn = ca_server [ :dnshostname ] [ 0 ] . to_s . downcase
422
+ ca_server_ip_address = get_ip_addresses_by_fqdn ( ca_server_fqdn ) &.first
423
+
424
+ if ca_server_ip_address
425
+ service = report_service ( {
426
+ host : ca_server_ip_address ,
427
+ port : 445 ,
428
+ proto : 'tcp' ,
429
+ name : 'AD CS' ,
430
+ info : "AD CS CA name: #{ ca_server [ :name ] [ 0 ] } "
431
+ } )
432
+
433
+ report_note ( {
434
+ data : ca_server [ :dn ] [ 0 ] . to_s ,
435
+ service : service ,
436
+ host : ca_server_ip_address ,
437
+ ntype : 'windows.ad.cs.ca.dn'
438
+ } )
439
+
440
+ report_host ( {
441
+ host : ca_server_ip_address ,
442
+ name : ca_server_fqdn
443
+ } )
444
+ end
445
+
446
+ ca_server_key = ca_server_fqdn . to_sym
441
447
next if @certificate_details [ certificate_template ] [ :ca_servers ] . key? ( ca_server_key )
442
448
443
449
@certificate_details [ certificate_template ] [ :ca_servers ] [ ca_server_key ] = {
444
- hostname : ca_server [ :dnshostname ] [ 0 ] . to_s ,
450
+ fqdn : ca_server_fqdn ,
451
+ ip_address : ca_server_ip_address ,
445
452
enrollment_sids : allowed_sids ,
446
453
name : ca_server [ :name ] [ 0 ] . to_s ,
447
454
dn : ca_server [ :dn ] [ 0 ] . to_s
@@ -488,17 +495,17 @@ def print_vulnerable_cert_info
488
495
info = hash [ :notes ] . select { |note | note . start_with? ( prefix ) } . map { |note | note . delete_prefix ( prefix ) . strip } . join ( "\n " )
489
496
info = nil if info . blank?
490
497
491
- hash [ :ca_servers ] . each do |dnshostname , ca_server |
498
+ hash [ :ca_servers ] . each do |ca_fqdn , ca_server |
492
499
service = report_service ( {
493
- host : dnshostname . to_s ,
500
+ host : ca_server [ :ip_address ] ,
494
501
port : 445 ,
495
502
proto : 'tcp' ,
496
503
name : 'AD CS' ,
497
504
info : "AD CS CA name: #{ ca_server [ :name ] } "
498
505
} )
499
506
500
507
vuln = report_vuln (
501
- host : dnshostname . to_s ,
508
+ host : ca_server [ :ip_address ] ,
502
509
port : 445 ,
503
510
proto : 'tcp' ,
504
511
sname : 'AD CS' ,
@@ -511,7 +518,7 @@ def print_vulnerable_cert_info
511
518
report_note ( {
512
519
data : hash [ :dn ] ,
513
520
service : service ,
514
- host : dnshostname . to_s ,
521
+ host : ca_fqdn . to_s ,
515
522
ntype : 'windows.ad.cs.ca.template.dn' ,
516
523
vuln_id : vuln . id
517
524
} )
@@ -539,8 +546,8 @@ def print_vulnerable_cert_info
539
546
end
540
547
541
548
if hash [ :ca_servers ] . any?
542
- hash [ :ca_servers ] . each do |ca_hostname , ca_hash |
543
- print_good ( " Issuing CA: #{ ca_hash [ :name ] } (#{ ca_hostname } )" )
549
+ hash [ :ca_servers ] . each do |ca_fqdn , ca_hash |
550
+ print_good ( " Issuing CA: #{ ca_hash [ :name ] } (#{ ca_fqdn } )" )
544
551
print_status ( ' Enrollment SIDs:' )
545
552
convert_sids_to_human_readable_name ( ca_hash [ :enrollment_sids ] ) . each do |sid |
546
553
print_status ( " * #{ highlight_sid ( sid ) } " )
@@ -607,10 +614,48 @@ def get_object_by_sid(object_sid)
607
614
object
608
615
end
609
616
617
+ def get_ip_addresses_by_fqdn ( host_fqdn )
618
+ return @fqdns [ host_fqdn ] if @fqdns . key? ( host_fqdn )
619
+
620
+ vprint_status ( "Looking up DNS records for #{ host_fqdn } in LDAP." )
621
+ hostname , _ , domain = host_fqdn . partition ( '.' )
622
+ results = query_ldap_server (
623
+ "(&(objectClass=dnsNode)(DC=#{ ldap_escape_filter ( hostname ) } ))" ,
624
+ %w[ dnsRecord ] ,
625
+ base_prefix : "DC=#{ ldap_escape_filter ( domain ) } ,CN=MicrosoftDNS,DC=DomainDnsZones"
626
+ )
627
+ return nil if results . blank?
628
+
629
+ ip_addresses = [ ]
630
+ results . first [ :dnsrecord ] . each do |packed |
631
+ begin
632
+ unpacked = MsDnspDnsRecord . read ( packed )
633
+ rescue ::EOFError
634
+ next
635
+ rescue ::IOError
636
+ next
637
+ end
638
+
639
+ next unless [ DnsRecordType ::DNS_TYPE_A , DnsRecordType ::DNS_TYPE_AAAA ] . include? ( unpacked . record_type )
640
+
641
+ ip_addresses << unpacked . data . to_s
642
+ end
643
+
644
+ @fqdns [ host_fqdn ] = ip_addresses
645
+ if ip_addresses . empty?
646
+ print_warning ( "No A or AAAA DNS records were found for #{ host_fqdn } in LDAP." )
647
+ else
648
+ vprint_status ( "Found #{ ip_addresses . length } IP address#{ ip_addresses . length > 1 ? 'es' : '' } via A and AAAA DNS records." )
649
+ end
650
+
651
+ ip_addresses
652
+ end
653
+
610
654
def run
611
655
# Define our instance variables real quick.
612
656
@base_dn = nil
613
657
@ldap_objects = [ ]
658
+ @fqdns = { }
614
659
@certificate_details = { } # Initialize to empty hash since we want to only keep one copy of each certificate template along with its details.
615
660
616
661
ldap_connect do |ldap |
0 commit comments