当前位置:编程学习 > 网站相关 >>

深入Linux网络核心堆栈

==Phrack Inc.==

卷标 0x0b 期刊号 0x3d Phile #0x0d of 0x0f

|=---------------------=[ 深入Linux网络核心堆栈 ]=-----------------------=|
|=-----------------------------------------------------------------------=|
|=------------------=[ bioforge <alkerr@yifan.net> ]=--------------------=|
|=------------------------=[ 翻译 : raodan ]=----------------------------=|

目录

1 - 简介
1.1 - 本文涉及的内容
1.2 - 本文不涉及的内容
2 - 各种Netfilter hook及其用法
2.1 - Linux内核对数据包的处理
2.2 - Netfilter对IPv4的hook
3 - 注册和注销Netfilter hook
4 - Netfilter 基本的数据报过滤技术[1]
4.1 - 深入hook函数
4.2 - 基于接口进行过滤
4.3 - 基于地址进行过滤
4.4 - 基于TCP端口进行过滤
5 - Netfilter hook的其它可能用法
5.1 - 隐藏后门的守护进程
5.2 - 基于内核的FTP密码嗅探器
5.2.1 - 源代码 : nfsniff.c
5.2.2 - 源代码 : getpass.c
6 - 在Libpcap中隐藏网络通信
6.1 - SOCK_PACKET、SOCK_RAW与Libpcap
6.2 - 给狼披上羊皮
7 - 结束语
A - 轻量级防火墙
A.1 - 概述
A.2 - 源代码 : lwfw.c
A.3 - 头文件 : lwfw.h
B - 第6节中的源代码

