荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: hellsolaris (qq), 信区: Security
标  题: LIDS精通与进阶(上)
发信站: 荔园晨风BBS站 (Sat Nov  1 12:52:16 2003), 站内信件

一、系统入侵
  随着Internet上的Linux主机的增加,越来越多的安全漏洞在当前的GNU/Linux系统
上发现。你也许在Internet上听说过在Linux下发现Bug,它会导致系统很容易的被黑客
攻击。
  因为Linux是一个开放源代码的系统,漏洞很容易发现,并且也会很快的有补丁出来
。但是当漏洞没有公布的时候,并且管理员很懒,没有去打补丁。黑客就会很容易的攻
击这个系统,取得root权限,在现有的GNU/Linux下,他就可以做任何他想做的事情。现
在你可以问,我们现在到底可以做些什么呢?
1、现在的GNU/Linux错误在哪里?
  超级用户会滥用职权,他能够做所有他要做的事情。作为root。他会改变所有的东
西。
  许多系统文件很容易被更改。这些文件可能是很重要的文件,如/bin/login,如果
一个黑客进入,他可以上传一个login程序来覆盖/bin/login,这样他就可以不用登陆名
和密码来登陆系统。但是这些文件不需要经常改动,除非你要升级系统。
  模块modules很容易用来中断内核。模块是为了让Linux内核更模块话和更高效而设
计的。但是当模块加入到内核,它就会成为内核的一部分并且能做原始内核能做的工作
。因此,一些不友好的代码可以写成模块来加入到内核里,这些代码就会重定向系统调
用并且作为一个病毒来运行。
  进程是不受保护的,一些进程,如后台的Web服务器,一直都认为是没有严格保护的
程序。因此,他们就会很容易被黑客攻击。
2、LIDS的设想是什么。
  保护重要文件。因为文件很容易被root更改,为什么不严格文件操作呢?因此,LI
DS改变了文件系统在内核里的安全系统调用。如果某个时候一些人访问一个文件,他就
会进入系统调用然后我们就可以检查文件名并且看她们是否被保护。如果它已经被保护
,我们就可以拒绝这个访问者的要求。
  保护重要的进程。这个和上面的保护进程的想法不是一样的。当一个系统里运行一
个进程,它会在/proc 文件系统里有一个用pid作为路径名的入口。所以,如果你用"ps
 -axf"你就可以显示出当前运行的进程。你可以问如果保护这些进程。如果你要杀死一
个进程的话,首先,你键入"ps"来得到进程的PID,然后,你键入"kill 〈pid〉"来杀死
它。但是,如果我不让你看到进程,你怎么来杀死这个进程呢?因此,LIDS是用隐藏进
程来保护它的。 另外一个重要的方法就是不让任何人可以杀死进程,包括root用户。L
IDS能够保护父进程是init(pid=1)的所有进程 。
  封装内核。有时候我们需要要把一些必要的模块加入到内核里来使用,另外,我们
也要拒绝任何人包括root用户向内核插入模块。那么如何来平衡这个矛盾的问题呢?我
们可以只允许在系统启动的时候插入模块,然后我们封装模块,在封装后,内核不允许
任何人插入模块到内核里。通过这种封装功能,我们能用它来保护重要的文件,进程,
我们可以在系统启动的时候只允许必要的进程,只改变必要的文件。在封装内核后,我
们就不能在对文件有任何的修改。
二、保护文件系统
    1、保护文件系统是LIDS的重要功能之一。这个功能是在内核的VFS(虚拟文件系统
)层实现的,我们可以保护任何种类的文件系统,如EXT2,FAT。 在LIDS,保护的文件
按种类分为以下几种:
    只读的文件或目录。只读文件意味着它们不被允许改写,如,在目录/usr/bin,/s
bin。这些类型的文件大多数都是二进制系统程序或是系统配置文件,除了在升级系统的
时候,我们不需要改变它们。
    只可增加文件或目录。这些文件是那些只可以增加大小的文件。大多数是系统的日
值文件,如在/var/log里的只可增加文件。
额外的文件或目录,这些文件没有被保护。一般来说,你想要保护目录下的所有文件,
但是,还需要有一些特殊的文件不要被保护。所以我们可以定义这些文件作为额外的其
他的只读文件。
    保护挂载或卸载文件系统。当你在启动的时候挂载文件系统的时候,你可以禁止所
有人,甚至是root,去卸载文件系统。你也可以禁止任何人在当前文件系统下挂载文件
系统来覆盖它。
    2、LIDS如何在内核保护文件
    在这部分,我们会看到一些内核的代码来理解LIDS是如何保护文件的。
    (1)、Linux文件系统数据结构程序
    首先,我们必须了解Linux的虚拟文件系统。
    在Linux里的每一个文件,不管是什么样子的,都有一个结点inode数,文件系统提
