为Bash增加命令执行日志
我们将修改bash的源码来实现”无敌”logging机制,也将看到”无敌”并不是真正的无敌。
一:bash为何需要logging
Bash堪称*nix世界使用最广泛的shell,其特性之一是历史命令(history)机制。此机制主要用于为用户提供方便--少敲几下键盘,提高工作效率。然而,被广泛讨论的是bash_history可以用作logging机制以此来监控用户的活动。此文将对上述问题进行讨论并解释为啥logging机制在少数人面前会失效。我们将见到各种用于保护history文件的防御措施是如何不费吹灰之力或稍微费点力就被突破的。随着讨论的跟进,突破的限制也将变得更严,但这并不代表突破起来就更困难,与之相反大部分方法都是可以不费脑子的。最后,我们将修改bash的源码来实现”无敌”logging机制,也将看到”无敌”并不是真正的无敌。
二:加固bash_history
假设你所管理的系统提供shell登录功能,你的用户当中有个别及其讨人厌的家伙,于是你想监控他的活动,因为你非常怀疑他半夜三更使用你所负责保护的CPU和系统资源作恶意行为(或是其他的,例如下毛片等)。我们暂且叫他小明(此处原文为Bob,Bob一名在国外经常用来指代坏蛋)。
因为所有用户都是使用bash作为默认shell,你开始着手修改bash的配置文件:
第1步
使bash历史记录文件和相关文件无法被删除或修改。
小明所做的第一件事应该是建立history到/dev/null的链接。
bob$ rm ~/.bash_history
bob$ ln -s /dev/null ~/.bash_history
这可以通过修改历史记录文件为只能被追加来进行阻止,执行以下命令来改变其属性:
# chattr +a /home/bob/.bash_history
这是 使用文件系统附加属性来指定文件只能被追加,大多数文件系统支持此功能(例如ext2/3,XFS,JFS)。在FreeBSD上可以执行:
# sappnd /home/bob/.bash_history
你还应修改shell启动相关的其他文件的这个属性:
# chattr +a /home/bob/.bash_profile
# chattr +a /home/bob/.bash_login
# chattr +a /home/bob/.profile
# chattr +a /home/bob/.bash_logout
# chattr +a /home/bob/.bashrc
前三个文件在交互式bash shell(或非交互式sehll使用–login选项)调用时被读取(在读完全局配置文件/etc/profile后)。.bashrc文件只在当non-login交互式shell调用时被读取。这意味着当小明已登进系统后,用以下方法自己调用一个新shell时:
bob$ bash
此时只有.bashrc 文件被读取,而上面所列的前三个配置文件不会再次被读取了。
做了以上属性的修改后再来做更进一步的”加固”,一个所谓的保护措施。
第2步
配置 .bash*配置文件
所有的配置将针对.bashrc文件,因为其他三个配置文件本身会调用.bashrc,也就是说.bashrc无论如何都会被读取 (不管用户是否刚登录或是登录后手工调用bash shell)。
所以,所有修改都针对.bashrc的好处是可以防止小明登录后手工调用新的bash shell来跳过仅在.bash_profile,.bash_login,.profile三个配置文件中生效的配置选项,另一好处是这三个文件本身都会调用.bashrc,所以在首次登录系统时.bashrc当中的配置也会生效。
# cat >> /home/bob/.bashrc << EOF
> shopt -s histappend
> readonly PROMPT_COMMAND=”history -a”
> EOF
此处histappend选项的作用是让bash附加上最后一行$HISTSIZE给$HISTFILE文件(一般是~/.bash_history文件),不管交互式shell何时退出。默认的,bash每次均会覆盖$HISTFILE以保证只有一个session 被保存以此来节约空间。
环境变量PROMPT_COMMAND会保存一条将被优先执行的命令,意思是说”history -a”命令将在用户执行命令前被优先执行,这将保证不管当前命令前一条是执行的什么,它将立即被追加进$HISTFILE,而不用等待整个会话结束再将历史命令从内存记录至硬盘。
此处的readonly作用是使变量不可修改以防止被小明覆盖掉或是直接屏蔽掉。
最后要完成的步骤是使所有与bash_history相关的环境变量都变为readonly:
readonly HISTFILE
readonly HISTFILESIZE
readonly HISTSIZE
readonly HISTCMD
readonly HISTCONTROL
readonly HISTIGNORE
第3步
禁掉系统中所有其他shell,一般包括csh,tcsh,ksh。
# chmod 750 csh
# chmod 750 tcsh
# chmod 750 ksh
这将阻止小明把bash shell切换成其他shell。
现在,机敏点的管理员会抱怨上面的都是shit!
还有一个shell逃出了我们的掌控!在你看完以上叙述跳入浮想联翩之前,让我们来搞清一些事情。
很久很久以前… (你懂的),原本只有一个Bourne shell 或者叫sh,现如今,/bin/sh实际上是/bin/bash的一个链接。Bash在被调用时检查它是以哪个名字被调用的并以此来判断是不是调用sh,它试图模仿历史版本的sh的行为并和POSIX标准保持一致。
如果以交互式login shell或非交互式shell带上–login选项启动,它才读取/etc/profile和~/.profile来初始化配置。如果以交互式shell被调用,则试图解释$ENV变量,当$ENV非空则使用它的值当作默认配置并执行。我们将在本文的下一节讨论如何利用这点来秒杀bash的所有设置。
三:攻破logging机制
现在是时候站在小明的角度来看下所有问题了。我们将验证上面的防御是如何一步步被攻破的。在实践中的可能性是无穷进的。
以下所提及的突破bash_history logging机制的技巧只是九牛一毛。
- 方法1:使用Bourne shell –/bin/sh逃脱术
$ /bin/sh