[关闭]
@SmashStack 2017-05-03T18:10:05.000000Z 字数 5841 阅读 75

记录一次失败的虫洞攻击实验

Chore


学号 :5140369057
报告人:张倬

实验环境

系统信息: Ubuntu 16.04.02 LTS
ns 版本: ns-2.35
nam 版本: nam-1.15
gawk 版本: GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.1)

虫洞攻击原理

虫洞攻击是一种针对路由机制的攻击,它由两个或两个以上的攻击者联合形成一条隧道,通过隧道将一端监听到的数据包发送到另一端进行重放。这种攻击对路由协议危害最大。一般来说隧道的长度大于普通的单跳距离,即节点的信号覆盖半径,但在路由协议的表现上却体现为一跳距离。因而节点在选择路由时,肯定倾向于虫洞所形成的路径。这样一来,正常的依靠节点间距离信息的路由机制被扰乱,而攻击者就可以吸引大量路由通过,并便于进行进一步的监听,篡改和执行诸如黑洞攻击或者灰洞攻击等等

wormhole.png-12kB

以简单的路由协议 OLSR 在虫洞攻击下的行为为例, OLSR 的特点在于周期性使用 HELLO 数据包来通知邻节点自己的存在。如果攻击者通过私有通道将由节点 A 发出的 HELLO 数据包传递给节点 B 附近的串谋攻击者,同样攻击者通过私有通道将节点 B 发出的 HELLO 数据包传递给先前的攻击者,那么 A 和 B 将相信它们互为邻节点,根据路由协议,它们误认为相互之间可以直接进行数据传递,而事实上 A 的信号并不能到达节点 B。

虫洞攻击可以根据恶意节点在网络中的位置分为显式攻击隐式攻击

隐式攻击

虫洞节点转发时不改变数据包头,因此虫洞节点在网络中是隐身的,这也意味着虫洞攻击者甚至可以不了解网络中使用的路由协议,或不需要破解路由协议中的安全认证机制就能够达到攻击效果。如图中,W1 和 W2 仅仅是转发 S 发出的数据包到 D ,不在数据包头的路由中添加自己的身份,则隐式虫洞攻击下 S 到 D 的路径为: S -> D。即 D 直接收到 S 发出的原始数据。

wormhole_ys.png-15kB

显示攻击

这种虫洞节点不改变数据段的内容,但是它将自己的身份证明加载在包头,就像合法节点做的一样,因此,其它的节点知道虫洞节点的存在,但是他们不知道攻击节点具有虫洞连接,其行为是恶意的。显然,要进行显示虫洞攻击,攻击者必须理解目前网络中所使用的网络协议,并且能够实现在目标网络中接入。显式虫洞攻击下 S 到 D 的路径为: S → W1 → W2 → D

wormhole_xs.png-16.9kB

实验尝试

设置大功率无线节点作为虫洞节点

基本思路
通过加大两个虫洞节点的无线信号功率扩大虫洞节点间的传输距离,另一方面修改模拟程序中 MAC 层的源码实现虫洞节点的隐蔽性。

设置不同的无线信号功率

使用如下 tcl 语言,分两次设置无线信号功率,便可以实现虫洞节点与普通节点拥有不同的无线信号功率。

  1. Phy/WirelessPhy set RXThresh_ 1.92278e-06