供了以下数据结构。
    在/usr/src/linux/include/linux/fs.h
    struct inode {
            struct list_head     i_hash;
            struct list_head     i_list;
            struct list_head     i_dentry;
            unsigned long       i_ino; ----> inode number.
            unsigned int       i_count;
            kdev_t          i_dev; ----> device number.
            umode_t          i_mode;
            nlink_t          i_nlink;
            uid_t           i_uid;
            ......
        }
    注意:用来鉴定一个结点inode。这个意思是你可以用一对来得到一个系统里独一无
二的inode。
    在/ur/src/linux/cinclude/linux/dcache.h里
    struct dentry {
                int d_count;
                unsigned int d_flags;
                struct inode * d_inode;       /* Where the name be
longs to - NULL is negative */
                struct dentry * d_parent;     /* parent     directo
ry */
                struct dentry * d_mounts;     /* mount information
*/
                struct dentry * d_covers; struct list_head d_hash;
/* lookup hash list */
                struct list_head d_lru;      /* d_count = 0 LRU li
st */
                struct list_head d_child;     /* child of parent li
st */
                struct list_head d_subdirs;    /* our
                ......
       }
    dentry是一个目录文件的入口。通过这个入口,我们可以很容易的在文件的父目录
下移动。
    例如,如果你一文件的inode是(struct inode*)file_inode,如果你可以用file_i
node->d_entry来得到它的目录入口并且用file_inode->d_entry->d_parent来得到父目
录的目录入口。
    (2)、LIDS保护数据结构
    在分析完linux文件系统后,让我们来看看LIDS是如何容VFS来保护文件和目录的。

    在/usr/src/linux/fs/lids.c
    struct secure_ino {
                    unsigned long int ino;     /* the inode number
*/
                    kdev_t dev;           /* the dev number /*

                    int type;            /* the file type */
                    };
    上面的结构用一对来存储保护文件或目录的结点。"type"是用来标明保护结点文件
类型的。
    LIDS有4种类型:
    在/usr/src/linux/include/linux/fs.h
    #define LIDS_APPEND    1    /* APPEND ONLY FILE */
    #define LIDS_READONLY   2    /* Read Only File */
    #define LIDS_DEVICE    3    /* Protect MBR Writing to     device
 */
    #define LIDS_IGNORE    4    /* Ignore the protection */
    通过secure_ino结构,我们能很容易的初使化保护的文件或是在内核里执行以下函
数。
    在/usr/src/linux/fs/lids.c
    int lids_add_inode(unsigned long int inode ,kdev_t dev , int type)
{
     if ( last_secure == (LIDS_MAX_INODE-1))
     return 0;
     secure[last_secure].ino = inode;
     secure[last_secure].dev = dev;
     secure[last_secure].type = type;
     secure[++last_secure].ino = 0;
    #ifdef VFS_SECURITY_DEBUG
     printk("lids_add_inode : return %dn",last_secure);
#endif
     return last_secure;
    }
    就象你在上面代码上可以看到的,给secure_ino加到一个结点上是非常容易的。被
