china.com
主页
新闻
体育
游戏
文化
教育
健康
财经
科技
旅游
军事
娱乐
商贸
  科技动态 硬件广场 下载基地 网络教室 网络冲浪 科学博览 移动时代 手机上网 桌面壁纸 科技商情  


第三部分 解决方案(给系统管理员)


3.1 LKM检测的理论和想法
我想现在该到帮助我们的系统管理员来保护他们的系统的时候了。在解释一些理论以前,为了使你的系统变的安全,请记住如下的基本原则:

绝对不要安装你没有源代码的LKMs。(当然,这对于普通的可执行文件也适用)

如果你有了源代码,要仔细检查他们(如果你能够的话)。还记得tcpd木马问题吗?大的软件包很复杂,因此很难看懂。但是如果你需要一个安全的系统,你必须分析源代码。

甚至你已经遵守了这些原则,你的系统还是有可能被别人闯入并放置LKM(比如说溢出等等)。

因此,可以考虑用一个LKM记录每一个模块的加载,并且拒绝任何一个不是从指定安全安全目录的模块的加载企图。(为了防止简单的溢出。不存在完美的方法...)。记录功能可以通过拦截create_module(...)来很轻易的实现。用同样的方法你也可以检查模块加载的目录。

当然拒绝任何的模块的加载也是有可能的。但是这是一个很坏的方法。因为你确实需要他们。因此我们可以考虑改变模块的加载方式,比如说要一个密码。密码可以在你控制的create-module(...)里面检查。如果密码正确,模块就会被加载,否则,模块被丢弃。

要注意的是你必须掩藏你的模块并使他不可以被卸栽。因此,让我们来看看一些记录LKM和密码保护的实现的原型。(通过保护的create_module(...)系统调用)。

3.1.1 一个使用的检测器的原形


对于这个简单的例子,没有什么可以说的。只不过是拦截了sys_create_module(...)并且记录下了加载的模块的名字。

#define MODULE

#define __KERNEL__

#include <linux/module.h>

#include <linux/kernel.h>

#include <asm/unistd.h>

#include <sys/syscall.h>

#include <sys/types.h>

#include <asm/fcntl.h>

#include <asm/errno.h>

#include <linux/types.h>

#include <linux/dirent.h>

#include <sys/mman.h>

#include <linux/string.h>

#include <linux/fs.h>

#include <linux/malloc.h>

extern void* sys_call_table[];

int (*orig_create_module)(char*, unsigned long);

int hacked_create_module(char *name, unsigned long size)

{

char *kernel_name;

char hide[]="ourtool";

int ret;

kernel_name = (char*) kmalloc(256, GFP_KERNEL);

memcpy_fromfs(kernel_name, name, 255);

/*这里我们向syslog记录,但是你可以记录到任何你想要的地方*/

printk("<1> SYS_CREATE_MODULE : %s\n", kernel_name);

ret=orig_create_module(name, size);

return ret;

}

int init_module(void)      

/*初始化模块*/

{

orig_create_module=sys_call_table[SYS_create_module];

sys_call_table[SYS_create_module]=hacked_create_module;

return 0;

}

void cleanup_module(void)      

/*卸载模块*/

{

sys_call_table[SYS_create_module]=orig_create_module;                  

}

这就是所有你需要的。当然,你必须加一些代码来隐藏这个模块,这个应该没有问题。在使得这个模块不可以被卸载以后,一个hacker只可以改变记录文件了。但是你也可以把你的记录文件存到一个不可被接触的文件中去(看2.1来获得相关的技巧).当然,你也可以拦截sys_init_module(...)来显示每一个模块。这不过是一个品位问题。

3.1.2 一个密码保护的create_module(...)的例子


这一节我们会讨论如何给一个模块的加载加入密码校验。我们需要两件事情来完成这项任务:

一个检查模块加载的方法(容易)

一个校验的方法(相当的难)

第一点是十分容易实现的。只需要拦截sys_create_module(...),然后检查一些变量,内核就会知道这次加载是否合法了。但是如何进行校验呢?我必须承认我没有花多少时间在这个问题上。因此这个方案并不是太好。但是这是一篇LKM的文章,因此,使用你的头脑去想一些更好的办法。我的方法是,拦截stat(...)系统调用。当你敲任何命令时,系统需要搜索他,stat就会被调用. 因此,在敲命令的同时敲一个密码,LKM会在拦截下的stat系统调用中检查他.[我知道这很不安全;甚至一个Linux starter都可以击败这种机制.但是(再一次的)这并不是这里的重点....].看看我的实现(我从plaguez的一个类似的LKM中直接抢过来了很多现存的代码....)

#define MODULE

#define __KERNEL__

#include <linux/module.h>

#include <linux/kernel.h>

#include <asm/unistd.h>

#include <sys/syscall.h>

#include <sys/types.h>

#include <asm/fcntl.h>

#include <asm/errno.h>

#include <linux/types.h>

#include <linux/dirent.h>

#include <sys/mman.h>

#include <linux/string.h>

#include <linux/fs.h>

