PGMfuzz is a fuzzer written for identifying vulnerabilities in PGM option parsing implementations.
b74310aa941f94bcbfee075e203ba145d732c8d357727cc806d9623b94be7d22
// pgmfuzz v1.0 - a fuzzing tool for Pragmatic General Multicast options
// Varun Uppal and Andy Davis, IRM 2007
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#define SOCK_ADDR struct sockaddr_in
#define IN_ADDR struct in_addr
#define IP struct ip
#define IP_HDR struct iphdr
#define TH_OFFSET 5
#define DEFAULT_TTL 255
#define IPPROTO_PGM 0x71
/* Function prototypes */
void fill_ip_hdr (char *packet,u_int8_t protocol,IN_ADDR sa,IN_ADDR da,u_int16_t len);
int checksum (u_int16_t *buf,int nbytes);
void fill_pgm_pack(unsigned char *tmpbuffer, unsigned char *pgm_header,int pgm_hdr_size, unsigned char *pgm_data, int pgm_data_size,int seq_tracker);
void packet_sender(int sockd, unsigned char *packet, int ip_header_size, int pgm_header_size, int pgm_data_size);
void usage (char *progname);
unsigned char PGM_header[]=
"\x40\x47" //source port (16455)
"\x1d\x7e" //dst port (7550)
"\x04" //type ODATA
"\x01" //options present - set to 03 to include network options
"\x00\x00" //checksum
"\xc0\xa8\x00\x02\xb5\x7e" //Global Source Ident
"\x00\x08" // Transport Service Data Unit Length
"\x00\x00\x00\x00" //seq no
"\x00\x00\x00\x00" //trail edg seq no
//PGM options
//OPT_LENGTH option
"\x00" //option type OPT_LENGTH
"\x04" //length of option (4 bytes)
"\x00\x08" //total length of options (including OPT_LENGTH)
//The option we're using
"\x92" //option type (this changes)
"\x0c" //option length (12 bytes)
"\x00\x00" //option parameters (this changes)
"\x61\x61\x61\x61" //option data
"\x61\x61\x61\x61"; //option data
unsigned char PGM_data[]=
"\x61\x61\x61\x61\x61\x61\x61\x61";
IN_ADDR src_addr, dst_addr;
SOCK_ADDR sock_addr;
int sockd, on=1;
int dst_port;
int check;
int check1;
int q;
unsigned char *buffer;
char *buffer1;
int seq_tracker=0;
int seq_tracker2;
u_int8_t packet[sizeof(IP)+ sizeof(PGM_header)-1 + sizeof(PGM_data)-1]; //IP header + PGM header + PGM data
main(int argc,char *argv[])
{
int c, errflg;
unsigned long pgm_ip;
unsigned long src_ip;
unsigned int pgm_port=7550; //default value
unsigned char pgm_opt_start=0; //default value
unsigned char pgm_opt_end=127; //default value
unsigned char pgm_type_start=0; //default value
unsigned char pgm_type_end=255; //default value
unsigned int pgm_net_sig=0; //default value
unsigned int verbose=0;
extern char *optarg;
extern int optind, optopt;
int q=4;
int j,count;
int pops;
time_t mytime = time(0);
unsigned char *thepgmbuffer;
pgm_ip=inet_addr("224.0.1.78"); //default value
src_ip=inet_addr("10.0.0.2"); //default value
errflg=0;
while ((c = getopt(argc, argv, ":a:i:p:r:s:t:u:nvh")) != -1)
{
switch(c)
{
case 'a':
pgm_ip = inet_addr(optarg);
break;
case 'i':
src_ip = inet_addr(optarg);
break;
case 'p':
pgm_port = atoi(optarg);
break;
case 'r':
pgm_opt_start = atoi(optarg);
break;
case 's':
pgm_opt_end = atoi(optarg);
break;
case 't':
pgm_type_start = atoi(optarg);
break;
case 'u':
pgm_type_end = atoi(optarg);
break;
case 'n':
pgm_net_sig = 1;
break;
case 'v':
verbose = 1;
break;
case 'h':
usage(argv[0]);
case ':':
printf ("Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
printf("Unrecognized option: -%c\n", optopt);
errflg++;
}
}
if (errflg)
{
usage(argv[0]);
}
printf ("------------------------------------------------\n");
printf ("%s - a fuzzer for PGM options\n",argv[0]);
printf ("v1.0 by Varun Uppal and Andy Davis, IRM Plc 2007\n\n");
printf ("For help, type pgmfuzz -h\n");
printf ("------------------------------------------------\n\n");
if (verbose)
{
printf ("Parameter values:\n");
printf ("Source IP address = %s\n",inet_ntoa(src_ip));
printf ("Destination IP address = %s\n",inet_ntoa(pgm_ip));
printf ("PGM port = %d\n",pgm_port);
printf ("PGM option type start value = %d\n", pgm_opt_start);
printf ("PGM option type end value = %d\n", pgm_opt_end);
printf ("PGM packet type start value = %d\n", pgm_type_start);
printf ("PGM packet type end value = %d\n", pgm_type_end);
printf ("Network Significant option bit = %d\n\n", pgm_net_sig);
printf ("Starting to fuzz now...\n\n");
}
src_addr.s_addr=src_ip;
dst_addr.s_addr=pgm_ip;
PGM_header[2]=htons(pgm_port);
PGM_header[3]=pgm_port;
pgm_opt_start+=128;
pgm_opt_end+=128;
if (pgm_net_sig)
PGM_header[5]=3;
//Create a socket
if((sockd=socket(AF_INET,SOCK_RAW,IPPROTO_PGM))<0)
{
perror("Error - socket()\n");
exit(1);
}
//Set socket options
if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0)
{
perror("Error - setsockopt()\n");
close(sockd);
exit(1);
}
for (q=pgm_type_start; q<=pgm_type_end; q++) //loop through PGM packet types
{
PGM_header[4]=q;
for (j=pgm_opt_start;j<=pgm_opt_end;j++) //loop though PGM option types
{
PGM_header[28]=j;
mytime = time(0);
printf("%sPGM packet type:%d PGM option type:%d\n", ctime(&mytime),q,j & 0x7f);
for(pops=0;pops<=65535;pops++) //loop though remainder of option bits
{
PGM_header[30]=pops;
PGM_header[31]=htons(pops);
fill_ip_hdr(packet,IPPROTO_PGM,src_addr,dst_addr,sizeof(IP)+ sizeof(PGM_header)-1 + sizeof(PGM_data)-1);
thepgmbuffer = (unsigned char *)malloc(sizeof(PGM_header)-1 + sizeof(PGM_data)-1);
fill_pgm_pack(thepgmbuffer,(unsigned char *)PGM_header,sizeof(PGM_header)-1,(unsigned char *)PGM_data,sizeof(PGM_data)-1, seq_tracker);
seq_tracker=seq_tracker+1;
memcpy(packet+sizeof(IP), thepgmbuffer, sizeof(PGM_header)-1 + sizeof(PGM_data)-1);
packet_sender(sockd, packet, sizeof(IP), sizeof(PGM_header)-1, sizeof(PGM_data)-1);
free(thepgmbuffer);
}
}
}
close(sockd);
exit(0);
}
void fill_ip_hdr (char *packet,u_int8_t protocol,IN_ADDR sa,IN_ADDR da,u_int16_t len)
{
IP_HDR *iphdr;
iphdr=(IP_HDR*)packet;
memset((char *)iphdr,'\0',sizeof(IP_HDR));
iphdr->version=4;
iphdr->ihl=5;
iphdr->tot_len=len;
iphdr->id=htons(getpid());
iphdr->ttl=DEFAULT_TTL;
iphdr->protocol=protocol;
iphdr->saddr=sa.s_addr;
iphdr->daddr=da.s_addr;
iphdr->check=(u_int16_t)checksum((u_int16_t *)iphdr,sizeof(IP_HDR));
}
void fill_pgm_pack(unsigned char *tmpbuffer, unsigned char *pgm_header,int pgm_hdr_size, unsigned char *pgm_data, int pgm_data_size, int seq_tracker)
{
int check;
int tsdu_length;
memcpy(tmpbuffer, pgm_header, pgm_hdr_size);
memcpy(tmpbuffer+pgm_hdr_size, pgm_data, pgm_data_size);
if(seq_tracker<2)
{
tmpbuffer[14] = htons(pgm_data_size);
tmpbuffer[15] = pgm_data_size;
//calculate sequence number
tmpbuffer[19]=tmpbuffer[19]+seq_tracker;
//seq_tracker=seq_tracker+1;
}
if(seq_tracker>9)
{
tmpbuffer[14] = htons(pgm_data_size);
tmpbuffer[15] = pgm_data_size;
//calculate sequence number
tmpbuffer[19]=tmpbuffer[19]+(seq_tracker-8);
//seq_tracker=seq_tracker+1;
}
if(seq_tracker>=2 && seq_tracker<=9)
{
seq_tracker=seq_tracker-2;//reduce tsdu by 2 when data transmitted
//tsdu_length=pgm_data_size-2;
tmpbuffer[14] = htons(pgm_data_size);
tmpbuffer[15] = pgm_data_size;
//calculate sequence number
tmpbuffer[19]=tmpbuffer[19]+seq_tracker;
//seq_tracker=seq_tracker+1;
}
//Calculate checksum
check=(u_int16_t)checksum((u_int16_t *)tmpbuffer,pgm_hdr_size + pgm_data_size);
tmpbuffer[6] = check;
tmpbuffer[7] = htons(check);
}
int checksum (u_int16_t *buf,int nbytes)
{
u_int32_t sum;
u_int16_t oddbyte;
sum = 0;
while (nbytes > 1)
{
sum += *buf++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_int16_t *) &oddbyte) = *(u_int8_t *) buf;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (u_int16_t) ~sum;
}
void packet_sender(int sockd, unsigned char *packet, int ip_header_size, int pgm_header_size, int pgm_data_size)
{
struct sockaddr_in sock_addr;
int dst_port;
int i;
memset(&sock_addr,'\0',sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
//sock_addr.sin_port = htons(dst_port);
sock_addr.sin_addr = dst_addr;
if(sendto (sockd,packet,ip_header_size+ pgm_header_size+ pgm_data_size,0x0,(struct sockaddr *)&sock_addr,sizeof(sock_addr)) != ip_header_size+pgm_header_size+ pgm_data_size)
{
perror("Error - sendto()\n");
close(sockd);
exit(1);
}
}
void usage (char *progname)
{
printf ("------------------------------------------------\n");
printf ("%s - a fuzzer for PGM options\n",progname);
printf ("v1.0 by Varun Uppal and Andy Davis, IRM Plc 2007\n");
printf ("------------------------------------------------\n\n");
printf ("Usage:\n");
printf ("-i <Source IP address>\n");
printf ("-a <Destination multicast IP address>\n");
printf ("-p <PGM port>\n");
printf ("-r <PGM option type start value>\n");
printf ("-s <PGM option type end value>\n");
printf ("-t <PGM packet type start value>\n");
printf ("-u <PGM packet type end value>\n");
printf ("-n <set the Network Significant option bit>\n");
printf ("-v <maximum verbosity>\n");
printf ("-h this page\n\n");
printf ("Example: pgmfuzz -i 10.0.0.2 -a 224.0.1.78 -p 7550 -r 0 -s 127 -t 0 -u 4 -n\n\n");
exit(1);
}