于是我们有了如下的 test.tcl 脚本

  1. set val(stop) 10
  2. set val(chan) Channel/WirelessChannel
  3. set val(prop) Propagation/TwoRayGround
  4. set val(netif) Phy/WirelessPhy
  5. set val(mac) Mac/802_11
  6. set val(ifq) CMUPriQueue
  7. set val(ll) LL
  8. set val(ant) Antenna/OmniAntenna
  9. set val(ifqlen) 50
  10. set val(rp) DSR
  11. set val(nn) 8
  12. set val(x) 600
  13. set val(y) 300
  14. set ns [new Simulator]
  15. #打开 Trace 文件
  16. set namfd [open ns1.nam w]
  17. $ns namtrace-all-wireless $namfd $val(x) $val(y)
  18. set val(tr) out.tr
  19. set tracefd [open $val(tr) w]
  20. $ns trace-all $tracefd
  21. set topo [new Topography]
  22. $topo load_flatgrid $val(x) $val(y)
  23. set chan [new $val(chan)]
  24. set god [create-god $val(nn)]
  25. # node 0, 1 is wormhole node
  26. Phy/WirelessPhy set RXThresh_ 2.28289e-11
  27. $ns node-config -adhocRouting $val(rp) \
  28. -llType $val(ll) \
  29. -macType $val(mac)\
  30. -ifqType $val(ifq) \
  31. -ifqLen $val(ifqlen) \
  32. -antType $val(ant) \
  33. -propType $val(prop) \
  34. -phyType $val(netif)\
  35. -channel $chan \
  36. -topoInstance $topo \
  37. -agentTrace ON \
  38. -routerTrace ON \
  39. -macTrace ON \
  40. -movementTrace ON
  41. for {set i 0} {$i < 2} {incr i} {
  42. set node_($i) [$ns node]
  43. }
  44. # node 2, 3, 4, 5, 6, 7 is normal node
  45. Phy/WirelessPhy set RXThresh_ 6.88081e-09
  46. $ns node-config -adhocRouting $val(rp) \
  47. -llType $val(ll) \
  48. -macType $val(mac)\
  49. -ifqType $val(ifq) \
  50. -ifqLen $val(ifqlen) \
  51. -antType $val(ant) \
  52. -propType $val(prop) \
  53. -phyType $val(netif)\
  54. -channel $chan \
  55. -topoInstance $topo \
  56. -agentTrace ON \
  57. -routerTrace ON \
  58. -macTrace ON \
  59. -movementTrace ON
  60. for {set i 2} {$i < $val(nn)} {incr i} {
  61. set node_($i) [$ns node]
  62. }
  63. for {set i 2} {$i < $val(nn)} {incr i} {
  64. $node_($i) set X_ [expr 100*($i-2)]
  65. $node_($i) set Y_ 0
  66. $node_($i) set Z_ 0
  67. }
  68. $node_(0) set X_ 50
  69. $node_(0) set Y_ 50
  70. $node_(0) set Z_ 0
  71. $node_(1) set X_ 450
  72. $node_(1) set Y_ 50
  73. $node_(1) set Z_ 0
  74. set udp1 [new Agent/UDP]
  75. $ns attach-agent $node_(2) $udp1
  76. set null5 [new Agent/Null]
  77. $ns attach-agent $node_([expr $val(nn)-1]) $null5
  78. set cbr [new Application/Traffic/CBR]
  79. $cbr set packetSize_ 500
  80. $cbr set inteval_ 0.005
  81. $cbr attach-agent $udp1
  82. $ns connect $udp1 $null5
  83. $ns at 0.5 "$cbr start"
  84. $ns at 9.5 "$cbr stop"
  85. for {set i 0 } {$i<$val(nn)} {incr i} {
  86. $ns initial_node_pos $node_($i) 30
  87. }
  88. for {set i 0 } {$i<$val(nn)} {incr i} {
  89. $ns at $val(stop) "$node_($i) reset";
  90. }
  91. $ns at $val(stop) "stop"
  92. $ns at $val(stop) "puts \"NS EXITING...\"; $ns halt"
  93. proc stop {} {
  94. global ns tracefd namfd
  95. $ns flush-trace
  96. close $tracefd
  97. close $namfd
  98. exec nam ns1.nam &
  99. }
  100. $ns run

修改源码以支持隐蔽性

如果不对源码进行修改,将会出现第一个虫洞节点直接将报文传送给目标节点的问题,直接破坏了虫洞节点的隐蔽性。

第一步 源码出入

实验指导使用的 ns 版本与我们使用的 2.35 不同,源码有小小的出入。

实验指导对函数 sendUp 和函数 sendDown 的修改如下:

  1. int WirelessPhy::sendDown(Packet *p){
  2. ......
  3. if(node.address()==#wormhole){
  4. p-> iswormhole = true;
  5. }
  6. channel_->recv(p, this);
  7. }
  1. int WirelessPhy::sendUp(Packet *p){
  2. if(node.address()!=#wormhole){
  3. if p->iswormhole
  4. Packet::free(p);
  5. }
  6. else p->iswormhole = false;
  7. ......
  8. }

在阅读了 ns-2.35 的部分源码以后,发现在新的代码中,node 节点通过 node() 函数返回,而不是一个变量。

第二步 实验指导出错

阅读实验指导的代码,我们会发现两个很明显致命的问题:

直接 free packet
在代码中,sendUp 函数过后多次使用了 Packet *p,如果提前 free, 会导致内存泄露,甚至于段错误。

程序逻辑错误
阅读代码,我们会发现程序满足如下事实:

这样,就有一个很大的问题,一旦报文进入了虫洞节点,从此以后报文将只能在虫洞节点传播,无法发送给目标节点。

解决方案如下:

  1. int WirelessPhy::sendDown(Packet *p){
  2. ......
  3. if(node.address()==#wormhole){
  4. p->iswormhole = !p->iswormhole;
  5. }
  6. channel_->recv(p, this);
  7. }
  1. int WirelessPhy::sendUp(Packet *p){
  2. if(node.address()!=#wormhole){
  3. if p->iswormhole
  4. pkt_recvd = 0;
  5. goto DONE;
  6. }
  7. else p->iswormhole = false;
  8. ......
  9. }

