当前位置: 首页 > 科技观察

Rootkit隐藏进程及端口检测

时间:2023-03-12 09:07:35 科技观察

1.简介Rootkit是一种特殊的恶意软件。其作用是隐藏安装目标上的自身及指定文件、进程、网络链接等信息。Rootkit更为常见。一般与木马、后门等其他恶意程序结合使用。Rootkit检测也已成为主机安全的重要功能。对于rootkit中最常见的隐藏进程和端口检测,主要有两种检测方法,一种是基于内核内存分析,另一种是基于应用层分析。基于内存分析的Rootkit检测可参考Rootkit检测。该方案的缺点是需要增加内核模块,风险较高,检测效果相对较好。本文介绍第二种方案。Unhide在应用层发现隐藏的进程和端口。该方案风险低,可集成到主机安全代理中。二、应用层隐藏进程检测1、进程隐藏及检测方法进程隐藏有两种方法:替换ps命令,在读取/proc/pid目录时,过滤掉需要隐藏的进程信息,加载内核模块,通过拦截proc文件系统的回调函数,过滤掉需要隐藏的进程信息。检测的核心思想:利用libc系统函数盲测进程pid的生存状态,然后根据ps结果比较差异,确定该pid为隐藏进程。unhide提供了以下19种检测方式,大致可以分为四类:一是通过procfs下的进程目录信息,二是通过系统调用函数,三是结合前两种,四是通过爆炸裂化(不推荐)。tab_test[TST_PROC].func=checkproc;tab_test[TST_CHDIR].func=checkchdir;tab_test[TST_OPENDIR].func=checkopendir;tab_test[TST_READDIR].func=checkreaddir;tab_test[TST_GETPRIO].func=checkgetpriority;tabTP_test[ID]函数=checkgetpgid;tab_test[TST_GETSID].func=checkgetsid;tab_test[TST_GETAFF].func=checksched_getaffinity;tab_test[TST_GETPARM].func=checksched_getparam;tab_test[TST_GETSCHED].func=checksched_getscheduler;tab_test[TST_RR_INT].func=checksched_rr_tab_test[间隔;TST_KILL].func=checkkill;tab_test[TST_NOPROCPS].func=checkallnoprocps;tab_test[TST_BRUTE].func=brute;tab_test[TST_REVERSE].func=checkallreverse;tab_test[TST_QUICKONLY].func=checkallquick;tab_test[INSTFO_SYS_=checksysinfo;tab_test[TST_SYS_INFO2].func=checksysinfo2;tab_test[TST_SYS_INFO3].func=checksysinfo3;从名字可以看出,unhide使用了chdir、opendir、readdir、getpriority、getpgid、getsid、sched_getaffinity、kill、sysinfo等libc函数。接下来,从三个类别中分别选择一种检测方法进行分析。2.procfs检测提取checkreaddir检测分析:遍历/proc目录,如果子文件名是数字,说明是进程pid读取进程状态任务目录(/proc/pid/task),得到各个子线程的个数并通过ps命令查找线程比较是否有差异,如果没有则判断为隐藏进程procdir=opendir("/proc");dirproc=readdir(procdir));taskdir=opendir(task);dir=readdir(taskdir)checkps(procpids,PS_THREAD)这种方法可以检测到对第二种无效。3、syscall检测提取checkgetsid检测分析:读取/proc/sys/kernel/pid_max获取max_pid:遍历从1到max_pid的进程,通过getsid返回值和错误码检测进程的生存状态,使用ps命令再次查找进程是否存在通过getsid确认进程的存活状态,防止进程退出时ps执行时比较差异,不存在隐藏进程ret=getsid(syspids)checkps这样的分类(syspids,PS_PROC|PS_THREAD);ret=getsid(syspids)这两种方法都可以检测到上面两个隐藏进程的方法。4.Compund检测提取checkall快速检测分析:从1到max_pid遍历进程通过kill返回值和错误码检测进程存活状态通过getpriority返回值和错误码检测进程存活状态通过getpgid返回值和错误码检测进程存活状态检测进程通过getsid检测进程存活状态通过返回值和错误码检测进程存活状态通过sched_getaffinity返回值和错误码检测进程存活状态通过sched_getparam返回值和错误码检测进程存活状态通过sched_getscheduler返回值和错误码检测进程存活状态进程存活状态通过chdir和opendir读取进程目录(/proc/pid)。使用ps命令查看进程是否存在。通过kill再次确认进程存活状态,防止进程在ps执行过程中退出。比较差异,只有进程不存在(found=0)或者检测11次(found==11)才认为进程正常,其余判断为隐藏进程ret=kill(syspids,0);ret=getpriority(PRIO_PROCESS,syspids);ret=getpgid(syspids);ret=getsid(syspids);ret=sched_getaffinity(syspids,sizeof(cpu_set_t),&mask);ret=sched_getparam(syspids,¶m);ret=sched_getscheduler(syspids);statstatusproc=stat(目录,&缓冲区);statusdir=chdir(目录);dir_fd=opendir(目录);checkps(syspids,PS_PROC|PS_THREAD)ret=kill(syspids,0);if(found_killbefore==found_killafter){if(!((found_killbefore==0&&found==0)||(found_killbefore==1&&found==11))){printbadpid(syspids);}3.应用层隐藏端口检测核心思想:通过libc系统函数bind,监听盲测端口1.tcp隐藏端口检测从1开始遍历端口到65535创建一个基于tcp协议SOCK_STREAM的socket,通过bind返回值和错误码检测端口的状态。如果被占用,错误码为EADDRINUSE,通过监听确认端口被占用。通过ss或netstat命令过滤tcp协议,查看端口情况对比差异,确认端口为隐藏端口。socketsocket_desc=socket(AF_INET,SOCK_STREAM,0);bind(socket_desc,(structsockaddr*)&address,sizeof(address));listen(socket_desc,1);if(EADDRINUSE==errno){checkoneport(i,tcpcommand,TCP);}2.与tcp相比,udp隐藏端口检测使用SOCK_DGRAMsocket,少了listen这一步。其他检测步骤类似socket_desc=socket(AF_INET,SOCK_DGRAM,0);bind(socket_desc,(structsockaddr*)&address,sizeof(address));if(EADDRINUSE==errno){checkoneport(u,udpcommand,UDP);}4.结论本文通过应用层提供了对rootkit中最常见的隐藏进程和端口的检测,风险较小,可以无缝集成到主机安全代理中