深入Linux内核网络堆栈
第一章 简介
本文将描述如何利用Linux网络堆栈的窍门(不一定都是漏洞)来达到一些目的,或者是恶意的,或者是出于其它意图的。文中会就后门通讯对Netfilter钩子进行讨论,并在本地机器上实现将这个传输从基于Libpcap的嗅探器(sniffer)中隐藏。
Netfilter是2.4内核的一个子系统。Netfilter可以通过在内核的网络代码中使用各种钩子来实现数据包过滤,网络地址转换(NAT)和连接跟踪等网络欺骗。这些钩子被放置在内核代码段,或者静态编译进内核,或者作为一个可动态加载/卸载的可卸载模块,然后就可以注册称之为网络事件的函数(比如数据包的接收)。
1.1 本文论述的内容
本文将讲述内核模块的编写者如何利用Netfilter的钩子来达到任何目的,以及怎样将网络传输从一个Libpcap的应用中隐藏掉。尽管Linux2.4支持对IPV4,IPV6以及DECnet的钩子,本文只提及IPV4的钩子。但是,对IPV4的大多数应用内容同样也可以应用于其他协议。出于教学目的,我们在附录A给出了一个可以工作的内核模块,实现基本的数据包过滤功能。针对本文中所列技术的所有开发和试验都在Intel机子上的Linux2.4.5系统上进行过。对Netfilte 钩子行为的测试使用的是回环设备(Loopback device),以太网设备和一个点对点接口的调制解调器。
对Netfilter进行完全理解是我撰写本文的另一个初衷。我不能保证这篇文章所附的代码100%的没有差错,但是所列举的所有代码我都事先测试过了。我已经饱尝了内核错误带来的磨砺,而你却不必再经受这些。同样,我不会为按照这篇文档所说的任何东西进行的作所所为带来的损失而负责。阅读本篇文章的读者最好熟悉C程序设计语言,并且对内核可卸载模块有一定的经验。
如果我在文中犯了任何错误的话,请告知我。我对于你们的建议和针对此文的改进或者其它的Netfilter应用会倾心接受。
1.2 本文不会涉及到的方面
本文并不是Netfilter的完全贯穿(或者进进出出的讲解)。也不是iptables命令的介绍。如果你想更好的学习iptables的命令,可以去咨询man手册。
让我们从介绍Nerfilter的使用开始吧……….
第二章 各种NetFilter 钩子及其用法
2.1 Linux内核对数据包的处理
我将尽最大努力去分析内核处理数据包的详细内幕,然而对于事件触发处理以及之后的Netfilter 钩子不做介绍。原因很简单,因为Harald Welte 关于这个已经写了一篇再好不过的文章<<Journey of a Packet Through the Linux 2.4 Network Stack>>,如果你想获取更多关于Linux对数据包的相关处理知识的话,我强烈建议你也阅读一下这篇文章。目前,就认为数据包只是经过了Linux内核的网络堆栈,它穿过几层钩子,在经过这些钩子时,数据包被解析,保留或者丢弃。这就是所谓的Netfilter 钩子。
2.2 Ipv4中的Netfilter钩子
Netfilter为IPV4定义了5个钩子。可以在 linux/netfilter-ipv4.h里面找到这些符号的定义,表2.1列出了这些钩子。
表 2.1. ipv4中定义的钩子
钩子名称 调用时机
NF_IP_PRE_ROUTING 完整性校验之后,路由决策之前
NF_IP_LOCAL_IN 目的地为本机,路由决策之后
NF_IP_FORWARD 数据包要到达另外一个接口去
NF_IP_LOCAL_OUT 本地进程的数据,发送出去的过程中
NF_IP_POST_ROUTING 向外流出的数据上线之前
复制代码
NF_IP_PRE_ROUTING 钩子称为是数据包接收后第一个调用的钩子程序,这个钩子在我们后面提到的模块当中将会被用到。其他的钩子也很重要,但是目前我们只集中探讨NF_IP_PRE_ROUTING这个钩子。
不管钩子函数对数据包做了哪些处理,它都必须返回表2.2中的一个预定义好的Netfilter返回码。
表2.2 Netfilter 返回码
返回码 含义
NF_DROP 丢弃这个数据包
NF_ACCEPT 保留这个数据包
NF_STOLEN 忘掉这个数据包
NF_QUEUE 让这个数据包在用户空间排队
NF_REPEAT 再次调用这个钩子函数
复制代码
NF_DROP 表示要丢弃这个数据包,并且为这个数据包申请的所有资源都要得到释放。NF_ACCEPT告诉Netfilter到目前为止,这个数据包仍然可以被接受,应该将它移到网络堆栈的下一层。NF_STOLEN是非常有趣的一个返回码,它告诉Netfilter让其忘掉这个数据包。也就是说钩子函数会在这里对这个数据包进行完全的处理,而Netfilter就应该放弃任何对它的处理了。然而这并不意味着为该数据包申请的所有资源都要释放掉。这个数据包和它各自的sk_buff结构体依然有效,只是钩子函数从Netfilter夺取了对这个数据包的掌控权。不幸的是,我对于NF_QUEUE这个返回码的真实作用还不是很清楚,所在目前不对它进行讨论。最后一个返回值NF_REPEAT请求Netfilter再次调用这个钩子函数,很明显,你应该慎重的应用这个返回值,以免程序陷入死循环。
第三章 注册和注销NetFilter 钩子
注册一个钩子函数是一个围绕nf_hook_ops结构体的很简单的过程,在linux/netfilter.h中有这个结构体的定义,定义如下:
struct nf_hook_ops
{
struct list_head list;
/* User fills in from here down. */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority. */
int priority;
};
复制代码
这个结构体的成员列表主要是用来维护注册的钩子函数列表的,对于用户来说,在注册时并没有多么重要。hook是指向nf_hookfn函数的指针。也就是为这个钩子将要调用的所有函数。nf_hookfn同样定义在linux/netfilter.h这个文件中。pf字段指定了协议簇(protocol family)。Linux/socket.h中定义了可用的协议簇。但是对于IPV4我们只使用PF_INET。hooknum 域指名了为哪个特殊的钩子安装这个函数,也就是表2.1中所列出的条目中的一个。Priority域表示在运行时这个钩子函数执行的顺序。为了演示例子模块,我们选择NF_IP_PRI_FIRST这个优先级。
注册一个Netfilter钩子要用到nf_hook_ops这个结构体和nf_register_hook()函数。nf_register_hook()函数以一个nf_hook_ops结构体的地址作为参数,返回一个整型值。如果你阅读了net/core/netfilter.c中nf_register_钩子()的源代码的话,你就会发现这个函数只返回了一个0。下面这个例子注册了一个丢弃所有进入的数据包的函数。这段代码同时会向你演示Netfilter的返回值是如何被解析的。
代码列表1. Netfilter钩子的注册
/* Sample code to install a Netfilter hook function that will
* drop all incoming packets. */
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* This is the structure we shall use to register our function */
static struct nf_hook_ops nfho;
/* This is the hook function itself */
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; /* Drop ALL packets */
}
/* Initialisation routine */
int init_module()
{
/* Fill in our hook structure */
nfho.hook = hook_func; /* Handler function */
nfho.hooknum = NF_IP_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
return 0;
}
/* Cleanup routine */
void cleanup_module()
{
nf_unregister_hook(&nfho);
}
复制代码
这就是注册所要做的一切。从代码列表1你可以看到注销一个Netfilter钩子也是很简单的一件事情,只需要调用nf_unregister_hook()函数,并将注册时用到的结构体地址再次作为注销函数参数使用就可以了。
第四章 基本的NetFilter数据包过滤技术
4.1 钩子函数近距离接触
现在是我们来查看获得的数据如何传入钩子函数并被用来进行过滤决策的时候了。所以,我们需要更多的关注于nf_hookfn函数的模型。Linux/netfilter.h给出了如下的接口定义:
typedef unsigned int nf_hookfn(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
复制代码
nf_hookfn函数的第一个参数指定了表2.1给出的钩子类型中的一种。第二个参数更有趣,它是一个指向指针(这个指针指向一个sk_buff类型的结构体)的指针,它是网络堆栈用来描述数据包的结构体。这个结构体定义在linux/skbuff.h中,由于这个结构体的定义很大,这里我只着重于它当中更有趣的一些域。
或许sk_buff结构体中最有用的域就是其中的三个联合了,这三个联合描述了传输层的头信息(例如 UDP,TCP,ICMP,SPX),网络层的头信息(例如ipv4/6, IPX, RAW)和链路层的头信息(Ethernet 或者RAW)。三个联合相应的名字分别为:h,nh和mac。根据特定数据包使用的不同协议,这些联合包含了不同的结构体。应当注意,传输层的头和网络层的头极有可能在内存中指向相同的内存单元。在TCP数据包中也是这样的情况,h和nh都是指向IP头结构体的指针。这就意味着,如果认为h->th指向TCP头,从而想通过h->th来获取一个值的话,将会导致错
Hacking-the-Linux-Kernel-.zip_Sniffer_netfilter
版权申诉
100 浏览量
2022-09-20
18:42:35
上传
评论
收藏 15KB ZIP 举报
朱moyimi
- 粉丝: 61
- 资源: 1万+
最新资源
- 解决未在远程桌面会话中捕获到鼠标,vmguest.iso软件分享给大家
- JSP+SQL基于WEB的开放性实验管理系统设计与实现(源代码+论文+开题报告+中英文献+答辩PPT).rar
- log4net配置文件!!!!!!!!!!!!!!!!!
- 河南统计面板数据集(2010-2022年).xlsx
- OrcaleDBHelper帮助类!!!!!!!!!!!!
- log4net帮助类,用来写日志!!!!!!!!!!!!!
- Windows10时间同步源
- 信呼OA系统2.1.7版源码
- 3122080306 邹子轩 实验报告二.docx
- 基于STM32 NUCLEO板设计彩色LED照明灯(纯cubeMX开发)(大赛作品,文档完整,可直接运行)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