多完美呀,而我万万没想到后面我还是通宵改代码,还失败了。

第三步 初始化 iswormhole 变量

经过上一步的修改,测试代码发现程序还是会出现第一个虫洞节点直接发包给目标节点。
通过 printf 来对源码进行 debug, 发现布尔变量 iswormhole 出现了等于 44 的情况。
努力阅读源码发现我们没有在 Packet 对象的构造函数中对 iswormhole 进行赋值,导致代码出现未初始化漏洞。

  1. Packet() : bits_(0), data_(0), ref_count_(0), next_(0), iswormhole(false) { }
第四步 拷贝复制函数

经过上一步的修改,测试代码发现程序还是会出现第一个虫洞节点直接发包给目标节点。
回头在看源码,发现 Packet 对象在 sendDown 以后会多次拷贝赋值自身,我们没有对拷贝构造函数进行修改,导致 iswormhole 对象出现错误。

  1. inline Packet* Packet::copy() const
  2. {
  3. ......
  4. p->txinfo_info(&txinfo_);
  5. p->iswormhole = iswormholel
  6. }
第五步 还没有发现的问题

经过上一步的修改,测试代码发现程序终于不出现第一个虫洞节点直接发包给目标节点的问题了!!
可是根本不走虫洞节点了
继续使用 printf 进行 debug,发现问题在于第二个虫洞节点收到了第一个虫洞节点的包以后,并不转发,因为在 sendDown 函数后面还有很多代码处理。

  1. 0x348d210: 6 -->
  2. 0x3445780: 6 --> 1
  3. 0x343aec0: 6 --> 5
  4. 0x34899d0: 6 --> 7
  5. 0x3420da0: 6 --> 4
  6. 0x3495550: 6 --> 3
  7. 0x3426d00: 6 --> 0
  8. 0x3448fc0: 6 --> 2
  9. 0x3448fc0: 7 -->
  10. 0x3426d00: 7 --> 1
  11. 0x3495550: 7 --> 6
  12. 0x3420da0: 7 --> 5
  13. 0x343aec0: 7 --> 4
  14. 0x3445780: 7 --> 3
  15. 0x348d210: 7 --> 0
  16. 0x346c330: 7 --> 2
  17. 0x346c330: 2 -->
  18. 0x348d210: 2 --> 0
  19. 0x3445780: 2 --> 3
  20. 0x343aec0: 2 --> 4
  21. 0x3420da0: 2 --> 5
  22. 0x3495550: 2 --> 6
  23. 0x346c840: 2 --> 1
  24. 0x3426d00: 2 --> 7
  25. 0x3426d00: 3 -->
  26. 0x346c840: 3 --> 0
  27. 0x3495550: 3 --> 2
  28. 0x3420da0: 3 --> 4
  29. 0x343aec0: 3 --> 5
  30. 0x3445780: 3 --> 6
  31. 0x346c330: 3 --> 1
  32. 0x348e4d0: 3 --> 7
  33. 0x348e4d0: 2 -->
  34. 0x346c330: 2 --> 0
  35. 0x3445780: 2 --> 3
  36. 0x343aec0: 2 --> 4

然后就是一整夜去追踪 sendUp 和 sendDown 函数

第六步 破罐破摔

既然设置标志位的方法屡屡出错,不如重新造轮子,放弃标志位的方式。
随后我使用了一种投机取巧的办法:在 sendUp 函数中设置第一个虫洞节点发出的包只能被第二个虫洞节点接受。

  1. if (p->txinfo_.node()->address == 0 && node()->address() != 1){
  2. pky_recvd = 0;
  3. goto DONE;
  4. }

还是失败了。

个人认为错误原因在于不应该只修改报文的 sendUp 和 sendDown 函数,考虑到上下层传输的复杂性,应该全面阅读源代码,在合适的地方进行修改,希望能在后面实现代码

有线-无线混合方案

基本思路
通过有线连接两个虫洞节点,因为有线链路中传输的数据不会被普通无线节点监听到,因此可以使用有线-无线混合场景进行虫洞攻击的模拟

引用一段指导文档中的话:

  1. 混合场景中使用了基站节点作为连接有线网和无线网的网关,使得两者
  2. 之间可以转发数据。基站节点本身相当于两个身份相同的有线节点和无线节
  3. 点。在无线场景中没有链路的概念,数据包在无线拓扑中根据ad hoc路由选
  4. 路,这种路由根据邻居之间传递的路由请求信息建立转发表。因此,想在有
  5. 线和无线节点之间传递数据,必须使用基站作为连接两个域的网关。

然后我看见了文档中的最后一句话:

  1. 此时再在 MAC 层上做类似于 3.1.1 节中的修改,就可以保证有线通信链路对外保密,形成虫洞攻击的效果。

遂放弃。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注