章节大纲

  • 本实验的目的是让学生掌握远程 DNS 缓存中毒攻击 (也被称为 Kaminsky DNS 攻击) 的经验,DNS (Domain Name System) 是互联网的电话本,它可以帮助用户通过主机名找到 IP 地址,或者反向查询。这种查询的过程是比较复杂的,DNS攻击便是针对于这一过程,以各种方式将用户误导至攻击者提供的 IP 地址 (该IP往往是恶意的)。本实验关注于一种叫做 DNS 缓存中毒攻击的攻击技术。在另一个 SEED 实验中,我们设计了一个在本地网络环境下的 DNS 缓存中毒攻击实验,即攻击者和受害的 DNS 服务器位于同一网络中。在这种情况下,攻击者可以使用数据包嗅探的技术。而在远程攻击中,没法用数据包嗅探,因此远程 DNS 攻击变得更有挑战和难度。本实验涵盖以下主题:
    • DNS 介绍与 DNS 工作原理
    • DNS 服务器搭建
    • DNS 缓存中毒攻击
    • 伪造 DNS 响应
    • 数据包伪造
  • DNS缓存中毒攻击的主要目标是本地 DNS 服务器。显然,攻击真实的 DNS 服务器是违法的,因此我们需要搭建自己的 DNS 服务器来进行攻击实验。实验环境需要四台独立的机器:一台用于模拟受害者,一台用作 DNS 服务器,两台用于攻击者。下图描述了实验环境的设置。
     
    DNS 缓存中毒攻击

    为了简单起见,我们将这些 VM 都放在同一 LAN (局域网)中,但学生不可以在攻击中利用这一点,他们应该将攻击者的机器视为远程机器,即攻击者无法在 LAN 上嗅探数据包。这与本地DNS攻击有所不同。
     
    测试 DNS 设置

    在用户容器中,我们将运行一系列命令来确保我们的实验设置正确。在实验报告中,请记录你的测试结果。

    获取 ns.attacker32.com 的 IP 地址。当我们运行以下 dig 命令时,本地 DNS 服务器将根据添加到其配置文件中的 forward 区域条目,将请求转发到攻击者的域名服务器。因此,回复应来自我们在攻击者域名服务器上设置的区域文件 attacker32.com.zone。如果得到的结果不是这样,那么你的设置可能存在问题。请在实验报告中描述观察结果。

    $ dig ns.attacker32.com

    获取 www.example.com 的 IP 地址。现在有两个域名服务器托管 example.com 域名,一个是该域的官方域名服务器,另一个是攻击者容器。我们将查询这两个域名服务器,看看得到什么响应。请运行以下两个命令(从用户机器上运行),并描述观察结果。

    // 将查询发送到我们的本地 DNS 服务器,本地服务器会将查询
    // 转发到 example.com 的官方名称服务器。
    $ dig www.example.com
    
    // 直接向 ns.attacker32.com 查询
    $ dig @ns.attacker32.com www.example.com

    显然,没有人会向 ns.attacker32.com 查询 www.example.com 的 IP 地址;他们总是会向 example.com 的官方域名服务器查询答案。DNS 缓存投毒攻击的目标是让受害者向 ns.attacker32.com 查询 www.example.com 的 IP 地址。换句话说,如果我们的攻击成功,只要运行第一个 dig 命令(没有 @ 选项的那个),我们就会从攻击者那里得到伪造的结果,而不是从官方的域名服务器获取的真实结果。
  • 该任务专注于发送 DNS 请求。为了完成攻击,攻击者需要触发目标 DNS 服务器发出 DNS 查询,这样攻击者才有机会去伪造 DNS 响应。由于攻击者需要尝试多次才能成功,因此最好使用程序来自动发送 DNS 查询。

    学生需要编写一个程序来向目标服务器发送 DNS 请求(即我们配置的本地 DNS 服务器)。具体任务是编写该程序并证明 (使用 Wireshark ) 他们的查询请求可以触发目标 DNS 服务器会发出相应的 DNS 查询。该任务对性能的要求不高,因此学生可以使用 C 语言或Python (使用Scapy) 编写此代码。以下提供了 Python 的代码示例 (学生需要将其中的 +++ 替换为实际的值)。
    Qdsec  = DNSQR(qname='www.example.com')
    dns    = DNS(id=0xAAAA, qr=0, qdcount=1, ancount=0, nscount=0,
                 arcount=0, qd=Qdsec)
    
    
    ip  = IP(dst='+++', src='+++')
    udp = UDP(dport=+++, sport=+++, chksum=0)
    request = ip/udp/dns
  • 在此任务中,我们需要伪造 Kaminsky 攻击中的 DNS 响应。由于我们的攻击目标是 example.com,我们需要伪造从该域的域名服务器返回的响应。学生首先需要找到 example.com 的合法域名服务器的 IP 地址 (值得注意的是这个域名有多个域名服务器)。

    学生可以使用 Scapy 来实现这个任务,以下的代码示例构建了一个 DNS 响应包,其中包含了问题部分,回答部分以及一个域名服务器部分。在这段代码中,我们使用 +++ 作为占位符,学生需要用 Kaminsky 攻击中所需要的值来替换。学生需要解释为什么选择这些值。
    name   = '+++'  
    domain = '+++'  
    ns     = '+++'
    
    Qdsec  = DNSQR(qname=name)
    Anssec = DNSRR(rrname=name,   type='A',  rdata='1.2.3.4', ttl=259200)
    NSsec  = DNSRR(rrname=domain, type='NS', rdata=ns, ttl=259200)
    dns    = DNS(id=0xAAAA, aa=1, rd=1, qr=1,
                 qdcount=1, ancount=1, nscount=1, arcount=0,
                 qd=Qdsec, an=Anssec, ns=NSsec)
    
    ip    = IP(dst='+++', src='+++')
    udp   = UDP(dport=+++, sport=+++, chksum=0)
    reply = ip/udp/dns
     
    由于这些响应本身并不能成功实施攻击,为了展示任务完成的效果,学生需要使用 Wireshark 来捕获伪造的 DNS 响应,并证明这些伪造的数据包是合法的。
  • 现在我们将所有东西合在一起进行 Kaminsky 攻击。在攻击中,我们需要发送许多欺骗的 DNS 响应,希望其中有一个可以猜中正确的 Transaction ID,并比合法的响应更早到达。因此,发包速度至关重要:发出的数据包越多,成功的概率也就越大。如果我们像之前的任务那样,使用 Scapy 发送伪造的 DNS 回复成功率会非常低。学生可以使用 C 语言进行实现,但在 C 语言中构造 DNS 数据包并非易事。因此我们采用一个使用 C 语言和 Scapy 相结合的混合方法。通过混合方法,我们首先使用 Scapy 生成 DNS 数据包模板,并把模板保存在文件中。接着我们将该数据包模板加载到 C 程序中,并对其中某些字段进行一些微小修改,然后发出这个数据包。我们在 Labsetup/Files/attack.c 中提供了 C 语言的代码框架。学生可以对其中标记的区域进行修改,详细的代码解释在之后的指南部分中。

    检查 DNS 缓存:为了检查攻击是否成功,我们需要查看 DNS 缓存。以下的命令先将 DNS 缓存存到文件中,然后在文件中搜寻  attacker 关键词 (在我们的攻击中,我们采用 attacker32.com 作为攻击者的域名,如果学生使用不同的攻击域名,那么需要搜索不同的关键词)。
    # rndc dumpdb -cache && grep attacker /var/cache/bind/dump.db
    
  • 如果攻击成功,在本地 DNS 服务器的缓存中,example.com 的 NS 记录应该会改为 ns.attacker32.com。当服务器收到对 example.com 域内的任何域名的查询请求时,它会向 ns.attacker32.com 发送查询请求,而不是向原本合法的域名服务器。
     
    为了验证攻击是否成功,在用户主机上运行以下两条 dig 命令。在两次响应中,www.example.com 的 IP 地址应该相同,并且应该是在攻击主机的区域文件中配置的内容。
    //向本地 DNS 服务器发出查询请求
    $ dig www.example.com
    
    //直接向 attacker32 域名服务器发出请求
    $ dig @ns.attacker32.com www.example.com
     
    请在实验报告中给出你的观察结果 (截图),并解释你认为攻击成功的原因。需要注意的是,当你第一次运行 dig 命令时,请使用 Wireshark 来捕获网络流量,并指出 dig 命令触发了哪些数据包。根据数据包追踪来证明你的攻击是成功的。请注意,在运行第一个 dig 命令后,DNS 结果可能会缓存在本地 DNS 服务器上。如果你在使用 Wireshark 之前运行了第一个 dig 命令,这可能会影响结果。你可以在本地 DNS 服务器上使用 "sudo rndc flush" 清除缓存,但这将需要你重新进行攻击。
  • 你需要提交一份带有截图的详细实验报告来描述你所做的工作和你观察到的现象。你还需要对一些有趣或令人惊讶的观察结果进行解释。请同时列出重要的代码段并附上解释。只是简单地附上代码不加以解释不会获得学分。实验报告的提交方式会由你的老师进行具体安排。