敏感文件监控
入侵检测很多,总结起来就是两大部分:流量,文件。
针对敏感文件进行监控:是否被篡改,是否新增内容,是否被删除... 进而发送通知,系统管理员可以及时关注到系统的运行情况。
一、敏感文件的监控原理
判断一个文件是否被篡改:可以使用 md5sum 命令记录文件的md5的数字指纹。md5是一种摘要算法,是不可逆的加密,只用于表示某个文件是否被篡改,或者用于保存密码。
在安全状态下,针对敏感文件生成基线的摘要数据(保存起来,下一次,再根据当前最新的文件状态生成一次,两次进行对比,可以知道是否被篡改)(潜在的风险:基线数据也被改了。解决方案:离线保存)
另外,针对文本型文件,还可以继续深入,去比较那些内容被篡改了。
二、先进行基线操作
进行备份 cd /opt mkdir -p baselearn/files cd baselearn/ cp ../learn/* ./files/ 将 /opt/learn 中的文件备份在 /opt/baselearn/files/ 里面,一旦 /opt/learn 中的文件被篡改了,通过和 /opt/baselearn/files/ 中的文件进行md5sum 和 diff 的对比,就知道了到底是哪里出了问题 md5sum /opt/learn* #md5无法针对文件夹进行摘要,所以,如果learn目录下有文件夹则此命令无法成功执行 那我们该如何解决这个问题呢?即如何直接对全部的文件进行md5加密计算? 我们应该尝试先找到所有的文件,这样执行md5就容易多了 find /opt/learn -type f | xargs md5sum #这是比较标准的用法,找到/opt/learn这个目录下的所有文件并计算其md5摘要值 find /opt/learn -type f | xargs md5sum > /opt/baselearn/learn.md5.base #将上面计算好的基线数据保存起来 #利用 md5sum -c learn.md5.base 来检查文件是否被篡改 md5sum -c learn.md5.base 说白了 -c 参数是用来重新检查文件的md5值的,比如我将一个目录下的所有文件的md5值全部重定向到了一个文件中(例如 learn.md5.base),然后我使用 md5sum -c learn.md5.base 就可以重新检查之前检查过的目录然后和这个文件中的md5值进行对比
当然上面这个图不是上面的文件,只是演示一下结果
其次,我们还可以使用 --quiet 参数来直接输出重新计算错误的文件
md5sum -c --quiet learn.md5.base #当然,这种方式完全可以使用grep来代替 #然后将对比失败的文件信息保存到 learn.diff md5sum -c --quiet learn.md5.base > learn.diff
三、比较文件内容的具体修改部分
在这里使用的是 diff
diff /opt/learn/date.txt /opt/baselearn/files/date.txt 2d1 < 2021-08-18 15:44:06 diff /opt/baselearn/files/date.txt /opt/learn/date.txt 1a2 > 2021-08-18 15:44:06 比较两个文件内容的不同之处:d 代表删除,a 代表新增, c 代表修改 2d1 :左边的文件的第二行相对于右边的文件第一行删除了一行
那么如何检测目录下有新增的文件,在这里就拿 /opt/learn/ 目录中的文件 和 /opt/baselearn/files/ 中的文件进对比(因为原本/opt/baselearn/files/ 中的文件就是/opt/learn/ 中文件的备份 )
diff /opt/learn/ /opt/baselearn/files/ | grep ^diff | awk '{print $2}' #最终结果就是被修改的文件 diff /opt/learn/ /opt/baselearn/files/ | grep ^Only #列出文件新增或删除的信息 基于上述信息,通过sed替换得到完整的文件名 diff /opt/learn/ /opt/baselearn/files/ | grep ^Only | sed -e 's/Only in //g' -e 's/://g' 例如: [root@mycentos learn]# md5sum -c learn.md5.base /opt/learn/moniter.sh: 确定 /opt/learn/site_check.log: 确定 /opt/learn/site_check.sh: 确定 /opt/learn/test.txt: 确定 [root@mycentos learn]# md5sum -c learn.md5.base | sed 's/: 确定//g' /opt/learn/moniter.sh /opt/learn/site_check.log /opt/learn/site_check.sh /opt/learn/test.txt
target=$1 #这是原来的目录 base=$2 #这是备份出来的目录 action=$3 if [ $action = "new" ]; then mkdir $base/files #创建备份的目标位置 cp $target/* $base/files/ #执行备份 find $target -type f | xargs md5sum > $base/learn.md5 #将备份前目录下的所有文件生成md5摘 要值并输出重定向到 /opt/baselearn/learn.md5 中 fi echo > $base/result.log md5sum -c --quiet $base/learn.md5 1> $base/learn.diff 2> /dev/null #重新计算 /opt/baselearn/learn.md5 这个文件中不同文件的md5值并进行比较,将对比结果不一样的文件输出重定向,1> 重定向我们想要的内容,2> 将类似于 “md5sum: /opt/learn/moniter.sh: 没有那个文件或目录md5sum: 警告:1 个列出的文件无法读取”这种的信息丢掉 remove=$(cat $base/learn.diff | grep "打开或读取失败" | sed 's/打开或读取失败//g') #意思就是查询之后删除一点内容,使输出更简洁 英文版的就将 打开或读取失败 换为 FAILED open or read if [ $? -eq 0 ]; then echo "$target folder was removed some files: $remove" | tee -a $base/result.log fi change=$(cat $base/learn.diff | grep "失败$") if [ $? -eq 0 ]; then echo "$target folder was changed some files: $change" | tee -a $base/result.log diff $target/ $base/files/ fi #英文版的就将 失败 换为 FAILED list=$(diff $target/ $base/files/ | grep ^只在 | sed -e 's/只在 //g' -e 's/ 存在://g') #英文版的就是Only 和 : if [ $? -eq 0 ]; then echo "两个目录中有文件的数量的变化:$list" | tee -a $base/result.log fi mail -s "关键文件监控警报" 2811403517@qq.com < $base/result.log
比较文件的具体修改内容
[root@mycentos opt]# diff /opt/learn/date.txt /opt/baselearn/files/date.txt 2d1 < 2023-10-16 19:15:34 [root@mycentos opt]# diff /opt/baselearn/files/date.txt /opt/learn/date.txt 1a2 > 2023-10-16 19:15:34 比较两个文件内容的不同之处: d 代表 删除,a 代表 新增,c 代表 修改 #如何检测被检测目录下有新的文件 diff /opt/learn /opt/baselearn/files/ diff /opt/learn/ /opt/baselearn/files/ | grep ^diff | awk '{print $2}' diff /opt/learn/ /opt/baselearn/files/ | grep ^Only #列出文件新增或删除的信息 #基于上述信息,通过sed替换得到完整的文件名 diff /opt/learn/ /opt/baselearn/files/ | grep ^Only | sed -e 's/Only in //g' -e 's/://g
优化
1.完成上述敏感文件检测的脚本
2.确保已知的4个bug被修复:
-
参数没有检查
-
没有判断文件被修改的内容
这个问题可以用 diff 的结果来解决,搭配 grep awk 等指令
-
路径名里少了 / 符
-
不管如何哪怕 $remove 和 $change 是空的,if 条件判断也依然是对的
3.防火墙应急安全
-
如果发现有用户远程登录,并且失败多次,则直接封锁IP,并且强制断开对方可能的SSH连接
target=$1 #这是原来的目录 base=$2 #这是备份出来的目录 action=$3 if [ $action = "new" ]; then mkdir $base/files #创建备份的目标位置 cp $target/* $base/files/ #执行备份 find $target -type f | xargs md5sum > $base/learn.md5 fi echo > $base/result.log #正事开始之前,先清空日志文件 md5sum -c --quiet $base/learn.md5 1> $base/learn.diff 2> /dev/null remove=$(cat $base/learn.diff | grep "打开或读取失败" | sed 's/:打开或读取失败//g') if [ $? -eq 0 ]; then echo "$target folder was removed some files: $remove" | tee -a $base/result.log fi change=$(cat $base/learn.diff | grep "失败$" | sed -e 's/失败//g' -e 's/: 打开或读取失败//g') if [ $? -eq 0 ]; then echo "$target folder was changed some files: $change" | tee -a $base/result.log diff $target/ $base/files/ #这个输出的就是两个文件不同的内容 fi list=$(diff $target/ $base/files/ | grep ^只在 | sed -e 's/只在 //g' -e 's/ 存在://g' | sed 's/\g') if [ $? -eq 0 ]; then echo "两个目录中有文件的数量的变化:$list" | tee -a $base/result.log fi mail -s "关键文件监控警报" 2811403517@qq.com < $base/result.log
问题一:
输出错误信息,但错误结果为空
从这里我们可以看到,就算我们
/opt/baselearn/learn.diff 文件中没有任何关于 FAILED open or read 的信息
但是我们依然使用了 sed 而且该命令使用完了之后 $? 的结果还是 0
我们将其赋值给 remove 的命令的 $? 的结果是 0 说明我们将一个空赋值给了 remove
这样使得 if [ $? -eq 0 ] 判断条件虽然成立,但是 remove 这个变量却是空的
所以就导致了,即使没有remove这个错,但依然输出了这句话 $target folder was removed some files
就像这样,明明是空,但却依然输出了前面的话,该如何解决呢?
将 if [ $? -eq 0 ]; then echo "$target folder was removed some files: $remove" | tee -a $base/result.log fi 改为 if [ ${#remove} -gt 0 ]; then echo "$target folder was removed some files: $remove" | tee -a $base/result.log fi
同理可得:
将 if [ $? -eq 0 ]; then echo "$target folder was changed some files: $change" | tee -a $base/result.log diff $target/ $base/files/ #这个输出的就是两个文件不同的内容 fi 改为 if [ ${#change} -gt 0 ]; then echo "$target folder was changed some files: $change" | tee -a $base/result.log diff $target/ $base/files/ #这个输出的就是两个文件不同的内容 fi 将 if [ $? -eq 0 ]; then echo "两个目录中有文件的数量的变化:$list" | tee -a $base/result.log fi 改为 if [ ${#list} -gt 0 ]; then echo "两个目录中有文件的数量的变化:$list" | tee -a $base/result.log fi
问题二:
简化界面输出:
将 echo "$target folder was removed some files: $remove" | tee -a $base/result.log 改为 echo -e "******$target folder was removed some files:****** \n$remove\n" | tee -a $base/result.log 同理:其他的 echo 都是一样的
问题三:
双斜杠的输出
将 list=$(diff $target/ $base/files/ | grep ^只在 | sed -e 's/只在 //g' -e 's/ 存在://g' | sed 's/\g') if [ $? -eq 0 ]; then echo "两个目录中有文件的数量的变化:$list" | tee -a $base/result.log fi 修改为 list=$(diff $target/ $base/files/ | grep ^只在 | sed -e 's/只在 //g' -e 's/ 存在://g' -e 's/\/\//\//g') if [ ${#list} -gt 0 ]; then echo -e "******两个目录中有文件的数量的变化:****** \n$list" | tee -a $base/result.log diff $target/ $base/files/ | head -n 1 | sed -e 's/\/\//\//g' echo -e "\n" fi
问题四:
判断文件参数是否存在
使用 test 命令,配合逻辑或
在最上面的 参数 赋值 下面添加以下指令
if [ ! -d $target ]; then echo "参数一不是一个有效目录" if [ ! -d $base ]; then echo "参数二不是一个有效目录" fi exit 1 fi
问题五:
如果将脚本应用于真正的文件中会有什么样的效果?
如果第一个参数下还有目录呢,我们 cp 只是 cp 的普通文件
我们可以看到问题有:略过目录;自动执行了最后一个文件数量变化的检查功能
如何解决这些问题呢?
为什么会略过目录???
仔细一想原来是cp命令的问题,我们普通的cp命令只是简单的拷贝普通文件,要想拷贝目录,还得加上 -r 参数 将 cp $target/* $base/files/ 改为 cp -r $target/* $base/files/
改完之后就变成了这样
最终成果:
target=$1 #这是原来的目录 base=$2 #这是备份出来的目录 action=$3 if [ ! -d $target ]; then echo "参数一不是一个有效目录" if [ ! -d $base ]; then echo "参数二不是一个有效目录" fi exit 1 fi if [ $action = "new" ]; then mkdir $base/files #创建备份的目标位置 cp -r $target/* $base/files/ #执行备份 find $target -type f | xargs md5sum > $base/learn.md5 fi echo > $base/result.log #正事开始之前,先清空日志文件 md5sum -c --quiet $base/learn.md5 1> $base/learn.diff 2> /dev/null remove=$(cat $base/learn.diff | grep "打开或读取失败" | sed 's/:打开或读取失败//g') if [ ${#remove} -gt 0 ]; then echo -e "******$target folder was removed some files:****** \n$remove\n" | tee -a $base/result.log fi change=$(cat $base/learn.diff | grep "失败$" | sed -e 's/失败//g' -e 's/: 打开或读取失败//g') if [ ${#change} -gt 0 ]; then echo "******$target folder was changed some files:****** \n$change" | tee -a $base/result.log diff $target/ $base/files/ #这个输出的就是两个文件不同的内容 fi list=$(diff $target/ $base/files/ | grep ^只在 | sed -e 's/只在 //g' -e 's/ 存在://g' -e 's/\/\//\//g') if [ ${#list} -gt 0 ]; then echo -e "******两个目录中有文件的数量的变化:****** \n$list" | tee -a $base/result.log diff $target/ $base/files/ | head -n 1 | sed -e 's/\/\//\//g' echo -e "\n" fi mail -s "关键文件监控警报" 2811403517@qq.com < $base/result.log
扩展内容:
目前的功能主要实现了针对某个特定目录下的所有普通文件进行监控,到那时,如果作为一个真正意义上的监控工具,通常会监控多个目录,会监控多个文件,甚至会指定监控某些特定文件