服务器 频道

深入Linux网络核心堆栈之六

  【IT168 服务器学院】--[ 6 - 在Libpcap中隐藏网络通信

  这一节简短的描述,如何在修改Linux的内核,使与匹配预先定义的条件的网络通信对运行于本机的数据包嗅探工具不可见。列在本文最后的是可以正常运行的代码,它实现了隐藏所有来自或者是去往指定的IP地址的数据包的功能。好了,让我们开始...

  ----[ 6.1 - SOCK_PACKET、SOCK_RAW与Libpcap

  对系统管理员来说,最有用的软件莫过于哪些在广义分类下被称为“数据包嗅探器”的软件了。两个最典型的通用数据包嗅探器是tcpdump(1)以及ethereal(1)。这两个软件都利用了Libpcap库(随着参考文献[1]中的tcpdump发布)来抓取原始数据包。网络入侵检测系统(NIDS)也利用了Libpcap库。SNORT需要Libpcap,Libnids——一个提供IP重组和TCP流跟踪的NIDS开发库(参见参考文献[2]),也是如此。

  在Linux系统下,Libpcap库使用SOCK_PACKET接口。Packet套接字是一种特殊的套接字,它可以用于发生和接收链路层的原始数据包。关于Paket套接字有很多话题,但是由于本节讨论的是关于如何隐藏它们而不是如何利用它们,感兴趣的读者可以直接去看packet(7)手册页。对于本文中的讨论,只需要理解packet套接字被Libpcap应用程序用于获取进入或者离开本地主机的原始数据包。

  当核心网络堆栈收到一个数据包的时候,检查该数据包是否是某个packet套接字感兴趣的数据包。如果是,则将该数据递交给那些对其感兴趣的套接字。如果不是,该数据包继续它的旅程,进入TCP、UDP或者其它类型的套接字。对于SOCK_RAW类型的套接字同样如此。原始套接字很类似于packet套接字,只是原始套接字不提供链路层的包头。一个利用原始套接字的实用程序的例子是我的SYNalert程序,参见参考文献[3](请原谅我在这儿插入的题外话 :)。

  到此,你应该已经了解了Linux下的数据包嗅探软件使用了Libpcap库。Libpcap在Linux下利用packet套接字接口来获取包含链路层包头的原始数据包。同时提到了原始套接字,它提供给用户空间的应用程序获取包含IP头的数据包的方法。下一节将讨论如何通过Linux核心模块来隐藏来自这些packet套接字以及原始套接字的网络通信。

  ------[ 6.2 给狼披上羊皮

  当收到数据包并将其送到一个packet套接字时,packet_rcv()函数被调用。这个函数可以在net/packet/af_packet.c中找到,packet_rcv()负责使数据包经过所有应用于目的套接字的套接字过滤器,并最终将其递交到用户空间。为了隐藏来自packet套接字的数据包,我们需要阻止所有特定数据包调用packet_rcv()函数。我们如何做到这一点?当然是优秀的ol式的函数劫持了。

  函数劫持的基本操作是:如果我们知道一个内核函数,甚至是那些没有被导出的函数,的入口地址,我们可以在使实际的代码运行前将这个函数重定位到其他的位置。为了达到这样的目的,我们首先要从这个函数的开始,保存其原来的指令字节,然后将它们换成跳转到我们的代码处执行的绝对跳转指令。例如以i386汇编语言实现该操作如下:

  movl  (address of our function),  %eax
  jmp   *eax

  这些指令的16进制代码如下(假设我们的函数地址为0):

  0xb8 0x00 0x00 0x00 0x00
  0xff 0xe0

  如果我们在Linux核心模块的初始化时将上例中的函数地址替换为我们的hook函数的地址,我们就能够使我们的hook函数先运行。当我们想运行原来的函数时,我们只需要在开始时恢复函数原来的指令,调用该函数并且替换我们的劫持代码。简单而有效。Silvio Cesare 不久前写过一篇文章,讲述如何实现内核函数劫持,参见参考文献[4]。

  要从packet套接字隐藏数据包,我们首先要写一个hook函数,用于检查数据包是否满足我们隐藏的标准。如果满足,那么我们的hook函数简单的向它的调用函数返回0,packet_rcv()永远不会被调用。如果packet_rcv()永远不被调用,那么这个数据包也永远都不会递交给用户空间的packet套接字。注意,只是对于"packet"套接字来说,该数据包被丢弃了。如果我们要过滤送到packet套接字的FTP数据包,那么FTP服务器的TCP套接字仍然能收到这些数据包。我们所做的一切只是使运行在本机上的嗅探软件无法看到这些数据包。FTP服务器仍然能够处理和记录连接。

  理论上就是这么多,关于原始套接字的用法同理可得。不同的是我们需要hook的是raw_rcv()函数(在net/ipv4/raw.c中可以找到)。下一节将给出并讨论一个Linux核心模块的示例代码,该代码劫持packet_rcv()函数和raw_rcv()函数,隐藏任何来自或去往我们指定的IP地址的数据包。
 

0
相关文章