保护的结点会在系统启动的时候初使化。初使化程序在/usr/src/linux/fs/lids.c的in
it_vfs_security()里。
    现在,让我们看看LIDS是如何来检查是否一个结点已经受到保护。
    在/usr/src/linux/fs/open.c
    int do_truncate(struct dentry *dentry, unsigned long length)
    {
     struct inode *inode = dentry->d_inode;
     int error;
     struct iattr newattrs;
     /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it
 is. */
     if ((off_t) length < 0)
     return -EINVAL;
    #ifdef CONFIG_LIDS
     if (lids_load && lids_local_load) {
     error =
     lids_check_base(dentry,LIDS_READONLY);
     if (error) {
              lids_security_alert("Try to truncate a protected
 file (dev %d %d,inode %ld)",
              MAJOR(dentry->d_inode->i_dev),
              MINOR(dentry->d_inode->i_dev),
              dentry->d_inode->i_ino);
    .....................
    这个是LIDS加到内核里做检测的一个例子。你会看到lids_check_base()是LIDS保护
方法的一个核心函数。
    你可以在LIDS要保护的地方看到很多LIDS保护方法用到lids_check_base()函数,特
别是在linux内核的子目录下。
    在/usr/src/linux/fs/lids.c
    int lids_check_base(struct dentry *base, int flag)
    {
        ..................
        inode = base->d_inode;     /* get the inode number */
        parent = base->d_parent; /* get the parent diretory */
        .................
        ---->  do {
                 if ( inode == parent->d_inode)
                 break;
                 if ((retval = lids_search_inode(inode))) {
                   if ( retval == LIDS_IGNORE || (retval == LIDS_
DEVICE && flag != LIDS_DEVICE)) break;
                   if ( flag == LIDS_READONLY || ( flag == LIDS_A
PPEND && retval >flag ) || ( flag == LIDS_DEVICE && flag == retval )) {
                         return -EROFS;
                      } break; }
                      inode = parent->d_inode;
                  } while( ((parent = parent->d_parent ) !
= NULL) );
            return 0;
     }
    lids_check_base()会检查一个给定文件的dentry和它的父目录是否被保护。
    注意:如果它的父目录被保护,它下面的文件也会被保护。
    例如,如果"/etc/"被保护,"/etc/passwd"也一样被保护。
    (3)、在内核保护系统调用
    为了保护系统,LIDS会在一些检查临界的系统调用的时候做检查。因此,我们可以
保护系统调用和限制文件系统的用户调用。
    这些是一些例子:
    open(),open是通过禁止一些权利来保护文件的打开。你可以在打开调用open_nam
ei()调用的时候LIDS在检测它。
    mknod(),mknod是用来在指定目录下保护mknod。
    unlink(),在内核代码检查do_unlink()。
三、保护设备
    Linux的设备会在/dev/目录下以文件的形式列出,我们可以用上面保护文件的方法
来保护设备。但是在一些情况下,用户也可以用IO操作来旁路文件系统来读写设备,我
们必须注意这个问题。
    1、设备,内核I/O
    在GNU/Linux系统下的设备会以文件的形式表达,所以我们可以用保护文件系统那样
来保护设备。
    用户的I/O访问是通过系统调用sys_operm和sys_iopl来实现的。你可以看看/usr/s
rc/linux/arch/i386/kernel/ioport.。这个是要基于系统结构的,要是到其他平台,就
需要注意它们的变化。
    2、如何用LIDS来保护
    大多数情况下,程序不需要通过在/dev的设备文件名称来访问设备。但是,一些特
殊的程序需要直接访问,如X Server,这个会写到/dev/mem和甚至是I/O设备。我们需要
一些额外的东西来保护设备。LIDS会在配置内核的时候来定义这个功能。
    CONFIG_LIDS_ALLOW_DEV_MEM,如果你选择了开启这个功能,你就可以允许一些特殊
程序来访问/dev/men和/dev/kmen这些内核临界的设备。如果你想要用内核的X Server,
选择这个功能就会在配置内核的时候提供整个路径和文件名。
CONFIG_LIDS_ALLOW_RAW_DISKS,如果选择这个开启,你就可以允许一些特殊的程序来访
问物理磁盘。
    CONFIG_LIDS_ALLOW_IO_PORTS,如果你选择了开启这个功能,你就可以允许一些特
殊的程序来访I/O端口。
    当系统运行fs/lids.c里的init_vfs_security()的时候初使化就被调用。
    #ifdef CONFIG_LIDS_ALLOW_DEV_MEM
    lids_fill_table    (allow_dev_mem,&last_dev_mem,LIDS_MAX_ALLOWED,CONFIG_
LIDS_DEV_MEM_PROGS);
    #endif
    #ifdef CONFIG_LIDS_ALLOW_RAW_DISKS
    lids_fill_table(allow_raw_disks,&last_raw_disks,LIDS_MAX_ALLOWED,CONFIG_
LIDS_RAW_DISKS_PROGS);
    #endif
    #ifdef CONFIG_LIDS_ALLOW_IO_PORTS
    lids_fill_table    (allow_io_ports,&last_io_ports,LIDS_MAX_ALLOWED,CONFI
G_LIDS_IO_PORTS_PROGS);
    #endif
    如果一个进程或是程序要直接访问ip端口或是磁盘设备,LIDS就会检查它在数组al
low_raw_disk,last_io_ports,等)。这个检查是通过调用lids_check_base()里的lids
_search_inode(inode)来实现的。
    比如,让我们看看CONFIG_LIDS_ALLOW_DEV_MEM
    /* in lids_search_inode() */
    #ifdef CONFIG_LIDS_ALLOW_DEV_MEM
    for( i = 0 ; i < last_dev_mem ;i++ ) {
                if ( allow_dev_mem[i].ino == ino && allow_dev_mem[i].dev ==
dev) {
                    return LIDS_READONLY;
                }
        }
    #endif
    #ifdef CONFIG_LIDS_ALLOW_RAW_DISKS
    在allow_dev_mem包括了哪一个程序结点在系统启动的时候在init_vfs_security()
里初使化。用同样的方法,除了一些特殊程序,我们可以保护设备,I/O访问等等。



--
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.44.223]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店