--[ 1 - 简介

本文将向你展示,Linux的网络堆栈的一些怪异行为(并不一定是弱点)如何被用于邪恶的或者是其它形形色色的目的。在这里将要讨论的是将表面上看起来合法的Netfilter hook用于后门的通信,以及一种使特定的网络通信在运行于本机的基于Libpcap的嗅探器中消声匿迹的技术。
Netfilter是Linux 2.4内核的一个子系统,Netfiler使得诸如数据包过滤、网络地址转换(NAT)以及网络连接跟踪等技巧成为可能,这些功能仅通过使用内核网络代码提供的各式各样的hook既可以完成。这些hook位于内核代码中,要么是静态链接的,要么是以动态加载的模块的形式存在。可以为指定的网络事件注册相应的回调函数,数据包的接收就是这样一个例子。


----[ 1.1 - 本文涉及的内容

本文讨论模块编写者如何利用Netfilter hook来实现任意目的以及如何将将网络通信在基于Libpcap的应用程序中隐藏。虽然Linux 2.4支持对IPv4、IPv6以及DECnet的hook,但在本文中将只讨论关于IPv4的话题,虽然如此,大部分关于IPv4的内容都同样可以运用于其它几种协议。出于教学的目的,附录A提供了一个可用的、提供基本的包过滤的内核模块。本文中所有的开发和试验都在运行于Intel主机上的Linux 2.4.5中完成。对Netfilter hook功能的测试在环回接口、以太网接口以及调制解调器点对点接口上完成。

本文也是出于我对Netfilter完全理解的尝试的兴趣而写的。我并不能保证文中附带的任何代码100%的没有错误,但是我已经测试了所有在这里提供的代码。我已经受够了核心错误的折磨,因此真诚的希望你不会再如此。同样,我不会为任何按照本文所述进行的操作中可能发生的损害承担责任。本文假定读者熟悉C语言编程并且有一定的关于可加载模块的经验。

欢迎对本文中出现的错误进行批评指正,我同时开诚布公的接受对本文的改进以及其它各种关于Netfilter的优秀技巧的建议。


---- [ 1.2 - 本文不涉及的内容

本文不是一个完全的关于Netfilter的细节上的参考资料,同样,也不是一个关于iptables的命令的参考资料。如果你想了解更多的关于iptables的命令,请参考相关的手册页。

好了,让我们从Netfilter的使用介绍开始 ...


--[ 2 - 各种Netfilter hook及其用法
----[ 2.1 - Linux内核对数据包的处理

看起来好像是我很喜欢深入到诸如Linux的数据包处理以及事件的发生以及跟踪每一个Netfilter hook这样的血淋淋的细节中,事实并非如此!原因很简单,Harald Welte已经写了一篇关于这个话题的优秀的文章——《Journey of a Packet Through the Linux 2.4 Network Stack》。如果你想了解更多的关于Linux数据包处理的内容,我强烈推荐你去拜读这篇文章。现在,仅需要理解:当数据包游历Linux内核的网络堆栈时,它穿过了几个hook点,在这里,数据包可以被分析并且选择是保留还是丢弃,这些hook点就是Netfilter hook。


----[ 2.2 - Netfilter对IPv4的hook

Netfilter中定义了五个关于IPv4的hook,对这些符号的声明可以在linux/netfilter_ipv4.h中找到。这些hook列在下面的表中:

表1 : 可用的IPv4 hook

Hook 调用的时机
NF_IP_PRE_ROUTING 在完整性校验之后,选路确定之前
NF_IP_LOCAL_IN 在选路确定之后,且数据包的目的是本地主机
NF_IP_FORWARD 目的地是其它主机地数据包
NF_IP_LOCAL_OUT 来自本机进程的数据包在其离开本地主机的过程中
NF_IP_POST_ROUTING 在数据包离开本地主机“上线”之前

NF_IP_PRE_ROUTING这个hook是数据包被接收到之后调用的第一个hook,这个hook既是稍后将要描述的模块所用到的。当然,其它的hook同样非常有用,但是在这里,我们的焦点是在NF_IP_PRE_ROUTING这个hook上。

在hook函数完成了对数据包所需的任何的操作之后,它们必须返回下列预定义的Netfilter返回值中的一个:

表2 : Netfilter返回值

返回值 含义
NF_DROP 丢弃该数据包
NF_ACCEPT 保留该数据包
NF_STOLEN 忘掉该数据包
NF_QUEUE 将该数据包插入到用户空间
NF_REPEAT 再次调用该hook函数

NF_DROP这个返回值的含义是该数据包将被完全的丢弃,所有为它分配的资源都应当被释放。NF_ACCEPT这个返回值告诉Netfilter:到目前为止,该数据包还是被接受的并且该数据包应当被递交到网络堆栈的下一个阶段。NF_STOLEN是一个有趣的返回值,因为它告诉Netfilter,“忘掉”这个数据包。这里告诉Netfilter的是:该hook函数将从此开始对数据包的处理,并且Netfilter应当放弃对该数据包做任何的处理。但是,这并不意味着该数据包的资源已经被释放。这个数据包以及它独自的sk_buff数据结构仍然有效,只是hook函数从Netfilter获取了该数据包的所有权。不幸的是,我还不是完全的清楚NF_QUEUE到底是如果工作的,因此在这里我不讨论它。最后一个返回值NF_REPEAT请求Netfilter再次调用这个hook函数。显然,使用者应当谨慎使用NF_REPEAT这个返回值,以免造成死循环。

--[3 - 注册和注销Netfilter hook

注册一个hook函数是围绕nf_hook_ops数据结构的一个非常简单的操作,nf_hook_ops数据结构在linux/netfilter.h中定义,该数据结构的定义如下:

struct nf_hook_ops {
struct list_head list;

/* 此下的值由用户填充 */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hook以升序的优先级排序 */
int priority;
};

该数据结构中的list成员用于维护Netfilter hook的列表,并且不是用户在注册hook时需要关心的重点。hook成员是一个指向nf_hookfn类型的函数的指针,该函数是这个hook被调用时执行的函数。nf_hookfn同样在linux/netfilter.h中定义。pf这个成员用于指定协议族。有效的协议族在linux/socket.h中列出,但对于IPv4我们希望使用协议族PF_INET。hooknum这个成员用于指定安装的这个函数对应的具体的hook类型,其值为表1中列出的值之一。最后,priority这个成员用于指定在执行的顺序中,这个hook函数应当在被放在什么地方。对于IPv4,可用的值在linux/netfilter_ipv4.h的nf_ip_hook_priorities枚举中定义。出于示范的目的,在后面的模块中我们将使用NF_IP_PRI_FIRST。

注册一个Netfilter hook需要调用nf_register_hook()函数,以及用到一个nf_hook_ops数据结构。nf_register_hook()函数以一个nf_hook_ops数据结构的地址作为参数并且返回一个整型的值。但是,如果你真正的看了在net/core/netfilter.c中的nf_register_hook()函数的实现代码,你会发现该函数总是返回0。以下提供的是一个示例代码,该示例代码简单的注册了一个丢弃所有到达的数据包的函数。该代码同时展示了Netfilter的返回值如何被解析。

示例代码1 : Netfilter hook的注册
/*
* 安装一个丢弃所有到达的数据包的Netfilter hook函数的示例代码
*/

#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

/* 用于注册我们的函数的数据结构 */
static struct nf_hook_ops nfho;

/* 注册的hook函数的实现 */
unsigned int hook_func(unsigned int hooknum
struct sk_buff **skb
const struct net_device *in
const struct net_device *out
int (*okfn)(struct sk_buff *))
{
return NF_DROP; /* 丢弃所有的数据包 */
}

/* 初始化程序 */
int init_module()
{
/* 填充我们的hook数据结构 */
nfho.hook = hook_func; /* 处理函数 */
nfho.hooknum = NF_IP_PRE_ROUTING; /* 使用IPv4的第一个hook */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* 让我们的函数首先执行 */

nf_register_hook(&nfho);

return 0;
}

/* 清除程序 */
void cleanup_module()
{
nf_unregister_hook(&nfho);
}

这就是全部内容,从示例代码1中,你可以看到,注销一个Netfilter hook是一件很简单事情,只需要调用nf_unregister_hook()函数,并且以你之前用于注册这个hook时用到的相同的

补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,