网站主页   操作系统    网络工程    服务器    网页制作    数据库    程序开发    网络安全    办公软件   
讲座日期: 本周六下午1点30分 抢座
讲座地点: 北大青鸟马甸校区
主讲老师: 王老师 金牌讲师
讲座主题: 网络安全
讲座内容: 检测、防御、黑客信息,如何过滤不安全的网站,如何防御黑客的进攻。
订座电话: 010-82011432/33
  您当前位置:主页 > 网络学院 > 程序开发 > C++/C教程 >

Building Into The Linux Network Layer




-------[ Phrack Magazine --- Vol. 9 | Issue 55 --- 09.09.99 --- 12 of 19 ]


-------------------------[ Building Into The Linux Network Layer ]


--------[ kossak <kossak@hackers-pt.org>, lifeline <arai@hackers-pt.org> ]


----[ Introduction

As we all know, the Linux kernel has a monolithic architecture. That basically
means that every piece of code that is executed by the kernel has to be loaded
into kernel memory. To prevent having to rebuild the kernel every time new
hardware is added (to add drivers for it), Mr. Linus Torvalds and the gang
came up with the loadable module concept that we all came to love: the linux
kernel modules (lkm's for short). This article begins by pointing out yet more
interesting things that can be done using lkm's in the networking layer, and
finishes by trying to provide a solution to kernel backdooring.


----[ Socket Kernel Buffers

TCP/IP is a layered set of protocols. This means that the kernel needs to use
several routine functions to process the different packet layers in order to
fully "understand" the packet and connect it to a socket, etc. First, it
needs a routine to handle the link-layer header and, once processed there, the
packet is passed to the IP-layer handling routine(s), then to the transport-
layer routine(s) and so on. Well, the different protocols need a way
to communicate with each other as the packets are being processed. Under Linux
the answer to this are socket kernel buffers (or sk_buff's). These are used to
pass data between the different protocol layers (handling routines) and
the network device drivers.

The sk_buff{} structure (only the most important items are presented, see
linux/include/linux/skbuff.h for more):

sk_buff{}
--------+
next |
--------|
prev |
--------|
dev |
--------|
|
--------|
head |---+
--------| |
data |---|---+
--------| | |
tail |---|---|---+
--------| | | |
end |---|---|---|---+
--------|<--+ | | |
| | | |
--------|<------+ | |
Packet | | |
being | | |
handled | | |
--------|<----------+ |
| |
| |
| |
--------+<--------------+

next: pointer to the next sk_buff{}.
prev: pointer to the previous sk_buff{}.
dev: device we are currently using.
head: pointer to beginning of buffer which holds our packet.
data: pointer to the actual start of the protocol data. This may vary
depending of the protocol layer we are on.
tail: pointer to the end of protocol data, also varies depending of the
protocol layer using he sk_buff.
end: points to the end of the buffer holding our packet. Fixed value.


For further enlightenment, imagine this:

- host A sends a packet to host B

- host B receives the packet through the appropriate network device.

- the network device converts the received data into sk_buff data structures.

- those data structures are added to the backlog queue.

- the scheduler then determines which protocol layer to pass the received
packets to.

Thus, our next question arises... How does the scheduler determine which
protocol to pass the data to? Well, each protocol is registered in a
packet_type{} data structure which is held by either the ptype_all list or
the ptype_base hash table. The packet_type{} data structure holds information
on protocol type, network device, pointer to the protocol's receive data
processing routine and a pointer to the next packet_type{} structure. The
network handler matches the protocol types of the incoming packets (sk_buff's)
with the ones in one or more packet_type{} structures. The sk_buff is then
passed to the matching protocol's handling routine(s).


----[ The Hack

What we do is code our own kernel module that registers our packet_type{}
data structure to handle all incoming packets (sk_buff's) right after they
come out of the device driver. This is easier than it seems. We simply fill
in a packet_type{} structure and register it by using a kernel exported
function called dev_add_pack(). Our handler will then sit between the device
driver and the next (previously the first) routine handler. This means that
every sk_buff that arrives from the device driver has to pass first through our
packet handler.


----[ The Examples

We present you with three real-world examples, a protocol "mutation" layer,
a kernel-level packet bouncer, and a kernel-level packet sniffer.


----[ OTP (Obscure Transport Protocol)

The first one is really simple (and fun too), it works in a client-server
paradigm, meaning that you need to have two modules loaded, one on the client
and one on the server (duh). The client module catches every TCP packet with
the SYN flag on and swaps it with a FIN flag. The server module does exactly
the opposite, swaps the FIN for a SYN. I find this particularly fun since both
sides behave like a regular connection is undergoing, but if you watch it on
the wire it will seem totally absurd. This can also do the same for ports and
source address. Let's look at an example taken right from the wire.

Imagine the following scenario, we have host 'doubt' who wishes to make a
telnet connection to host 'hardbitten'. We load the module in both sides
telling it to swap port 23 for 80 and to swap a SYN for a FIN and vice-versa.

[lifeline@doubt ITP]$ telnet hardbitten
A regular connection (without the modules loaded) looks like this:

03:29:56.766445 doubt.1025 > hardbitten.23: tcp (SYN)
03:29:56.766580 hardbitten.23 > doubt.1025: tcp (SYN ACK)
03:29:56.766637 doubt.1025 > hardbitten.23: tcp (ACK)

(we only look at the initial connection request, the 3-way handshake)

Now we load the modules and repeat the procedure. If we look at the wire the
connection looks like the following:

03:35:30.576331 doubt.1025 > hardbitten.80: tcp (FIN)
03:35:30.576440 hardbitten.80 > doubt.1025: tcp (FIN ACK)
03:35:30.576587 doubt.1025 > hardbitten.80: tcp (ACK)

When, what is happening in fact, is that 'doubt' is (successfully) requesting a
telnet session to host 'hardbitten'. This is a nice way to evade IDSes and
many firewall policies. It is also very funny. :-)

Ah, There is a problem with this, when closing a TCP connection the FIN's are
replaced by SYN's because of the reasons stated above, there is, however, an
easy way to get around this, is to tell our lkm just to swap the flags when the
socket is in TCP_LISTEN, TCP_SYN_SENT or TCP_SYN_RECV states. I have not
implemented this partly to avoid misuse by "script kiddies", partly because of
laziness and partly because I'm just too busy. However, it is not hard to do
this, go ahead and try it, I trust you.


----[ A Kernel Traffic Bouncer

This packet relaying tool is mainly a proof of concept work at this point.
This one is particularly interesting when combined with the previous example.
We load our module on the host 'medusa' that then sits watching every packet
coming in. We want to target host 'hydra' but this one only accepts telnet
connections from the former. However, it's too risky to log into 'medusa'
right now, because root is logged. No problem, we send an ICMP_ECHO_REQUEST
packet that contains a magic cookie or password and 2 ip's and 2 ports like:
<sourceip:srcport, destip:destport>. We ca

上一篇:用C语言小程序来解决大问题  
下一篇:解析C语言中的sizeof
相关信息:

·Using make to Simplify the Build Process

Copyright © 2002-2015 版权所有
学校地址:北京市海淀区西三旗建材城中路29号北大青鸟
招生热线:010-82011433/32 京公网安备110102004704  京ICP备05043413号 京公网安备110102004704