科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道Unix下的文件系统安全

Unix下的文件系统安全

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在商业的工作环境中文件的系统安全是至关重要的,在信息战中,商业间谍可以利用OS的漏洞拿到机密文件进行倒卖获取暴利,我利用一点点的可怜的OS知识,说下UNIX下的文件系统安全希望对大家有点帮助。

作者:Webmaster 来源:linuxdby.com 2008年4月14日

关键字: 系统安全 unix

  • 评论
  • 分享微博
  • 分享邮件

  在商业的工作环境中文件的系统安全是至关重要的,在信息战中,商业间谍可以利用OS的漏洞拿到机密文件进行倒卖获取暴利,我利用一点点的可怜的OS知识,说下UNIX下的文件系统安全希望对大家有点帮助,也希望高手指导,转载请保存文章信息

  目录:

  数据泄露

  未经授权的数据修改/删除

  资源消耗

  具有可预测名的临时文件

  任意用户可读写的命名管道

  文件竞争

  1. 数据泄露: 一般有以下几个危险> 配置数据的泄露,敏感应用程序的信息泄露,数据库架构与连接详悉信息的泄露,未授权的访问与网络窃听。用户和程序在/tmp建文件,如果用户没有指定的用户权限,一般也就应用了默认中umask,值为022,这时这个文件被赋予了所有人都可读的许可权。在一个多用户系统中,很容易在/tmp中找到一些包含数据库的口令,机密的商业数据,敏感的登入信息和包含加密口令的内核文件等脚本的副本。目录与共享区域同样有类似的问题也很容易渗透。

  如果是把tmpdir环境变量设置为私人的,单用户临时目录。保证在系统脚本启动时系统范围内umask是027,可以在(~user/.profile文件)中指定umask 值。再增加cron作业,检查启动脚本中不合适的umask设置。在看下服务器上的/tmp和其他的目录,对/tmp执行spot检查。更好的就是用一个软件(tmpwatch)来监视/tmp目录下的可预测文件名。调用 umask(2) 来强制把文件设置为受限的值,只需要调用库函数 mkstemp(3),就可以打开文件。要注意的是, mkstemp(3) 不直接支持 TMP 或 TMPDIR 环境变量

  2. 未经授权的数据修改/删除:这种风险分2种(1)由于用户的疏忽,把文件的的写权限对所有用户开放(2)目录的写权限对所有用户开放。如果在一个写权限对所有用户都开放的目录中创建了一个文件,那么任意用户都可以修改。删除该文件。在通过NFS共享的文件系统中在存在这样的问题,这种情况中的唯一例外是目录设置有粘代(sticky)位。如果文件的许可权限是被锁住的,那只有文件的拥有者可以对文件进行操作。这种情况一般不明显,因为可写的目录可能是当前目录的父目录,也可能是父目录的父目录的父目录。一个很极端的可能就是,如果根目录(/)是任何人可写的,这样攻击者就可以替换文件系统中的任何文件。任何直接属于根目录(/)下的目录都会发生这样的情况

  只要是禁用系统内核中通过ulimit命令创建文件的方式(不要同内核的crash dumps命令弄混)。目前的UNIX系统内核在set-uid程序出现问题时会拒绝转储内核,这是因为有可能回泄露敏感信息。但是,特权守护程序中和应用程序进程也会转储内核,从而把大量的敏感信息写入所有用户可读的内核文件。想验证是不是有这样的漏洞可以同过发一个QUIT信号来检查无法工作的网络服务,查看是否在当前的工作目录中转储存了内核(/proc或者lsof)

  PS:AIX set-uid set-gid 中的安全漏洞[来自绿盟]

  setuid root 程序:

  /usr/bin/setsenv *

  [ x=$s ]

  /usr/lib/lpd/digest *

  [ $s x ]

  /usr/sbin/portmir *

  [ -t $s -d x ]

  /usr/bin/enq

  [ -M $s ]

  /usr/bin/setclock

  [ $s ]

  /usr/lib/lpd/pio/etc/pioout

  [ PIO=$s ]

  setgid printq 程序:

  /usr/lib/lpd/piobe *

  [ PIOSTATUSFILE=x PIO=$s ]

  /usr/lib/lpd/pio/etc/piomkapqd *

  [ -p $s ]

  /usr/bin/splp

  [ $s ]

  后面标*号的程序表明已经被证实确实可以被用来攻击的程序。

  在内核配置文件中设置chown_restricted变量为真来预防文件权限的移交,但是许多的UNIX版本不允许文件giveaways。也可以考虑通过getfacl与setfacl命令(也就是sloaris)使用扩展ACL(在被支持的部分),这样可以扩展在inode中存放的访问信息 [ 有关set-uid程序中的编程错误,是UNIX一个重要的安全威胁 ]

  3. 资源消耗:每个文件系统都有固定的文件节点。不论系统是不是还有剩余空间,当所有的节点被分配时,系统就无法创建任何新文件,有写系统中不可写涉及到/tmp文件时,就会使整个系统崩溃。除非在系统内核中已经把文件giveaways(非ROOT用户修改文件所有权的能力)设置为无效,否则恶意用户为了嫁祸于其他用户而通过运行chown命令把自己创建的文件修改成被攻击用户的所有权,占用系统中的所有的剩余空间。这个问题就好解决了关闭一些起不常用却存在安全隐患的应用、对一些保存有用户信息及其口令的关键文件(如/.rhost、etc/host、passwd、shadow、group)等,再就是把系统升级

  4. 具有可预测文件名的临时文件:如果一个程序在other用户具有写权限的目录中(一般是/tmp)创建的是可以预测名字的文件,那么该程序就可以利用来改写或者删除文件。其他用户可以提前猜测文件的名字并创建一个到系统文件的符号连接。当该程序运行时,就会向系统文件中写入数据,造成系统崩溃。如果这是一个用户口令文件,用户就会遭到拒绝服务攻击。不要信任可以被黑客设置的文件名。Linux 和 Unix 允许用任意的字符序列来作为文件名,所以,如果正在使用一个来自攻击者的目录或者接受他的一个文件名,一定要有所准备。黑客可以创建以"-"开头的文件名,或者含有"&"等特殊字符的文件名。

  检查下自己的shell脚本,把所有公共可写的目录引用更改成自己的/tmp目录。在创建文件时不要依据时间,日期或者进程ID,或者一个功能很小的伪随机数产生器起名。还有要注意的就是umask 命令是一个内置的shell 命令,可以从shell 提示符下直接运行( umask 027 )

  5. 任意用户可读写的命名管道:一般意思上分2种:只能用于父子进程之间的通讯为无名通道.用于任何进程之间的通讯,也就是2个进程间通过文件系统进行通信的一种方式就是使用命名管道.大家都知道无名管道在系统内部是以inode节点的方式来存放的,对于外部用户来说是不可见,所以不能创建新的文件句柄来访问。命名管道就相反,她是真实的存在一个文件,有权限的对文件进行读写,很方便的对实现2个进程间的通讯。但是,如果命名管道创建时把权限设置的很弱,攻击者就可以读写该命名管道,从而破坏/毁坏管道另一边的进程或者读取特权数据。

  如果我们确保文件许可权限中的包含对命名管道的检查(这些对IPC也是很有用的,因为宽松是许可权限使得攻击者以黑客方式同进程进行交互)如果可以只使用一个管道,把数据从一个位置发送到另一个位置,那么就可以简化程序,并排除潜在的安全问题。如果确实需要创建一个临时文件,那么可以考虑把临时文件存储到其他地方。如果不是在编写一个有特权的程序,那么这点尤其需要考虑;如果程序没有特权,那么把临时文件放置在用户目录内部会更安全一些(处理 root 用户时要当心,它以"/"作为其主目录)。这样,即使您没有"正确地"创建临时文件,攻击者通常也无法引发问题(因为攻击者不能利用用户主目录的内容)。

  6. 竞争状态: .为了更好的理解什么的文件竞争状态在这里我先引用David A. Wheeler <安全编程:避免竞争条件>中的释例:

  清单 1. 普通的 C 声明

  b = b + 1;

  看起来非常简单,不是吗?但是,让我们假定有两个线程在运行这一行代码,在这里,"b"是一个由两个线程共享的变量,"b"的初始值为"5"。以下是一个似是而非的执行次序:

  清单 2. 使用共享的"b"的可能执行次序

  (thread1) load b into some register in thread 1.

  (thread2) load b into some register in thread 2.

  (thread1) add 1 to thread 1's register, computing 6.

  (thread2) add 1 to thread 2's register, computing 6.

  (thread1) store the register value (6) to b.

  (thread2) store the register value (6) to b.

  初始值为 5,然后两个线程分别加 1,但是最终的结果是 6... 而不是应该得到的 7。问题在于,两个线程互相干扰,从而导致产生错误的最终答案。

  早期的计算机只允许单线程进行一个程序,什么都不能中断,也不能与之进行竞争.到了现在,计算机需要同时运行大量的进程和线程,经常还会有多个处理器确实在同时运行不同的程序。这样做是加大了使用的灵活性,但是同时也附载了一个危险:如果这些进程和线程共享了所有的资源,实际上也就可以互相影响.如果一个程序存在竞争的状态,黑客就可以在检查阶段以及后来使用对象的阶段交换对象。这样就会欺骗程序对错误的对象进行操作.

  有很多朋友对文件竞争不是很清楚,我再简单的说下:文件竞争状态所产生的第一个安全漏洞就的缓冲区益出.相对的对于buffer overflow,大家都知道用户名的名字字符是存在缓冲区中,如果我们知道用户名只能容纳8个字符的情况下,通过提示符输入10个字符来测试益出,输入的名字的后2个字符就改写了下一快的缓冲区.有时候也由于本身C语言的缺陷与脆弱性造成的益出,由于竞争状态的关系,C会有2个方面的竞争状态:排序与保护,现在举例代码:

  increase_privs():

  ...

  value = special_app_function();/* requires privileges */

  other_unreleted_function();/* does not require privileges */

  other_unreleated_function2();/ * requires privileges */

  special_dependent_function(value);/* requires privileges */

  ...

  exit();

  这个代码就存在着竞争状态,如果想避免这样的竞争状态的出现,就必须很好的组织好函数:

  increase_privs();

  ...

  value = special_app_function;/* requires privileges */

  if (!validate_function(value)/* assure the safety of the value */

  {

  do_errpr_processing(value);/* do something intelligent with the error */

  }

  special_dependent_function(value);/* requires privileges */

  decrease_privs();/* no longer need privileges */

  ...

  other_unreleted_function();/* does not require privileges */

  other_unreleated_function2();/* ditto */

  有时候在下载一个软件工具,会以不安全的方式在/tmp 创建一个文件,或者多个符号连接的文件,如果没有对文件进行加锁操作,就直接写入,就会存在攻击,可以用户进程权限破坏系统文件,造成拒绝服务,或者就直接截断符号连接所指向的文件。黑客就可以借文件竞争来截断、毁坏、或是覆盖敏感文件。有时候是系统本身存在文件竞争,从而导致内核问题,系统不稳定甚至崩溃。也有时候是由于代码系统调用产生的文件竞争漏洞,如果对目标文件写入代码,理论上可以进行权限提升

  文件竞争状态大概有以下3种:

  1. 不可信进程导致的阻碍。也就是"次序"或"非原子"状态。这种情况是由于运行其它不同程序的进程在安全程序的步骤之间"失脚滑入"了其它操作引起的。这些其它程序可能是黑客特别执行来造成问题的。

  2. 可信进程(从安全程序的角度)导致的阻碍。也就是死锁、活锁或者锁定失效状态。这种情况是由于运行"相同"程序的进程引起的。由于这些不同的进程可能具有"相同"的优先级,如果没有适当地加以控制,可能会以其它程序无法做到的方式互相干扰。有时这种阻碍会被利用。

  3.UNIX下编程中出现的"检查时间/使用时间"(TOCTOU)竞争状态。

  现在我对以上3个文件竞争系统状态的问题求出以下几点解决方案

  (1; 不可信进程 ) : 限制程序暴露的部分_/限制暴露部分所允许的输入类型_/检查所有不可信的输入( 这里涉及许多UNIX安全编程的问题,程序设计与"setuid"或者"setgid"的程序问题,也就不讲了,但是请看官明白,一个安全的程序是没有不可信的进程,任何来自网络上的输入都是不安全的,我建议对不可信的输入来源进行严格的审查。安全的程序必须检查每一个不可信的输入通道,这样做可以避免很多问题。但是那也还不够。有时,即使只是读入数据也可以是安全漏洞 —— 甚至在数据被检查之前!处理数据可以导致程序以可怕的方式失败。

  特别是网络数据来自于网络时,它是高度不可信的。所谓的 "源 IP"地址、HTTP"Referrer"头的值或者类似的数据所告诉显示的地址,那些来自发送者的值可以被伪造。当心来自域名系统(DNS)的值;DNS 实现的是一个分布式数据库,那些值中有一些可能是黑客提供的。

  (2:可信进程 ): 一般在网络上介绍的解决文件竞争的典型解决方案: 是确保程序在使用某个资源(比如文件、设备、对象或者变量)时,拥有自己的专有权( 也就是死锁,活锁 ),比方,如果进程1锁定了资源A并等待资源B,而进程2锁定了资源B并等待资源A,死锁就发生了。简单地要求所有进程按相同顺序锁定资源就可以防止许多死锁(例如必须按字母顺序锁定资源)要补充一点的是有生活在一个进程内部,线称也很可能需要一个锁来保证.

  有时,可以一次执行一个单独操作来完成一些特殊的操作,从而使您不需要显式地对某个资源进行加锁而后再解锁。(b 锁这个问题太复杂了,以我现在可怜的UNIX知识目前还不能正确的理解,这里只是简单说下,有兴趣的可以去看下UNIX下的安全编程或者相关资料 b) 当然也可以使用 POSIX 记录锁,它通过 fcntl(2) 实现为一个任意的锁,来代替锁文件。或者当所有程序都共同合作的时候,使用单独的文件或者 fcntl(2) 任意锁。至于至于牛B的强制锁这里就不讲了,免的倒胃口.更和况,在一个系统里使用很多是锁是不明智的,想象以下以后的维护锁的工作,又无聊又累人........

  (3.:TOCTOU 竞争状态 ): 安全程序必须确定是否同意某个请求,如果是的话,对请求作出反应。一个不可信用户应该无法在程序反应之前改变此决定中用到的任何信息。这个问题在文件系统中经常出现。程序一般应该避免使用access(2)来确定是否同意某个请求,并随后使用open(2),因为用户可以在这两个调用之间移动文件,可能建立他们自己用来替代的符号连接或文件。安全程序应该设置自己的有效ID或文件系统ID,然后直接进行open调用.

  遵守一些简单的规则,可以避免这些问题:

  程序一般应该避免使用access(2)来确定是否同意某个请求,并随后使用open(2)。用户如果access(2)与open(2)之间调用移动文件,可能建立他们自己用来替代的符号连接或文件。所以用access(2)来判定是否可以做某件事情是很危险的,最好设置有效 id、文件系统 id 或者有效 gid,并通过 setgroups 来清除所有不需要的组;然后调用 open(2) 直接打开或创建您需要的文件

  当创建一个新文件时,最好设置权限位与操作标记.使用 O_CREAT | O_EXCL 模式打开它(确保只有在创建一个新文件时调用 O_EXCL 才会成功)。也就是说限定在创建者只能通过使用S_irwxu来读写与执行改文件.通常,也不要去尝试在创建完文件后再去减少权限,这危险的办法/

  当对文件的元信息进行操作时(比如修改它的所有者、对文件进行统计,或者修改它的权限位),首先要打开该文件,然后对打开的文件进行操作。只要有可能,应尽量避免使用获取文件名的操作,而是使用获取文件描述符的操作。这意味着要使用 fchown( )、 fstat( ) 或 fchmod( ) 系统调用,而不使用取得文件名的函数,比如 chown() 、 chgrp() 和 chmod()。这样做把避免文件在您的程序运行时被替换(一种可能的竞争条件)。例如,如果您关闭一个文件,然后使用 chmod() 来修改其权限,那么黑客很可能在这两个步骤之间移动或删除该文件,并创建指向另一个文件(比如 /etc/passwd)的符号链接。

  PS:竞争状态一般涉及一个或多个进程访问某个共享资源(如某个文件或变量),而这一多重访问没有被适当地控制。

  一般来说,进程不是以原子方式运行的,另一个进程甚至可以在任意两条指令之间中断它。如果一个安全程序的进程对这样的中断没有准备,其它进程就能够干扰安全程序的进程。如果其它进程的任意代码在安全程序进程的任意一对操作之间被执行,操作都不应该失败.

  上面说到了set-uid程序,因为C语言编程并不能编写安全的编程,只要在set-uid root程序中出一漏洞,黑客就可以利用他获取系统的root访问权限。但是这个问题在TOS系统中,比如trustedBSD与AIX TCSEC中就不存在,因为在TOS为用户提供了一个细粒度的控制访问机制。用来区分保护秘密数据。在TOS中可以认为的限定ROOT的权限。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章