极限首页 业界焦点 软件工程师之路 系统工程师之路 网络工程师之路 软件下载 技术社区
 Linux操作系统的内核编译内
 Linux下设备完全驱动之四
 Linux下设备完全驱动之二
 Linux下设备完全驱动之三
 Linux下设备完全驱动之一
 Linux内核如何从2.4升级到
 开源世界的虚拟机 QEMU
 Linux下软件RAID的实现
 RHEL4内建LVM工具入门
 linux SSH 的一些安全小技
 Linux操作系统的内核编译内
 Linux下设备完全驱动之四
 Linux下设备完全驱动之二
 Linux下设备完全驱动之三
 Linux下设备完全驱动之一
 Linux内核如何从2.4升级到
 开源世界的虚拟机 QEMU
 Linux下软件RAID的实现
 RHEL4内建LVM工具入门
 linux SSH 的一些安全小技

Shell 中文手册

Python 2.3 中文手册

Python 2.4 中文手册

Mysql 4.x 中文手册

PHP 4.x 中文手册

Apache 2.x 中文手册
更多手册

站内搜索:
当前位置:首页>>系统工程师之路>>管理进阶>>正文
Linux系统可卸载内核模块完全指南(中)(2)
时间:2005-09-25 作者:IHH 来源:赛迪

 

这确实是一个非常美妙的关于命令’whoami‘的系统调用列表,不是么?在这里为了控制’whoami‘的输出需要拦截4个系统调用















geteuid()               = 500
            getuid()                = 500
            getgid()                = 100
            getegid()               = 100



可以看看2.6的哪个程序的实现。这种分析程序的方法对于显示其他基本工具的信息也是十分重要的。

我希望现在你能够找到那些能够帮助你隐藏你自己的,或者做系统后门,或者任何你想做的事情的系统调用.的可执行文件也适用)

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

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

因此,可以考虑用一个LKM记录每一个模块的加载,并且拒绝任何一个不是从指定安全安全目录的模块的加载企图。(为了防止简单的溢出。不存在完美的方法...)。记录功能可以通过拦截create_module(...)来很轻易的实现。用同样的方法你也可以检查模块加载的目录。
当然拒绝任何的模块的加载也是有可能的。但是这是一个很坏的方法。因为你确实需要他们。因此我们可以考虑改变模块的加载方式,比如说要一个密码。密码可以在你控制的create-module(...)里面检查。如果密码正确,模块就会被加载,否则,模块被丢弃。

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

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

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





#define MODULE
            #define __KERNEL__
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            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系统调用中检查他.[我知道这很不安全;甚至一个Linuxstarter都可以击败这种机制.但是(再一次的)这并不是这里的重点....].看看我的实现(我从plaguez的一个类似的LKM中直接抢过来了很多现存的代码....)

#define MODULE
            #define __KERNEL__
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            #include
            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'字符串,比如) (T117)




  共2页: 上一页 [1] 2   
推荐】【 】【关闭


关于极限 | 站内地图 | 意见反馈 | 广告服务 | 数据服务 | 联系我们
本站所刊登的文章,技术资料,软件均整理于网络资源或本站原创,转载请务必联系原作者或本站。
Copyright ? 2001-2004 UPLinux.com All Rights Reserved.
本站唯一联系信箱:
京ICP备05010519