版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、个人资料整理,仅供个人学习使用深入 Linux 网络核心堆栈 -netfilter 详解目录 - 1 - 简介Netfilter hook 的嗅探器中消声本文将向你展示, Linux 的网络堆栈的一些怪异行为(并不一定是弱点)如何被用于邪 恶的或者是其它形形色色的目的。 在这里将要讨论的是将表面上看起来合法的 用于后门的通信, 以及一种使特定的网络通信在运行于本机的基于 Libpcap 匿迹的技术。 矚慫润厲钐瘗睞枥庑赖賃軔。网络地址转换Netfilter 是 Linux 2.4 内核的一个子系统, Netfiler 使得诸如数据包过滤、(NAT)以及网络连接跟踪等技巧成为可能,这些功能仅通过
2、使用内核网络代码提供的各式各 样的 hook 既可以完成。 这些 hook 位于内核代码中, 要么是静态链接的, 要么是以动态加载 的模块的形式存在。 可以为指定的网络事件注册相应的回调函数, 数据包的接收就是这样一 个例子。 聞創沟燴鐺險爱氇谴净祸測。 1.1 - 本文涉及的内容本文讨论模块编写者如何利用 Netfilter hook 来实现任意目的以及如何将将网络通信在 基于 Libpcap 的应用程序中隐藏。虽然 Linux 2.4 支持对 IPv4、IPv6 以及 DECnet 的 hook, 但在本文中将只讨论关于 IPv4 的话题,虽然如此, 大部分关于 IPv4 的内容都同样可以
3、运用 于其它几种协议。出于教学的目的,附录 A 提供了一个可用的、提供基本的包过滤的内核 模块。本文中所有的开发和试验都在运行于 Intel 主机上的 Linux 2.4.5 中完成。对 Netfilter hook 功能的测试在环回接口、以太网接口以及调制解调器点对点接口上完成。残骛楼諍锩瀨濟溆塹籟婭骒。同样,我不会为任何按照本文所述进行的操作中C 语言编程并且有一定的关于可加载模块的本文也是出于我对 Netfilter 完全理解的尝试的兴趣而写的。 我并不能保证文中附带的任 何代码 100%的没有错误,但是我已经测试了所有在这里提供的代码。我已经受够了核心错 误的折磨, 因此真诚的希望你不
4、会再如此。 可能发生的损害承担责任。本文假定读者熟悉 经验。 酽锕极額閉镇桧猪訣锥顧荭。我同时开诚布公的接受对本文的改进以及其它欢迎对本文中出现的错误进行批评指正,各种关于 Netfilter 的优秀技巧的建议。 彈贸摄尔霁毙攬砖卤庑诒尔。 1.2 - 本文不涉及的内容本文不是一个完全的关于 Netfilter 的细节上的参考资料, 同样,也不是一个关于 iptables 的命令的参考资料。 如果你想了解更多的关于 iptables 的命令, 请参考相关的手册页。 謀荞抟 箧飆鐸怼类蒋薔點鉍。好了,让我们从 Netfilter 的使用介绍开始 .- 2 - 各种 Netfilter hook
5、及其用法 2.1 - Linux 内核对数据包的处理看起来好像是我很喜欢深入到诸如 Linux 的数据包处理以及事件的发生以及跟踪每一个 Netfilter hook 这样的血淋淋的细节中,事实并非如此!原因很简单,Harald Welte 已经写了一篇关于这个话题的优秀的文章? Journey of a Packet Through the Linux 2.4 Networkstack。如果你想了解更多的关于Linux数据包处理的内容,我强烈推荐你去拜读这篇文章。现在,仅需要理解:当数据包游历 Linux 内核的网络堆栈时,它穿过了几个 hook 点,在这 里,数据包可以被分析并且选择是保留
6、还是丢弃,这些 hook 点就是 Netfilter hook。 厦礴恳蹒 骈時盡继價骚卺癩。 2.2 - Netfilter 对 IPv4 的 hook的 hook ,对这些符号的声明可以在 linux/netfilter_ipv4.h 茕桢广鳓鯡选块网羈泪镀齐。Netfilter 中定义了五个关于 IPv4中找到。这些 hook 列在下面的表中:37 / 37表 1 : 可用的 IPv4 hookHook NF_IP_PRE_ROUTING NF_IP_LOCAL_IN NF_IP_FORWARD NF_IP_LOCAL_OUTNF_IP_POST_ROUTINGNF_IP_PRE_ROU
7、TING调用的时机在完整性校验之后,选路确定之前 在选路确定之后,且数据包的目的是本地主机 目的地是其它主机地数据包来自本机进程的数据包在其离开本地主机的过程中 在数据包离开本地主机 “上线 ”之前这个hook是数据包被接收到之后调用的第一个hook,这个hook既是稍后将要描述的模块所用到的。当然,其它的 hook 同样非常有用,但是在这里,我们 的焦点是在 NF_IP_PRE_ROUTING 这个 hook 上。 鹅娅尽損鹌惨歷茏鴛賴縈诘。在 hook 函数完成了对数据包所需的任何的操作之后,它们必须返回下列预定义的Netfilter 返回值中的一个: 籟丛妈羥为贍偾蛏练淨槠挞。表 2 :
8、 Netfilter 返回值返回值NF_DROPNF_ACCEPT含义丢弃该数据包保留该数据包忘掉该数据包 将该数据包插入到用户空间 再次调用该 hook 函数NF_STOLEN NF_QUEUE NF_REPEATNF_DROP 这个返回值的含义是该数据包将被完全的丢弃, 被释放。 NF_ACCEPT 这个返回值告诉 Netfilter :到目前为止,该数据包还是被接受的并且 该数据包应当被递交到网络堆栈的下一个阶段。 NF_STOLEN所有为它分配的资源都应当是一个有趣的返回值, 因为它告诉 Netfilter ,“忘掉 ”这个数据包。 这里告诉 Netfilter 的是: 该 hook
9、函数将从此开始对数据 包的处理, 并且 Netfilter 应当放弃对该数据包做任何的处理。 但是, 这并不意味着该数据包 的资源已经被释放。 这个数据包以及它独自的 sk_buff 数据结构仍然有效, 只是 hook 函数从 Netfilter 获取了该数据包的所有权。不幸的是,我还不是完全的清楚NF_QUEUE 到底是如果工作的, 因此在这里我不讨论它。 最后一个返回值 NF_REPEAT 请求 Netfilter 再次调用这 个 hook 函数。显然,使用者应当谨慎使用 NF_REPEAT 这个返回值,以免造成死循环。 頌圣鉉儐歲龈讶骅籴買闥。-3 - 注册和注销 Netfilter h
10、ook注册一个 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 时 需要关心的重点。
11、 hook 成员是一个指向 nf_hookfn 类型的函数的指针,该函数是这个 hook 被调用时执行的函数。 nf_hookfn 同样在 linux/netfilter.h 中定义。 pf 这个成员用于指定协议族。有效的协议族在 linux/socket.h 中列出,但对于 IPv4 我们希望使用协议族 PF_INET 。 hooknum 这个成员用于指定安装的这个函数对应的具体的 hook 类型,其值为表 1 中列出的 值之一。最后, priority 这个成员用于指定在执行的顺序中,这个hook 函数应当在被放在什么地方。对于 IPv4 ,可用的值在 linux/netfilter_ip
12、v4.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。
13、以下提供的是一个示例代码,该示例代码简单的注册了 一个丢弃所有到达的数据包的函数。该代码同时展示了 Netfilter 的返回值如何被解析。 擁締 凤袜备訊顎轮烂蔷報赢。示例代码 1 : Netfilter hook 的注册/*Netfilter hook 函数的示例代码* 安装一个丢弃所有到达的数据包的 */ #define _KERNEL #define MODULE#include #include */#include #include /* 用于注册我们的函数的数据结构 static struct nf_hook_ops nfho;/* 注册的 hook 函数的实现 */ unsig
14、ned 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; /* 使用
15、 IPv4 的第一个 hook */ 贓熱俣阃歲匱阊邺 镓騷鯛汉。= PF_INET;= NF_IP_PRI_FIRST;/* 让我们的函数首先执行*/ 坛摶乡囂忏蒌鍥铃氈淚跻nfho.pfnfho.priority 馱。nf_register_hook(&nfho);return 0;/* 清除程序 */void cleanup_module()nf_unregister_hook(&nfho);这就是全部内容,从示例代码 1中,你可以看到,注销一个 Netfilter hook是一件很简 单事情,只需要调用 nf_unregister_hook() 函数,并且以你之前用于注册这个 hook
16、 时用到的 相同的数据结构的地址作为参数。 蜡變黲癟報伥铉锚鈰赘籜葦。- 4 - Netfilter 基本的数据报过滤技术 4.1 - 深入 hook 函数现在是到了看看什么数据被传递到 hook 函数中以及这些数据如何被用于做过滤选择的 时候了。那么,让我们更深入的看看 nf_hookfn 函数的原型吧。 这个函数原型在 linux/netfilter.h 中给出,如下: 買鲷鴯譖昙膚遙闫撷凄届嬌。typedef unsigned int nf_hookfn(unsigned int hooknum, 綾镝鯛駕櫬鹕踪韦辚糴飙钪。 struct sk_buff *skb, const stru
17、ct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *);nf_hookfn 函数的第一个参数用于指定表 1 中给出的 hook 类型中的一个。 第二个参数更 加有趣,它是一个指向指针的指针,该指针指向的指针指向一个sk_buff 数据结构,网络堆栈用 sk_buff 数据结构来描述数据包。这个数据结构在 linux/skbuff.h 中定义,由于它的内容 太多,在这里我将仅列出其中有意义的部分。 驅踬髏彦浃绥譎饴憂锦諑琼。sk_buff 数据结构中最有用的部分可能就是那三个描述传输层包头(例如
18、:UDP, TCP,ICMP, SPX )、网络层包头(例如:IPV4/6, IPX, RAW )以及链路层包头(例如:以太网或者 RAW)的联合(union) 了。这三个联合的名字分别是h、nh以及mac。这些联合包含了几个其中 h 和 nh 都应当被看作 并认为该指针指向一个 TCP 与 nh-iph 得到的结果相同。结构, 依赖于具体的数据包中使用的协议。 使用者应当注意: 传输层包头和网络层包头可能 是指向内存中的同一个位置。这是TCP数据包可能出现的情况,是指向 IP 头结构的指针。 这意味着尝试通过 h-th 获取一个值, 头,将会得到错误的结果。因为h-th实际上是指向的IP头,
19、猫虿驢绘燈鮒诛髅貺庑献鵬。len 指定了从 data 开始的数据接下来让我们感兴趣的其它部分是 len 和 data 这两个域。 包中的数据的总长度。好了,现在我们知道如何在 sk_buff 数据结构中分别访问协议头和数 据包中的数据了。 Netfilter hook 函数中有用的信息中其它的有趣的部分是什么呢? 锹籁饗迳琐 筆襖鸥娅薔嗚訝。紧跟在 skb 之后的两个参数是指向 net_device 数据结构的指针, net_device 数据结构被 Linux内核用于描述所有类型的网络接口。这两个参数中的第一个??in,用于描述数据包到达的接口,毫无疑问,参数 out 用于描述数据包离开的接
20、口。必须明白,在通常情况下,这 两个参数中将只有一个被提供。 例如:参数 in 只用于 NF_IP_PRE_ROUTING 和 NF_IP_LOCAL_IN hook ,参数 out 只用于 NF_IP_LOCAL_OUT 和 NF_IP_POST_ROUTING hook。在这一个阶段中,我还没有测试对于NF_IP_FORWARD hook,这两个参数中哪些是有效的,但是如果你能在使用之前先确定这些指针是非空的,那么你是非常优秀的!構氽頑黉碩饨荠龈话骛門戲。最后,传递给 hook 函数的最后一个参数是一个命名为 okfn 函数指针,该函数以一个sk_buff 数据结构作为它唯一的参数,并且返
21、回一个整型的值。我不是很确定这个函数是干 什么用的,在 net/core/netfilter.c 中查看,有两个地方调用了这个 okfn 函数。这两个地方是 分别在函数 nf_hook_slow()中以及函数 nf_reinject()中,在其中的某个位置,当Netfilter hook的返回值为 NF_ACCEPT 时被调用。如果任何人有更多的关于 okfn 函数的信息,请务必告 知。 輒峄陽檉簖疖網儂號泶蛴镧。* 译 注 : Linux 核 心 网 络 堆 栈 中 有 一 个 全 局 变 量 : struct list_head nf_hooksNPROTONF_MAX_HOOKS ,该变
22、量是一个二维数组,其中第一维用于指定协 议族,第二维用于指定 hook的类型(表1中定义的类型)。注册一个Netfilter hook实际就 是在由协议族和 hook 类型确定的链表中添加一个新的节点。 尧侧閆繭絳闕绚勵蜆贅瀝纰。以下代码摘自 net/core/netfilter , nf_register_hook() 函数的实现:int nf_register_hook(struct nf_hook_ops *reg)struct list_head *i; br_write_lock_bh(BR_NETPROTO_LOCK); for (i = nf_hooksreg-pfreg-hoo
23、knum.next;i != &nf_hooksreg-pfreg-hooknum;i = i-next) if (reg-priority priority) 识饒鎂錕缢灩筧嚌俨淒侬减。 break;Netfilter 中定义了一个宏 NF_HOOK ,作者在前面提到的 nf_hook_slow() 函数实际上就NF_HOOK 宏定义替换的对象,在 NF_HOOK 中执行注册的 hook 函数。 NF_HOOK 在 list_add(?-list, i-prev); br_write_unlock_bh(BR_NETPROTO_LOCK); return 0;是Linux 核心网络堆栈的适当
24、的地方以适当的参数调用。例如,在 ip_rcv() 函数 ( 位于 net/ipv4/ip_input.c) 的最后部分,调用 NF_HOOK 函数,执行 NF_IP_PRE_ROUTING 类型的 hook。ip_rcv()是Linux核心网络堆栈中用于接收IPv4数据包的主要函数。在NF_HOOK的参数中,页包含一个 okfn 函数指针,该函数是用于数据包被接收后完成后续的操作,例如在 ip_rcv 中 调 用 的 NF_HOOK 中 的 okfn 函 数 指 针 指 向 ip_rcv_finish() 函 数 (位 于 net/ipv4/ip_input.c) ,该函数用于 IP 数据包
25、被接收后的诸如 IP 选项处理等后续处理。 凍鈹鋨劳 臘锴痫婦胫籴铍賄。宏定义,NF_HOOK宏定义直接被替 :恥諤銪灭萦欢煬鞏鹜錦聰櫻。鯊腎鑰诎褳鉀沩懼統庫摇饬。硕癘鄴颃诌攆檸攜驤蔹鸶胶。阌擻輳嬪諫迁择楨秘騖輛埙。如果在内核编译参数中取消 CONFIG_NETFILTER 换为 okfn ,内核代码中的相关部分如下 (linux/netfilter.h) #ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER_DEBUG#define NF_HOOK nf_hook_slow#else#define NF_HOOK(pf, hook, skb, ind
26、ev, outdev, okfn) (list_empty(&nf_hooks(pf)(hook)? (okfn)(skb) : nf_hook_slow(pf), (hook), (skb), (indev), (outdev), (okfn)#endif #else /* !CONFIG_NETFILTER */#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) 氬嚕躑竄贸恳彈瀘颔澩纷釓。 #endif /*CONFIG_NETFILTER*/可见 okfn 函数是必不可少的,当 Netfilter 被启用时,它用
27、于完成接收的数据包后的后 续操作,如果不启用 Netfilter 做数据包过滤, 则所有的数据包都被接受, 直接调用该函数做 后续操作。 釷鹆資贏車贖孙滅獅赘慶獷。* 译注完现在,我们已经了解了我们的 hook 函数接收到的信息中最有趣和最有用的部分,是该 看看我们如何以各种各样的方式来利用这些信息来过滤数据包的时候了! 怂阐譜鯪迳導嘯畫長凉 馴鸨。4.2 - 基于接口进行过滤这应该是我们能做的最简单的过滤技术了。还记得我们的 hook 函数接收的参数中的那 些 net_device 数据结构吗?使用相应的 net_device 数据结构的 name 这个成员,你就可以根 据数据包的源接口和目
28、的接口来选择是否丢弃它。 如果想丢弃所有到达接口 eth0 的数据包, 所有你需要做的仅仅是将 in-name 的值与 eth0 做比较,如果名字匹配,那么 hook 函数简 单的返回 NF_DROP 即可, 数据包会被自动销毁。 就是这么简单! 完成该功能的示例代码见 如下的示例代码 2。注意, Light-Weight FireWall 模块将会提供所有的本文提到的过滤方法 的简单示例。它还包含了一个 IOCTL 接口以及用于动态改变其特性的应用程序。 谚辞調担鈧 谄动禪泻類谨觋。示例代码 2 : 基于源接口的数据包过滤Netfilter hook 函数的示例代码/* 安装一个丢弃所有进入
29、我们指定接口的数据包的*/#define _KERNEL_ #define MODULE#include#include #include #include #include*/* 用于注册我们的函数的数据结构 static struct nf_hook_ops nfho;*/* 我们丢弃的数据包来自的接口的名字 static char *drop_if = lo;/* 注册的 hook 函数的实现 */ unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in,
30、const struct net_device *out, int (*okfn)(struct sk_buff *)if (strcmp(in-name, drop_if) = 0) printk(Dropped packet on %s.n, drop_if); return NF_DROP; else return NF_ACCEPT; /* 初始化程序 */ int init_module() hook 数据结构 */= hook_func; /* 处理函数 */= NF_IP_PRE_ROUTING; /* 使用 IPv4 的第一个 hook */ 嘰觐詿缧铴嗫偽純nfho.pf n
31、fho.priority/* 填充我们的 nfho.hook nfho.hooknum 铪锩癱恳。= PF_INET;NF_IP_PRI_FIRST; /* 让我们的函数首先执行 */ 熒绐譏钲鏌觶鷹緇機库圆nf_register_hook(&nfho);/*return 0;清除程序 */ void cleanup_module() nf_unregister_hook(&nfho);是不是很简单?接下来,让我们看看基于 IP 地址的过滤。 4.3 - 基于地址进行过滤与根据数据包的接口进行过滤类似, 基于数据包的源或目的 IP 地址进行过滤同样简单。 这次我们感兴趣的是 sk_buff 数
32、据结构。还记得 skb 参数是一个指向 sk_buff 数据结构的指针 的指针吗?为了避免犯错误, 声明一个另外的指向 skb_buff 数据结构的指针并且将 skb 指针 指向的指针赋值给这个新的指针是一个好习惯,就像这样: 鶼渍螻偉阅劍鲰腎邏蘞阕簣。sk_buff IP 地址与被禁止的地址是否相同。这些 LWFW 统计的更新被移除。 颖刍莖蛺饽亿顿struct sk_buff *sb = *skb; /* Remove 1 level of indirection* / 纣忧蔣氳頑莶驅藥悯骛覲僨。 这样,你访问这个数据结构的元素时只需要反引用一次就可以了。获取一个数据包的 IP 头通过使用
33、 sk_buff 数据结构中的网络层包头来完成。这个头位于一个联合中,可以通过 sk_buff-nh.iph 这样的方式来访问。 示例代码 3 中的函数演示了当得到一个数据包的 数据结构时,如何利用它来检查收到的数据包的源 代码是直接从 LWFW 中取出来的,唯一不同的是 裊赔泷涨负。/* */ 濫驂膽閉驟羥闈詔寢賻減栖。示例代码 3 : 检查收到的数据包的源 IP unsigned char *deny_ip = x7fx00x00x01;static int check_ip_packet(struct sk_buff *skb)/* We dont want any
34、NULL pointers in the chain to* the IP header. */if (!skb )return NF_ACCEPT; if (!(skb-nh.iph) return NF_ACCEPT;銚銻縵哜鳗鸿锓謎諏涼鏗穎。那么该数据包将被丢if (skb-nh.iph-saddr = *(unsigned int *)deny_ip) return NF_DROP; return NF_ACCEPT; 这样,如果数据包的源地址与我们设定的丢弃数据包的地址匹配,那么该函数将会返回 NF_ACCEPT 。这4 展现了用于演示将基于接口的过滤略做修 挤貼綬电麥结鈺贖哓类芈罷
35、。弃。为了使这个函数能按预期的方式工作, deny_ip 的值应当以网络字节序 (Big-endian ,与 Intel 相反 )存放。虽然这个函数不太可能以一个空的指针作为参数来调用,带一点点偏执狂 从来不会有什么坏处。当然,如果错误确实发生了, 样 Netfilter 可以继续处理这个数据包。 示例代码 改以丢弃匹配给定 IP 地址的数据包的简单模块。示例代码 4 : 基于数据包源地址的过滤 /* 安装丢弃所有来自指定 IP 地址的数据包的 Netfilter hook 的示例代码 */ #define _KERNEL_ #define MODULE#include#include #in
36、clude#include/* For IP header */#include#include*/* 用于注册我们的函数的数据结构static struct nf_hook_ops nfho;/* 我们要丢弃的数据包来自的地址,网络字节序 */static unsigned char *drop_ip = x7fx00x00x01; 赔荊紳谘侖驟辽輩袜錈極嚕。 /* 注册的 hook 函数的实现 */unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, co
37、nst struct net_device *out, int (*okfn)(struct sk_buff *) struct sk_buff *sb = *skb;/ 译注:作者提供的代码中比较地址是否相同的方法是错误的,见注释掉的部分 if (sb-nh.iph-saddr = *(unsigned int *)drop_ip) 塤礙籟馐决穩賽釙冊庫麩适。/ if (sb-nh.iph-saddr = drop_ip) printk(Dropped packet from. %d.%d.%d.%dn,*drop_ip, *(drop_ip + 1),*(drop_ip + 2), *(d
38、rop_ip + 3); return NF_DROP; else return NF_ACCEPT;/* 初始化程序 */ int init_module() /* 填充我们的 nfho.hook nfho.hooknum 羋蔺递灿。hook 数据结构 */= hook_func; /* 处理函数 */hook */ 裊樣祕廬廂颤谚鍘nfho.pf nfho.priority= PF_INET;NF_IP_PRI_FIRST;/*让我们的函数首先执行*/ 仓嫗盤紲嘱珑詁鍬齊驁絛= NF_IP_PRE_ROUTING; /* 使用 IPv4 的第一个nf_register_hook(&nfho
39、);return 0;/*清除程序 */ void cleanup_module() nf_unregister_hook(&nfho); 4.4 - 基于 TCP 端口进行过滤另一个要实现的简单规则是基于数据包的 的要求要高一点点,因为我们需要自己创建一个 于传输层包头与网络层包头的内容吗?获取一个这只比检查 IP 地址TCP 目的端口进行过滤。TCP 头的指针。还记得我们前面讨论的关TCP 头的指针是一件简单的事情 ?分配一IP 头之后的数 5 给出了检查数据包的 TCP 目的端口是否个 tcphdr 数据结构 (在 linux/tcp.h 中定义 )的指针, 并将它指向我们的数据包中 据
40、。或许一个例子的帮助会更大一些,示例代码 与某个我们要丢弃数据包的端口匹配的代码。与示例代码 绽萬璉轆娛閬蛏鬮绾瀧恒蟬。3 一样,这些代码摘自 LWFW 。示例代码 5 : 检查收到的数据包的 TCP 目的端口unsigned char *deny_port = x00x19;/* port 25 */ 骁顾燁鶚巯瀆蕪領鲡赙骠弒。static int check_tcp_packet(struct sk_buff *skb) struct tcphdr *thead;/* We dont want any NULL pointers in the chain * to the IP heade
41、r. */if (!skb ) return NF_ACCEPT;if (!(skb-nh.iph) return NF_ACCEPT;/* Be sure this is a TCP packet first */if (skb-nh.iph-protocol != IPPROTO_TCP) return NF_ACCEPT;thead = (struct tcphdr *)(skb-data +(skb-nh.iph-ihl * 4);/* Now check the destination port */ if (thead-dest) = *(unsigned short *)deny
42、_port) 瑣钋濺暧惲锟缟馭篩凉貿锕。 return NF_DROP;return NF_ACCEPT; 确实很简单!不要忘了,要让这个函数工作, deny_port 必须是网络字节序。这就是数 据包过滤的基础了, 你应当已经清楚的理解了对于一个特定的数据包, 如何获取你想要的信 息。现在,是该进入更有趣的内容的时候了! 鎦诗涇艳损楼紲鯗餳類碍穑。- 5 - Netfilter hook 的其它可能用法 在这里,我将提出其它很酷的利用 Netfilter hook 的点子, 5.1 节将简单的给出精神食粮, 而 5.2 节将讨论和给出可以工作的基于内核的 FTP 密码嗅探器的代码, 它的远程
43、密码获取功 能是确实可用的。事实上,它工作的令我吃惊的好,并且我编写了它。 栉缏歐锄棗鈕种鵑瑶锬奧 伛。 5.1 - 隐藏后门的守护进程核心模块编程也许是 Linux 开发中最有趣的部分之一了, 在内核中编写代码意味着你在 一个仅受限于你的想象力的地方写代码。 以恶意的观点来看, 你可以隐藏文件、进程, 并且 做各式各样很酷的,任何的 rootkit 能够做的事情。那么,以不太恶意的观点来看(是的, 持这中观点人们的确存在) ,你可以隐藏文件、进程以及干各式各样的事情。内核真是一个 迷人的乐园! 辔烨棟剛殓攬瑤丽阄应頁諳。Netfilter有了赋予内核级程序员的强大力量, 很多事情成为可能。
44、其中最有趣的 (也是让系统管 理员恐慌的)一个就是嵌入到内核中的后门。 毕竟,如果后门不作为一个进程运行,那么我 们怎么知道它的运行?当然, 还是有办法让你的内核揪出这样的后门来, 但是它们可不像运 行 ps 命令一样容易和简单。现今,将后门代码放到内核中去的点子已经并不新鲜了。但是, 我在这里所提出的是安放一个用作内核后门的简单的网络服务。你猜对了,正是 hook !峴扬斕滾澗辐滠兴渙藺诈機。那么你就可以构Netfilter如果你已经具备必要的技能并且情愿以做试验的名义使你的内核崩溃, 建简单但是有用的,完全位于内核中的,可以远程访问的网络服务了。基本上一个hook 可以通过观察收到的数据包
45、来查找一个 “魔法”数据包,并且当接收到这个 “魔法 ”数据包 时干指定的事情。结果可以通过 Netfilter hook 来发送。并且该 hook 函数可以返回 NF_STOLEN ,以使得收到的 “魔法 ”数据包可以走得更远。但是要注意,当以这种方式来发 送时,输出数据包对于输出 Netfilter hook 仍然是可见的。因此用户空间完全不知道这个 “魔 法”数据包的曾经到达,但是它们还是能看到你送所出的。当心!因为在泄密主机上的嗅探 器不能看到这个包并不意味着在其它中间宿主主机上的嗅探器也看不到这个包。 詩叁撻訥烬忧 毀厉鋨骜靈韬。则鯤愜韋kossak 与 lifeline 曾为 Ph
46、rack 写了一篇精彩的文章,该文描述了如何通过注册数据包类 型处理器来完成这样的功能。 虽然本文涉及的是 Netfilter hook ,我仍然建议阅读他们的这篇 文章(第 55 期,文件 12),因为它是一篇给出了一些非常有趣的点子的有趣读物。 瘓賈晖园栋泷华缙。PING 请 应答流的 键不会立即暴露它们 SSH 会话来键入那些那么,后门 Netfilter hook 可以干些什么工作呢?以下是一些建议:PING- 远程访问击键记录器 (key-logger) 。模块记录击键, 并且当远程主机发送一个 求时,结果被送到该主机。这样,可以生成一个类似于稳定的(非洪水的) 击键信息的流。当然,
47、你可能想要实现一个简单的加密,这样, ASCII 自己,并且某些警觉的系统管理员会想: “坚持,我以前都是通过我的的! Oh $%T%”&! 。 胀鏝彈奥秘孫戶孪钇賻锵咏。- 各种简单的管理员任务,例如获取当前登录到主机的用户的列表或责获取打开的网 络连接的信息。鳃躋峽祷紉诵帮废掃減萵輳。Linux 核心编程是数小- 并非一个真正的后门,而是位于网络边界的模块,并且阻挡任何被疑为来自特洛伊 木马、 ICMP 隐蔽通道或者像 KaZaa 这样的文件共享工具的通信。IP 主机和端口,并 没有网络套接字被打- 文件传输 “服务器 ”。我最近已经实现了这个主意, 由此引起的 时的乐趣 :)- 数据包跳
48、跃。重定向目的为木马主机指定端口的数据包到其它的 且从那台主机发回数据包到发起者。 没有进程被派生, 并且最妙的是, 开。 稟虛嬪赈维哜妝扩踴粜椤灣。例如:配置路- 上面描述的数据包跳跃用于与网络中的关键系统以半隐蔽方式通信。 由器等。魔法”- FTP/POP3/Telnet 密码嗅探器。嗅探输出的密码并保存相关信息,直到进入的 “ 数据包要求获取它们。 陽簍埡鲑罷規呜旧岿錟麗鲍。以上只是一些想法的简短的列表, 其中最后一个想法是我们在接下来的一节中将要真正 详细讨论的。它提供了一个很好的了解更多的深藏于核心网络代码中的函数的机会。 5.2 - 基于内核的 FTP 密码嗅探器在这里展现的是一个
49、简单的,原理性的,用做 Netfilter 后门的模块。 该模块嗅探输出的FTP数据包,查找对于一个FTP服务器一个USER于PASS命令对。当这样一个命令对被发 现后,该模块接下来将等待一个魔法” ICMP ECHO(ping)数据包,该数据包应当足够大,使其能返回服务器的 IP 地址、用户名以及密码。同时提供了一个快速的发送一个 “魔法”数据 包,获取返回然后打印返回信息的技巧。一旦用户名/密码对从模块读取后,模块将接着查找下一对。注意,模块每次只保存一个对。以上是简要的浏览,是该展示更多的细节,来看 模块如何做到这些的时候了。 沩氣嘮戇苌鑿鑿槠谔應釵蔼。当模块加载时,模块的 init_m
50、odule() 函数简单的注册了两个 Netfilter hook 。第一个用于 查看输入的数据包(在 NF_IP_PRE_ROUTING处),尝试发现 魔法” ICMP数据包。接下来的 一个用于查看离开该模块被安装的主机的数据包(在NF_IP_POST_ROUTING处),这个函数正是搜索和捕获 FTP的USER和PASS数据包的地方。cleanup_module()函数只是简单的注 销这两个 hook。 钡嵐縣緱虜荣产涛團蔺缔嵛。watch_out()是用于hook NF_IP_POST_ROUTING 的函数,查看这个函数你可以看到, 它的执行的操作非常简单。 当一个数据包进入这个函数过
51、后, 将经过各种检查, 以确定它是 一个 FTP 数据包。如果它不是一个 FTP 数据包,那么立即返回 NF_ACCEPT 。如果它是一 个 FTP 数据包,那么该模块进行检查是否已经存在一个用户名/密码对。如果存在(以have_pair的非零值标识),那么返回NF_ACCEPT ,该数据包最终能够离开该系统。否则, check_ftp() 函数被调用, 这是密码提取实际发生的地方。 如果没有先前的数据包已经被接收, 那么 target_ip 和 target_port 变量应当被清除。 懨俠劑鈍触乐鹇烬觶騮揚銥。check_ftp()开始于从数据包的开始查找 USER,PASS或QUIT。注
52、意直到 USER命 令处理之后才处理 PASS命令。这样做的目的是为了防止在某些情况下PASS命令先于USER命令被接收到以及在 USER 到达之前连接中断而导致的死锁的发生。 同样, 如果 QUIT 命令 到达时仅有用户名被捕获,那么将重置操作,开始嗅探一个新的连接。当一个USER 或者PASS 命令到达时,如果必要完整性校验通过,则记录下命令的参数。正常运行下,在 check_ftp() 函数完成之前,检查是否已经有了一个有效的用户名和密码串。如果是,则设置 have_pair 的值为非零并且在当前的用户名/密码对被获取之前不会再抓取其它的用户名或密码。 謾饱兗争詣繚鮐癞别瀘鯽礎。 到目前
53、为止你已经看到了该模块如何安装它自己以及如何开始搜寻待记录的用户名和 密码。接下来你将看到当指定的 “魔法 ”数据包到达时会发生什么。 在此需特别注意,因为这 是在整个开发过程中出现的最大难题。如果我没记错的话,共遭遇了 16 个核心错误 :)。当 数据包进安装该模块的主机时, watch_in() 检查每一个数据包以查看其是否是一个 “魔法 ”数 据包。如果数据包不能提供足以证明它是一个 “魔法 ”数据包的信息, 那么它将被被 watch_in() 忽略,简单的返回一个 NF_ACCEPT 。注意 “魔法 ”数据包的标准之一是它们必须有足够的空 间来存放 IP 地址以及用户名和密码串。这使得
54、发送应答更加容易。当然,可以重新分配一 个新的 sk_buff ,但是正确的获取所有必要的域得值可能会比较困难,并且你还必须得正确 的获取它们! 因此, 与其为我们的应答数据包创建一个新的数据结构,不如简单的调整请求数据包的数据结构。为了成功的返回数据包,需要做几个改动。首先,交换 IP 地址,并且 sk_buff 数据结构中描述数据包类型的域 (pkt_type) 应当被换成 PACKET_OUTGOING ,这些 宏在 linux/if_packet.h 中定义。接下来应当小心的是确定包含了任意的链路层头。我们接收 到的数据包的 sk_buff 数据结构的数据域指向链路层头之后,并且它是指
55、向被发送的数据包 的数据的开始的数据域。那么对于需要链路层包头(以太网及环回和点对点的raw)的接口,我们将数据域指向 mac.ethernet或者mac.raw结构。为确定这个数据包来自的什么类型的接 口你可以查看 sb-dev-type 的值,其中 sb 是一个指向 sk_buff 数据结构的指针。这个域的 有效值可以在 linux/if_arp.h 中找到,但其中最有用的几个在下面的表 3 中列出。 呙铉們欤谦鸪 饺竞荡赚趱為。接口类型以太网环回设备点对点(例如拨号)表 3 : 接口类型的常用值 类型代码 ARPHRD_ETHERARPHRD_LOOPBACK ARPHRD_PPP最后,
56、 我们要做的是真正的复制我们想在的应答中送出的数据。到送出数据包的时候了,dev_queue_xmit() 函数以一个指向 sk_buff 数据结构的指针作为它唯一的参数, 在“好的错误 ” 情况下,返回一个负的错误代码。我所说的“好的错误 ”是什么意思呢?如果你给函数dev_queue_xmit() 一个错误构造的套接字缓冲,那么你就会得到一个伴随着内核错误和内核 堆栈的 dump 信息的 “不太好的错误 ”。看看在这里错误如何能被分成两组?最后, watch_in() 返回 NF_STOLEN ,以告诉 Netfilter 忘掉它曾经见到过这个数据包。如果你已经调用了 dev_queue_xmit(),不要返回 NF_DROP !这是因为 dev_queue_xmit()将释放传递进来的套接 字缓冲,而 Netfilter 会尝试对被 NF_DROP 的数据包做同样的操作。好了。对于代码的讨论 已经足够了,请看具体的代码。 莹谐龌蕲賞组靄绉嚴减籩诹。 5.2.1 - 源代码 : nfsniff.c nfsniff/nfsniff.c/* Simple proof-of-concept
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中职大数据应用技术(数据采集技术)试题及答案
- 2025年大学化妆品技术(化妆品研发)试题及答案
- 2025年中职(物联网应用技术)传感器应用综合测试题及答案
- 2025年大学大三(畜牧兽医法规)畜牧兽医行业法规应用阶段测试题及答案
- 2025年大学食品科学与工程(食品添加剂)试题及答案
- 2025年大学环境设计(公共空间设计)试题及答案
- 2025年大学大四(历史学)世界近代史工业革命测试题及答案
- 2025年高职(荒漠化防治技术)植被恢复技术专项测试试题及答案
- 巴洛克纹样介绍
- 运维管理制度
- 苏教版六年级上册科学期末模拟试题
- 中国武术段位制概要(示范提纲)
- 校园传染病预防主题班会PPT
- 激光原理习题解答完整版-周炳琨
- 项目2:复利终值地计算
- 新材料、生物缓冲剂及配套工程B3车间产品优化调整项目环评报告书
- 汽车美容装潢工(四级)职业资格考试题库-上(单选题汇总)
- 戏剧专业常用词汇中英文对照
- 国开生命健康学院《中药炮制》形成性考核一答卷
- 最新部编版四年级语文下册第一单元课件
- 资金时间价值-课件
评论
0/150
提交评论