#include <linux/malloc.h>

#include <sys/stat.h>

extern void* sys_call_table[];

/*如果lock_mod=1 就是允许加载一个模块*/

int lock_mod=0;

int __NR_myexecve;

/*拦截create_module(...)和stat(...)系统调用*/

int (*orig_create_module)(char*, unsigned long);

int (*orig_stat) (const char *, struct old_stat*);

char *strncpy_fromfs(char *dest, const char *src, int n)

{

char *tmp = src;

int compt = 0;

do {

dest[compt++] = __get_user(tmp++, 1);

}

while ((dest[compt - 1] != '\0') && (compt != n));

return dest;

}

int hacked_stat(const char *filename, struct old_stat *buf)

{

char *name;

int ret;

char *password = "password";

/*yeah,一个很好的密码*/

name  = (char *) kmalloc(255, GFP_KERNEL);

(void) strncpy_fromfs(name, filename, 255);

/*有密码么?*/

if (strstr(name, password)!=NULL)

{

  /*一次仅允许加载一个模块*/

lock_mod=1;

kfree(name);

return 0;

}

else

{

kfree(name);

ret = orig_stat(filename, buf);

}

return ret;

}

int hacked_create_module(char *name, unsigned long size)

{

char *kernel_name;

char hide[]="ourtool";

int ret;

if (lock_mod==1)

{

lock_mod=0;

ret=orig_create_module(name, size);

return ret;

}

else

{

printk("<1>MOD-POL : Permission denied !\n");

return 0;

}

return ret;

}

int init_module(void)

/*初始化模块*/        

{

__NR_myexecve = 200;

while (__NR_myexecve != 0 && sys_call_table[__NR_myexecve] != 0)

__NR_myexecve--;

sys_call_table[__NR_myexecve]=sys_call_table[SYS_execve];                  

orig_stat=sys_call_table[SYS_prev_stat];

sys_call_table[SYS_prev_stat]=hacked_stat;

orig_create_module=sys_call_table[SYS_create_module];

sys_call_table[SYS_create_module]=hacked_create_module;

printk("<1>MOD-POL LOADED...\n");

return 0;

}

void cleanup_module(void)

/*卸载模块*/      

{

sys_call_table[SYS_prev_stat]=orig_stat;                  

sys_call_table[SYS_create_module]=orig_create_module;                  

}

代码本身很清楚.下面将会告诉你如何才能让你的LKM更安全,也许这有一些多疑了 :) :

使用另外一种检验方式(使用你自己的用户空间接口,使用你自己的系统调用;使用用户的ID(而不仅仅是普通的密码);也许你有一个生物监测设备->读一些文档并且在linux下编写自己的设备驱动,然后使用他 :) ...)但是,要记住:哪怕是最安全的硬件保护(软件狗,生物监测系统,一些硬件卡)也常常脆弱的不安全的软件而被击败.你可以使用一种这样的机制来让你的系统变得安全:用一块硬件卡来控制你的整个内核.

另外一种不这么极端的方法可以是写你自己的系统调用来负责校验.(见2.11,那里有一个创建一个你自己的系统调用的例子)

找到一个更好的方法在sys_create_module(...)中进行检查.检查一个变量并不是十分的安全.如果某些人控制了你的系统.他是可以修改内存的(见下一章)

找到一个方法使得一个入侵者没有办法通过你的校验来加载他的LKM

加入隐藏的功能.

...

有很多工作可以做.但是即使有了这些工作,你的系统也不是完全就是安全的.如果某些人控制了你的系统,他是可以发现一些方法来加载他的LKM的(见下一章);甚至他并不需要一个LKM,因为他只是控制了这个系统,并不想隐藏文件或者进程(和其他的LKM提供的美妙的功能).

3.2 防止LKM传染者的方法


内存驻留的扫描程序(实时的)(就像DOS下的TSR病毒扫描;或者WIN9x下的VxD病毒扫描)

文件检查扫描器(检查模块文件里面的特征字串)

第一种方法可以通过拦截sys_create_module实现(或者init_module调用).第二种方法需要一些模块文件的特征字串.因此我们必须检查两个elf文件头或者标志位.当然,其他的一些LKM传染者可能使用一些改进了的方法.(加密,自我更改代码等等).我不会提供一个检查文件的扫描器.因为你只不过需要写一个小的用户空间的程序来读进模块文件,并且检查两种elf文件头('ELF'字符串,比如)

 

  摘自《赛迪网》 pragmatic/THC,(版本1.0)/文

 


科技检索


中华网推荐

  • 1000名医生在线咨询

  • 中国足球队官方网站

  • 鸦片玫瑰(新版)

  • 精选股票天地

  • 闪光的flash教程

  • 中华网汽车世界

  • 为你的爱情出谋划策

  • 网文精选——野百合集

  • 世界文化遗产在中国

  • 历届香港小姐风姿集




  • 网络教室编辑信箱
    版权声明 | 本站检索 | 联系方法 | 刊登广告 | 使用说明 | 关于中华网 | 豁免条款

    版权所有 中华网