小技巧
0x01 查找文件¶
从环境变量查找文件
- which
只能查找系统命令的具体文件位置
- whereis
查找的类型不只是系统命令(二进制文件),还有一些其他文件,比如源文件等,在$PATH路径基础上增加了一些系统目录的查找,查找范围比which稍大,查找速度快
- -b 只查找二进制文件
- -B 指定寻找二进制文件的路径
- -s 只搜索源文件
- -S 指定搜索源文件的路径
- locate
从索引数据库(/var/lib/mlocate/mlocate.db
)里查找文件,数据库每天更新,所以可能查到的文件不是最新的,甚至可能已经被删除了,可以使用 updatedb
来进行更新数据库
强烈建议在updatedb执行前查找一次,updatedb更新后查找一次
locate 默认会把包含所查询的字符的结果都显示出来,比如我们想查询 ls ,那么类似 tools 这种结果也会显示出来
我觉得locate 是一个很好的搜索工具,所以详细说几个参数
- -b 只搜索文件名,不搜索文件夹名
- -i 忽略大小写
- -r "" 正则匹配
- find
find 是从文件系统中进行搜索,大而全,但是巨慢,以上命令都查找不到的时候再使用这个命令
find 默认文件和目录都会进行搜索,名称要准确,支持正则,可以使用通配符
-type 参数指定
d 目录
f 文件
l 符号链接
s socket
- 基础使用
find / -name evil.sh
- 忽略大小写
find / -iname evil.sh
- 查找时排除某个/类文件
find / -name *evil* ! -name *.log
- 查找时排除目录
find / -name *evil* -path "/root/home/aaa" -prune
- 查找目录
find / -type d -name eval
按照权限查找文件 -perm
- 查找 777 权限的文件
find / -type f -perm 777
- 查找 SUID 文件
find / -perm /u=s
- 查找 SGID 文件
find / -perm /g=s
- 查找 Sticky 文件
find / -perm /o=t
基于所有者和组查找文件 -user / -group
- 查找根目录下属于 root 的文件或文件夹
find / -user root
- 查找ssh组的所有文件
find / -group ssh
基于时间进行查找
-mtime 修改时间
- 查找最近三天修改过的文件
find / -mtime -3
- 查找三天前修改过的文件
find / -mtime +3
- 查找最近24小时修改过的文件
find / -mtime -1
-atime 访问时间
- 查找3天内访问过的文件
find / -atime -3
- 其他类似
-ctime 属性修改时间,还未发现可以修改 ctime 的常规方法,所以可以作为依据
- 寻找最近三天修改过属性的文件
find / -ctime -3
-daystart 按天算,不是按照24小时算, -1 表示昨天,而不是从现在往前导24小时
- 寻找昨天创建的文件
find / -ctime 1 -daystart
- 寻找向前3~5 天之间编辑的文件
find / -mtime 3 -mtime -5 -daystart
如果你觉得天这个单位太大了,可以使用分钟,分别对应 -mmin/-amin/-cmin
- 查找三分钟前编辑的文件
find / -mmin +3
- 查找三分钟内编辑的文件
find / -mmin -3
- 查找三分钟前访问的文件
find / -amin +3
- 查找三分钟内访问的文件
find / -amin -3
- 查找三分钟前修改属性的文件
find / -cmin +3
- 找三分钟内修改属性的文件
find / -cmin -3
按照大小寻找文件 -size ,参数后单位可以为:
- b 512-byte block
- c bytes
- w two-byte words
- k
- M
- G
- 寻找10M的文件
find / -size 10M
- 寻找大于10M的文件
find / -size +10M
- 寻找小于10M的文件
find / -size -10M
- 寻找 10M到20M之间的文件
find / -size +10MB -20M
参考文章:
https://zhuanlan.zhihu.com/p/35727707
https://cloud.tencent.com/developer/article/1348438
https://www.cnblogs.com/Q--T/p/7864795.html
https://www.linuxprobe.com/find-search-file.html
0x02 查找文件内容¶
很多时候,我们无法确定恶意程序的文件名,但是某些配置文件的关键字是不会更改的,所以我们可以利用关键字进行查找
grep [OPTIONS] PATTERN [FILE...]
首先介绍一下 grep 的参数,后面有常用案例
正则表达式相关参数
- -E 扩展了正则表达式,支持了以下几种规则
- +
- ?
- a|b
- ()
- x{m}
- x{m,}
- x{m,n}
- -F 该参数后的正则表达式字符串中所有字符串都没有特殊含义,仅仅是其本身
- -P 使用 perl 正则表达式
- -e 正则表达式中存在 -- 的,默认会被识别为参数,使用 -e 参数可以将 -- 认定为正则表达式中的字符
- -f file 从文件中加载正则
- -i 忽略大小写
- -w 只匹配完整的单词,比如 administrator 中包含 admin,使用 -w admin 是不会查询到结果的,只有 i am admin ! 这种才可以
- -x 匹配整行
- -z 跨行匹配
杂项
- -s 禁止输出因文件不存在或文件没有读权限而产生的错误信息
- -v 反转结果,不显示制定的正则
- -V 版本信息
输出控制
-
-m NUM 匹配到NUM行后停止
-
-b 打印匹配的行在文件中的字节偏移量
-
-n 显示匹配的行号
-
-H 批量匹配时,显示匹配的文件名,默认参数
-
-h 与 H 相反,不显示文件名
-
-o 只输出匹配到的字符
-
-q 不显示任何东西
-
-a 匹配二进制数据
-
-I 不匹配二进制的内容
-
-d action 目录操作,读取(read),递归(recurse),跳过(skip)
-
-D action 设置对设备,FIFO,管道的操作,读取(read),跳过(skip)
-
-r 递归,不会搜索符号连接内的内容,所以可以尽量使用 -R
-
-R 递归的同时可以设置一些选项,比如排除一些目录等
-
-L 显示未匹配到的文件名
-
-l 只显示匹配到的文件名
-
-c 打印每一个文件中匹配结果的行数
文本控制
-
-B \<NUM> 显示查找到的行前的N行的内容
-
-A \<NUM> 显示查找到的行后的N行的内容
-
-C \<NUM> 显示查找都的行前后各N行的内容
常见使用方法
- 查找某个文件中的字符串
grep "str" evil.sh
- 在某个目录中的文件中搜索某个正则表达式
grep "str" /root/xxx/*
- 递归在某个目录下所有文件中进行查找
grep -rn "str" /root/xxxx/
-
查找多个字符
-
grep "str1\|str2" /root/xxxx/*
grep -E "str1|str2" /root/xxxx/*
grep -e "str1" -e "str2" /root/xxxx/*
-
查找同时存在两个字符
-
grep -E 'str1.*str2' /root/xxxx/*
-
只搜索部分文件
-
grep 'abc' -r --include=*.conf /root/xxxx
grep 'abc' -r --include="*.{conf,config}" /root/xxxx
-
排除部分文件
-
grep 'abc' --exclude=*.elf /root/xxxx
grep 'abc' --include=*.conf --exclude=*demo.conf
- 全盘搜索某个表达式
如果匹配到的内容行太长,影响观看,可以考虑加入 -l
参数,只显示匹配到的文件名
0x03 确定系统相关信息¶
查看系统版本信息
cat /etc/issue
- Ubuntu/Debian 系列适用
cat /etc/lsb-release
lsb_release -a
- Redhat/Centos 系列适用
cat /etc/redhat-release
查看系统是32位还是64位
getconf LONG_BIT
uname -m
arch
hostnamectl
file /sbin/init
或者file /lib/systemd/systemd
lscpu | grep "Architecture\|架构"
dpkg --print-architecture
[适用于Ubuntu类系统]dpkg-architecture -q DEB_BUILD_ARCH
[适用于Ubuntu类系统]
查看内核版本信息
cat /proc/version
uname -a
hostnamectl
0x04 系统完整性检查¶
很多时候我们想知道系统是否存在系统命令、软件包等被替换的情况,可以使用下面的方法进行检查
需要在 root 权限下执行
RedHat/Centos
rpm -Va
Ubuntu/Debian
-
apt install debsums
-
debsums --all --changed
0x05 系统文件监控工具¶
0x06 查看glibc版本¶
- ldd --version
0x07 文本比对¶
将要比对文本复制到 burpsuite 的 Compare 模块中 -> 粘贴进去 -> 使用words进行比对
不同的内容会有颜色标识
0x08 数据恢复¶
狡猾的攻击者往往会将自己留下的蛛丝马迹进行删除,此时,数据恢复就起到了重要作用
咱们就以管理员误删文件为背景来进行讲解
误删了文件,情况其实很简单,就两种: 被删除的文件有/无进程正在对其读写,有的话,那算事幸运,没有的话,自求多福。
存在进程对误删文件进行读写¶
这种情况简单来说就是被删除的文件在进程的内存空间还保存着一份,可以通过访问某个目录来找到文件恢复
接下来做一下这个实验
打开两个终端,终端1 和 终端2
终端1 : 创建文件
终端2 : 使用 cat 模拟一下进程持续读写 111.txt
终端1 :删除 111.txt
可以看到,111.txt
已经被删除了
终端1 : lsof 查找文件占用并恢复
可以看到 cat
这个程序正在操作这个文件,进程 id 为 68048
终端1: 找到进程空间文件对应目录(/proc/<pid>/fd
),恢复文件
数据成功恢复
如果应用主程序被删除了,也就是该案例中的 cat
,则直接执行以下命令即可恢复可执行程序
数据恢复程序¶
数据恢复程序的原理其实很简单,如果你读过《鸟哥的Linux私房菜》肯定知道,我们的文件 rm 删除之后,文件实体暂时还是在的,只不过文件所在的块已经被标记为删除了。就好像拆迁一样,我规划了要把你家拆迁,但是现在还没拆,只要手续都办完就会拆,所以我们应尽可能快地将数据恢复。
https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/59.html
选择数据恢复程序来进行恢复有几点比较重要
-
从误删除了文件的那一刻起,就不要再向文件所在的分区做任何写入工作了
当然了,很多时候已经在跑的程序不能停,那就要做好权衡了
-
在不影响其他程序运行的情况下将误删文件所在的分区卸载掉(umount)
-
在选择数据恢复软件前了解清楚文件系统类型
-
恢复文件存储分区选择需要谨慎
- 不能是之前误删文件的分区
- 分区大小要大于之前误删文件的总大小
-
有能力的话,可以考虑将分区备份一份
常见的支持文件系统有:
- 传统文件系统:ext2 / minix / MS-DOS / FAT (用 vfat 模块) / iso9660 (光盘)等等;
- 日志式文件系统: ext3 /ext4 / ReiserFS / Windows' NTFS / IBM's JFS / SGI's XFS / ZFS
- 网络文件系统: NFS / SMBFS
查看当前 Linux 支持的文件系统
ls -l /lib/modules/$(uname -r)/kernel/fs
查看系统目前已载入到内存中支持的文件系统
cat /proc/filesystems
常见的 Linux 文件恢复工具
- Extundelete
- Debugfs
- R-Linux
- Ext3grep
- Ext4magic
- Testdisk
数据恢复软件名称 | 支持文件系统类型 | 操作难易程度 | 最近一次更新 |
---|---|---|---|
Extundelete | ext3/ext4 | 中 | 2013/2/21 |
Debugfs | ext2/ext3/ext4(新系统白费) | 中 | 系统自带 |
R-Linux | ext2/ext3/ext4 | 简单 | 2015/5/17 |
Ext3grep | ext3 | 中 | 2010/4/19 |
Ext4magic | ext3/ext4 | 中 | 2014/9/12 |
TestDisk | 吹牛没输过,实战没赢过 | 复杂 | 2019/7/10 |
常见的系统急救工具(从崩溃的系统中copy文件)
- Ddrescue
- Avira Rescue System
查看误删除文件所在分区的文件系统类型¶
这里假设误删除文件为 /opt/project/data.mdb
-
df -T /opt/project/
df -T
命令可以直观得看到误删文件所在目录的挂在点,所在分区,以及分区的文件系统类型
如果你不喜欢 df 命令或者系统上不存在df 命令,可以先确定一下目录所在分区,直接使用 mount
和lsblk -f
命令
-
mount
-
lsblk -f
卸载误删文件所在的分区¶
如果卸载了该分区,那么该分区运行的程序和向该分区写入的操作都会终止,所以这个操作可能不会很顺利,需要权衡
如果该分区有程序正在运行或者有程序正在对该分区文件进行读写,是无法直接卸载的,需要停掉这些操作
还有就是不要想着把根目录卸载了,可以考虑其他方法,比如类似安全模式的东东
可以看到,/opt/project
所在分区为 /dev/sdb
, 或者应该说 /dev/sdb
挂载在 /opt/project
目录下
卸载该分区 umount /dev/sdb
这样就将分区卸载掉了,卸载掉的分区数据还在,可以在后期重新挂载到某个目录下
Extundelete¶
http://extundelete.sourceforge.net/
支持 ext3、ext4
安装 Extundelete
apt install extundelete
现在 /dev/sdb1
挂载在 /opt/project
下,我们在这个目录下创建一个文件 test1.txt
我们删除 test1.txt
并使用 Ext3grep
进行文件恢复
-
卸载
test1.txt
所在分区umount /dev/sdb1
-
扫描指定文件系统的根路径
extundelete --inode 2 /dev/sdb1
/dev/sdb1 是本次实验的文件系统,大家按照实际情况替换就好
--inode 2 是指根路径
可以看到成功找到了
test1.txt
,就在这个文件系统的根目录下,后面标识这是一个被删除的文件 -
恢复被删除的文件
test1.txt
extundelete --restore-inode 12 /dev/sdb1 -o backup
或者
extundelete --restore-file test1.txt /dev/sdb1 -o backup
可以看到,两种方式都成功恢复了文件,其中
--restore-inode 12
中的 12 是通过上图查询到的test1.txt
对应的inode
;-o
参数指定一个文件夹名字,extundelete
会以这个名字在你执行extundelete
命令的路径下新建文件夹。 -
恢复多个文件、全量恢复
--restore-files 'path'
--restore-directory
--restore-all
这次我们新建一个目录
t1
,之后再创建三个文本文件,之后把它们删除extundelete --inode 2 /dev/sdb1
因为我们没有删除
t1
这个目录,所以 t1 没有显示删除,但是吧,这里也看不出来 t1 是文件还是目录,也看不到 t1 里面有什么,所以我们试着指定 t1 这个目录的 inode 360449extundelete --inode 360449 /dev/sdb1
可以看到,我们被删除的三个文件,我们试着通过上面的几个参数来进行恢复
先来用之前的
--restore-file
试试
--restore-files
这个参数没用明白
试试
--restore-directory
extundelete --restore-directory t1/ /dev/sdb1 -o backup
试试
--restore-all
,这个就是全量恢复了extundelete --restore-all /dev/sdb1 -o backup
-
恢复某个时间段的文件
--after 时间戳
--before 时间戳
可以通过下面这个网站完成时间戳和时间的转换,也可以通过 date命令来获取,后面会讲
https://shijianchuo.net/
extundelete --after 1640966400 --restore-all /dev/sdb1 -o backup
现在我想恢复最近三天的数据,我还要用时间一点一点去算吗? 不用
最近三天也就是三天前的此刻 以后的文件都要
成功恢复。
-
重新挂载分区
mount /dev/sdb1 /opt/project
Debugfs¶
这个程序是系统自带的一个交互式文件系统调试器,在 Centos 6 上可以用来做数据恢复
https://man7.org/linux/man-pages/man8/debugfs.8.html
支持 ext2、ext3、ext4
Centos 7 以及 Ubuntu 16.04 已经不能恢复了
R-Linux¶
一个图形化的数据恢复应用
https://www.r-studio.com/free-linux-recovery-help/basicfilerecovery.html
ext2、ext3、ext4
虽然页面感人,但是还有中文支持
成功恢复文件内容
Ext3grep¶
http://manpages.ubuntu.com/manpages/jammy/man8/ext3grep.8.html
仅支持 ext3
安装 Ext3grep
apt install ext3grep
现在 /dev/sdb
挂载在 /opt/project
下,我们在这个目录下创建一个文件 test1.txt
我们删除 test1.txt
并使用 Ext3grep
进行文件恢复
-
卸载
test1.txt
所在分区umount /dev/sdb
-
扫描指定文件系统的根路径
ext3grep /dev/sdb --ls --inode 2
/dev/sdb 是本次实验的文件系统,大家按照实际情况替换就好
--inode 2 是指根路径
可以看到成功找到了
test1.txt
,前面的D
标志就是表示文件被删除了,而不是 “D 之一族” -
获取文件存在时候的具体路径
ext3grep /dev/sdb --dump-names
可以看到,就在根目录
-
恢复被删除的文件
test1.txt
ext3grep /dev/sdb --restore-file test1.txt
数据恢复成功,恢复后的数据会储存在执行
ext3grep
命令的路径下的RESTORED_FILES
文件夹内 -
恢复全部数据
如果你遇到的情况是不小心格式了一个分区,那可以试一下大招
ext3grep /dev/sdb --reatore-all
-
重新挂载分区
mount /dev/sdb /opt/project
看起来一切很顺利,但是当我测试直接删除一个目录的时候/删除非根目录下的文件,恢复起来就会有问题,大家可以多尝试一下
Ext4magic¶
这个工具非常好用
http://ext4magic.sourceforge.net/howto_en.html
ext3、ext4
这次我们玩儿得复杂点,玩点儿 ext3grep 做不到的(我的知识范围内)
我们在挂载的目录下创建了一个文件夹 aaa
,在其中创建文件夹 bbb
,在 bbb
文件夹中新建 ccc.txt
,还写入了一些字符,之后直接删除了 bbb 文件夹,接下来我们开始文件恢复
-
卸载
test1.txt
所在分区umount /dev/sdb
-
扫描指定文件系统所有的根路径
ext4magic /dev/sdb -f /
/dev/sdb 是本次实验的文件系统,大家按照实际情况替换就好
可以看到到
aaa
这个文件夹,毕竟还在文件系统里嘛,我们没有删除aaa
文件夹,我们能成功找到bbb
和ccc.txt
吗? -
扫描子文件夹中的内容
ext4magic /dev/sdb -f /aaa/
继续寻找
ext4magic /dev/sdb -f /aaa/bbb/
可以看到,此时直接这样查找就不行了,我们需要加上
-T -x
参数 -
恢复被删除的文件
ccc.txt
ext4magic /dev/sdb -rf /aaa/bbb/ccc.txt -d /opt/
数据恢复成功,恢复后的数据按照原来的目录结构保存在
-d
指定的文件夹下 -
全量数据恢复
-M
恢复全部文件-m
恢复全部被删除的文件除非你是一个分区挂了,不然不建议直接使用这两个参数,因为这个参数可以配合更牛的基于时间的参数来做某个时间点以前或者某个时间点以后的全量数据恢复
-
基于时间的数据恢复
-a
时间戳 a 代表 after,表示在这个时间点以后-b
时间戳 b 代表 before,表示在这个时间点以前时间戳可以通过
https://shijianchuo.net/
这个网站进行时间和时间戳的转换假设我们想把 2022 年 1 月 1 日以后删除的文件都恢复一下
ext4magic /dev/sdb -a 1640966400 -d /opt/backup -m
可以看到我们上面恢复的 aaa/bbb/ccc.txt 文件还在,但是之前几个工具做演示的文件,比如 test1.txt、test2.txt 已经恢复不了了,因为他们已经被我们新创建的文件和文件夹给覆盖了
现在我想恢复最近三天的数据,我还要用时间一点一点去算吗? 不用
最近三天也就是三天前的此刻 以后的文件都要
ext4magic /dev/sdb -a $(date -d "-3day" +%s) -d /opt/backup -m
有趣的是,ext4magic 官方的man手册里还犯了一点儿小错误
-
快速获取文件列表
之前我们从根目录开始,一层一层找 ccc.txt ,作为一个这么先进的工具,是不是可以直接把所有的目录和文件都显示出来呢,我们好通过 grep 来进行查找
ext4magic /dev/sdb -Lx -f /
如果你觉得,你对这里的 bdir 不感兴趣,你就是想看 aaa 目录里的,那就把
-f /
换成-f /aaa/
ext4magic /dev/sdb -Lx -f /aaa
-
直观地看文件覆盖情况
可以使用
-l
参数列出来指定目录还没有被覆盖的文件前面数字是 100% 的表示还没有被覆盖
很推荐这个工具
TestDisk【测试恢复文件失败,不推荐】¶
https://www.cgsecurity.org/wiki/TestDisk_CN
支持操作系统 Windows、Linux、Mac
支持的文件系统
- BeFS ( BeOS )
- BSD disklabel ( FreeBSD/OpenBSD/NetBSD )
- CramFS, 压缩文件系统
- DOS/Windows FAT12, FAT16 和 FAT32
- Windows exFAT
- HFS, HFS+ 和 HFSX (Hierarchical File System)
- JFS (IBM's Journaled File System)
- Linux ext2, ext3 和ext4
- Linux LUKS 加密分区
- Linux RAID md 0.9/1.0/1.1/1.2
- RAID 1: 镜像(Mirror)
- RAID 4: 带容错的条带阵列
- RAID 5: 带分布式冗余信息的条带阵列
- RAID 6: 带分布式双冗余信息的条带阵列
- Linux Swap (版本1 和 2)
- LVM 和 LVM2, Linux逻辑卷管理器(Linux Logical Volume Manager)
- Mac partition map
- Novel NSS (Novell Storage Services)
- NTFS ( Windows NT/2000/XP/2003/Vista/2008 )
- ReiserFS 3.5, 3.6 和 4
- Sun Solaris i386 disklabel
- Unix文件系统-UFS and UFS2 (Sun/BSD/...)
- XFS, SGI's Journaled File System
0x09 批量查找文件并打印信息¶
这个命令在防守清理webshell的很有用,很适合批量截图,这里以搜索 passwd
这个文件为例
find / -name "passwd" | while read line; do if [ -f $line ]; then ls -al $line; elif [ -d $line ]; then ls -al ../ | grep $line; fi; done
0x10 拷贝取证¶
拷贝取证只是一部分人的需求,可能是取证人员,也可能是需要做交接的应急人员等,以下工具及使用方法可以作为参考
虚拟化平台¶
- 使用自带的虚拟化快照功能
- 直接把整个系统打包带走
全盘拷贝¶
全盘拷贝的工作模式基本上都是需要关机之后再用启动光盘或者U盘等引导,进而进行拷贝的,不然可能会数据错误,mondo rescue 是工作时打包拷贝的,但是对于 Ubuntu 16.04 及以上的系统,bug太多,根本用不了,推荐 clonezilla , 感觉速度更快一些
-
dd 系列
- dd
- dcfldd
- ddrescue
-
G4L
- clonezilla
dd¶
dd 是 Linux 发行版基本都带的工具,可以用来做的事情也非常多,这里我们只演示用来全盘拷贝的功能
dcfldd 和 ddrescue 都是dd升级版或者辅助工具,建议大家了解一下
PS:使用dd命令进行全盘或者部分分区复制强烈建议准备一个LiveCD,建议使用Ubuntu Desktop 22.04启动U盘作为这个LiveCD;同时需要准备一个空的数据存储盘,空间要大于要复制的硬盘或者分区
使用dd进行复制的时候,需要将系统关闭,之后使用准备好的启动U盘进入 Ubuntu 22.04 中进行复制操作了,这也就意味着全盘拷贝是看不到恶意程序的进程情况的
假设受害系统只有一块硬盘,此时需要将其内容全部克隆下来,之后带走做更加深入的分析、取证等,受害系统信息如下
制作启动U盘
关闭受害系统,插上U盘,设置U盘启动,进入LiveCD
确定要备份的硬盘名称以及具体信息
确定我们要复制的源硬盘的设备名称为 /dev/sda
,这块硬盘有三个分区,使用的是 GPT 分区表,硬盘总大小为 16G
接入用来备份的数据盘 500G
查看数据盘信息
数据盘总大小为 500G,硬盘设备名称为 /dev/sdc
,有两个分区,现在我们删除这些分区,新建一个只有20G大小的分区就够了
格式化 /dev/sdc1
分区
新建 /data
目录,将 /dev/sdc1
挂载到该位置
使用 dd 命令将 /dev/sda
硬盘中的所有分区的所有内容拷贝到 /data 目录中的一个文件里,文件名以 ubuntu-sda 来命名
默认是看不到进度的,执行dd后,需要新开一个终端窗口,执行下面的命令来让 dd 显示进度
此时 /dev/sda
这块硬盘中的内容已经全部复制到 ubuntu-sda 文件中,此时已经可以复制多份,并且拿出一份测试系统是否可以正常启动
新建一个虚拟机,使用 CD/DVD 镜像Ubuntu 22.04 作为启动源,当然也可以使用之前做的启动U盘
硬盘容量大于 ubuntu-sda 文件的大小,这里直接以 64G 为例
插入刚刚拷贝的数据盘
根据硬盘大小等信息,可以确定新系统的硬盘设备名称为 /dev/sda
数据盘的设备名称为 /dev/sdb
数据盘有一个分区 /dev/sdb1
已经挂载在某一个路径下了,但是路径有点长,还是新建 /data
目录,挂载到其上
使用 dd 将拷贝的信息恢复到这块64G的硬盘上 (/dev/sda
)
新开终端执行监控指令
从 /dev/sda
硬盘结构上看已经恢复了,现在测试看能不能正常运行
成功启动,克隆成功,克隆的镜像可以直接作为取证材料或者交由其他应急响应人员分析、探究
G4L¶
G4L 是一个硬盘和分区镜像和克隆工具。其实就是 Ghost for Linux 的意思
https://sourceforge.net/projects/g4l/
G4L有一定的弊端
- 必须全盘克隆
- 克隆即使源硬盘500G只装了1G的信息,目的硬盘也必须大于等于 500G(后面有实验)
这个工具在2023年还更新了,这次演示就使用最新版本 G4L 0.62
假设受害系统只有一块硬盘,此时需要将其内容全部克隆下来,之后带走做更加深入的分析、取证等,受害系统信息如下
下载G4L
访问 https://sourceforge.net/projects/g4l/
解压zip,获取 iso 并烧录进U盘
本次演示选择 g4lefi 这个镜像,将其烧录进U盘(32G)
将受害系统关机,连接启动U盘,并设置U盘启动
此时插入数据盘 500G 硬盘(目的硬盘容量要大于源硬盘)
选择默认的这个
有几个这样的画面,一路回车就好,毕竟也没有其他选项
到这一步就要选择源和目的硬盘了
首先选择源驱动器(受害系统的硬盘)
通过上下键可以移动光标,使用空格选中本次要拷贝的 sdc 硬盘
选择目标驱动器(数据盘500G)
选择目的驱动器为 sdb ,也就是数据盘 500G硬盘
开始克隆
拷贝完成后就可以选择最下面的Reboot/Poweroff 进行关机
将数据盘拿回来会,在本地开始恢复系统
新建虚拟机
同样选择默认的第一个,同时接入数据盘 500G 硬盘
一路回车到这里
也使用默认的选项
输入 g4l 回车
选择默认的 RAW 模式
选择 Click'n'Cone,之后就到了熟悉的源目的驱动器选择界面
这回源驱动器就是数据盘500G硬盘了,目的驱动器就是新装的系统的硬盘
开始克隆
结果很尴尬,克隆进度直接停留在这个位置上了
新建的系统分配的硬盘是64G,而数据盘的大小是 500G ,讽刺的是实际上我们需要的数据只有16G
这就是在我们这种场景中,G4L 的弊端,它只能全盘备份,同时是将源硬盘容量的大小克隆给新硬盘,即使500G的硬盘只装了16G的数据,目标硬盘也必须大于等于500G
关机,将新系统硬盘(目的硬盘)容量扩大至 512G,再次克隆
经过了6-8 个小时后,拷贝完成,移除CD、启动U盘、数据盘
复制成功
clonezilla¶
clonezilla 也是一款分区和硬盘克隆工具,使用方式与G4L类似
https://clonezilla.org/
假设受害系统只有一块硬盘,此时需要将其内容全部克隆下来,之后带走做更加深入的分析、取证等,受害系统信息如下
下载 clonezilla https://clonezilla.org/downloads.php
本次演示选择基于 Debian 的稳定版本 3.0.2-21
烧录进 U 盘
关闭受害主机,插上启动U盘,插上数据盘500G硬盘
直接选择默认的选项就好
语言选择简体中文
默认即可
选择默认的选项使用再生龙
这里模式就比较多了,本次演示主要是 硬盘->镜像文件-> 还原到硬盘 为主,这样容易复制,所以选择 device-image
选择本地设备 local_dev
clonezilla 这点很好,它支持在操作过程中插入数据盘,而不是必须从一开始就插入,因为最开始已经插入了500G数据盘,所以这里直接回车
这里已经识别出源数据盘(受害主机)为 /dev/sda ,而目的数据盘为 /dev/sdc ,直接 Ctrl + c结束掉这个界面
这里有点绕,简单来说就是把打包后的镜像放在哪个分区里,/dev/sdc 是我们的镜像,里面有一个 64G 大小的分区 sdc1 ,所以这里选中 sdc1
本次场景是全盘拷贝,不做坏道/坏块 检查以及系统修复,选择默认的第一个
选择存储打包后的镜像的目录,按照实际需求选择,之后选择 Done
选择初学模式
目前场景需要的是全盘复制,所以选择 savedisk
打包后的镜像的名字,默认是当前日期
选择源硬盘,当前场景受害主机只有一块硬盘,所以就是 sda
压缩方式,选择默认即可
是否检查和修正来源系统,选择跳过
这里选择是,让clonezilla 帮我们做一个简单的检查,当然,跳过会节省一些时间,演示选择是,请交叉保存的镜像
选择不对镜像加密
直接选默认的选项
输入 y
克隆完成,回车,poweroff
将镜像拿回公司,新建虚拟机,CD/DVD 放入 clonezilla ,从CD/DVD 启动
进入 clonezilla
步骤同上,直到这一步
目的硬盘就一块,也就不需要选择了
使用默认情况
因为刚刚检查过,这次就选否了
默认选项
y, 继续执行
再 y ,继续执行
重新配置新系统从硬盘启动
成功还原
进程拷贝¶
- CRIU
CRIU¶
https://criu.org/
https://github.com/checkpoint-restore/criu
CRIU (Checkpoint/Restore In Userspace) 是一种在用户空间创建和恢复节点的工具
简单来说,CRIU 可以将正在运行的程序冻结,转化成一些j镜像文件,理想情况下可以随时随地通过这些镜像文件从冻结的节点恢复系统运行,而这些操作都是在用户空间内完成的
CRIU 安装
测试 CRIU 是否运行正常
输出 Looks good 表示安装成功
测试场景,受害主机某一个进程反弹 msf shell ,现在需要将其转储,在未来的某个时间节点在这台主机上重新让其运行
受害主机 Ubuntu Server 20.04 (192.168.31.16)
控制主机 Kali Linux (192.168.31.146)
控制主机 Kali Linux 生成木马(这里选择的是stegeless的木马,演示起来效果更好)
控制主机 Kali Linux 设置监听
msfconsole -q
> use exploit/multi/handler
> set payload linux/x64/meterpreter_reverse_tcp
> set lhost 192.168.31.146
> set lport 4444
> set exitonsession false
> exploit -j
受害主机下载木马并执行
反弹木马进程号 1267
控制主机 Kali Linux 接收到返回的shell
新开一个ssh连接,连接被害主机,安装 criu
在受害主机上使用 criu 对 pid 为 1267 对进程进行转储
此时查看控制主机 Kali Linux 处反弹shell 是否依旧正常
此时连接已经断了
静待五分钟,用来模拟正常应急中因为各种原因造成的时间间隔
恢复进程执行
控制主机 Kali Linux 这一侧
再次收到了反弹shell的请求
此时便可以继续对该进程进行研究了,但是总感觉有些鸡肋
假如说当前这台主机关机了,重启后,保存的进程镜像还能够再次恢复吗?
关闭受害主机,Kali Linux 保持监听
尝试恢复反弹shell的进程
还原失败,并且当前的终端输入字符已经无法看见了
再次启动一个ssh 连接,多次尝试恢复进程,这次 echo 123 并且睡眠3秒,这样即使看不到输入,也可以凭借着输出来判断是否是我们想执行的命令
仍旧失败,多次尝试之后,终于成功了
也就是说可以先将一个程序冻结,之后系统随意关机,再次开机后可以恢复进程,进行分析,这样看起来,是不是有点意思了呢
但是这还不够,看下面
组合拳¶
全盘拷贝会让内存丢失,进程全无;进程拷贝限制进程所在的电脑系统
但是! 如果我们将它们的优势组合起来,会有意想不到的惊喜,相信你已经懂了
组合拳分为三步
- 冻结进程
- 全盘拷贝
- 恢复进程
听起来有点像把大象关冰箱
上面的操作可以使我们不仅能够把系统全盘复制过来,还能保留比较可疑的进程信息
以上三步都是本文详细讲述过的内容,所以直接简述
新建反弹shell的进程
关机 -> 全盘拷贝 -> 新建虚拟机 -> 恢复
PS:这里有一个问题,恢复后的系统IP不会是原来的IP了,这会让进程恢复出现问题,所以需要修改IP为静态IP,同时需要网络设备配合,允许修改静态IP后的系统可以正常上网
我的两个系统网络环境相同,所以只需要修改静态IP就好
Ubuntu Server 20.04修改方法如下
cp /etc/netplan/00-installer-config.yaml .
sudo vim /etc/netplan/00-installer-config.yaml
# 将下面的配置写入该文件中,如果该文件有过定制,需要按照合适的方式配置
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
version: 2
renderer: networkd
ethernets:
eno1:
dhcp4: no
addresses: [192.168.1.2/24]
gateway4: 192.168.1.1
nameservers:
addresses: [114.114.114.114]
需要按照实际情况修改配置,以本次为例
网卡名称: enp0s5
IP地址: 192.168.31.16
网关: 192.168.31.1
即:
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
version: 2
renderer: networkd
ethernets:
enp0s5:
dhcp4: no
addresses: [192.168.31.16/24]
gateway4: 192.168.31.1
nameservers:
addresses: [114.114.114.114]
开始恢复进程
只执行了一次,Kali Linux 便收到了反弹的shell
成功实现了系统和进程的双迁移!
关键文件取证¶
-
Linux Evidence Acquisition Framework
https://github.com/alex-cart/LEAF
Linux Evidence Acquisition Framework¶
不要使用这个工具,可能会使系统出现故障,但是可以参考它的思路写一个自己的工具,代码就算了,这代码连异常都不处理
这个工具是一个取证工具,通过自定义的文件库对当前系统的响应文件进行复制,之后打包成ISO,还支持通过 yara 语法对文件进行匹配检查
很多时候,我们并不能关闭受害系统,而且只想获取部分文件的信息作为取证或者分析材料,这个工具本身自带了一份文件名单,同时支持自定义
// 更新索引
sudo apt update
// 安装pip3
sudo apt install python3-pip
// 升级pip3
pip3 install --upgrade pip
// 安装部分程序
sudo apt install python3-testresources
sudo apt install tree
sudo apt install mkisofs
// 下载 LEAF
git clone https://github.com/alex-cart/LEAF.git
// 安装 python3 依赖库,记得用sudo
cd LEAF
sudo pip3 install -r requirements.txt
// 开始使用,如果使用默认配置
sudo python3 LEAF_master.py
尽可能通过绝对地址来执行 LEAF_master.py
接下来等待进度条走完
// 如果不使用默认配置
-i filelist.txt
可以指定需要采集的文件地址,具体地址文件书写方式可以直接查看当前目录下的 target_locations 文件,使用 -i 指定
-u root
如果只想复制某个用户的文件信息,可以通过 -u root 这种形式来指定
-c SERVICES
如果只想针对某一种信息进行收集,可以通过 -c xxx 来进行指定,具体可选参数为 APPLICATIONS, EXECUTIONS, LOGS, MISC, NETWORK, SHELL, STARTUP, SERVICES, SYSTEM, TRASH, USERS
更多参数可以查看 https://github.com/alex-cart/LEAF
查看一下默认的文件清单
一共195条,去掉第一行,一共 194 个文件夹及文件
现在通过默认的配置文件进行关键文件拷贝
思路挺好,但是不要用这个工具及其代码,我尝试加一些异常处理代码,最终系统还是难以避免挂掉的结果
0x11 history 显示执行时间¶
history 信息默认是不显示命令执行的时间的,但是默认记录了时间,可以通过配置环境变量将时间显示出来
0x12 单独查看某个进程的日志¶
可以通过以下两条命令获取到相应的服务名称
0x13 如何暂停进程/冻结进程¶
暂停/冻结 一个进程¶
两条命令是一样的,执行其中一条即可,原理就是向其发送 SIGSTOP
信号,这个信号会使进程进入暂停状态
恢复/解冻 一个进程¶
同上,本次发送的信号是 SIGCONT
0x14 查找特定时间段内的文件¶
把这部分单拿出来是因为应急溯源过程中用得太多了
查找某段时间内创建的文件(btime)¶
此命令执行时间可能较长,会占用系统资源,而且需要系统支持创建时间记录
find / -type f -exec stat --format '%W %n' {} \; 2>/dev/null | awk -v start="$(date -d '2024-08-16 00:00:00' +%s)" -v end="$(date -d '2024-08-16 23:59:59' +%s)" '$1 != "0" && $1 >= start && $1 <= end {print $2}'
查找某段时间内修改的文件(mtime)¶
find /path/to/search -type f -newermt "2024-07-19 12:30:00" ! -newermt "2024-07-19 15:28:00" 2>/dev/null
查找某段时间访问的文件(atime)¶
查找某段时间内修改属性的文件(ctime)¶
注意事项¶
查找创建文件并不是所有文件系统都支持,基本上所有的文件系统都支持 m、a、c 时间,即修改、访问、属性变动,因此查找文件创建时间基本上只能在支持记录文件创建时间的系统上进行,所以下面的讨论背景都是在支持创建时间的系统上
find 命令的man手册描述是支持根据创建时间查找的,但是经过测试,即使在支持记录创建时间的系统上也无法通过创建时间查找,简单来说就是目前还不兼容。
技巧解析¶
上面提到的查找方式都是单一维度的,要么是查找创建时间,要么是查找访问时间,如果进行稍稍改变,就可以组合查询,例如我想要查找在 2024-07-31 09:33:00
后访问过,且在 2024-07-31 10:49:07
前修改过的文件
find /path/to/search -type f -newerat "2024-07-31 09:33:00" ! -newermt "2024-07-31 10:49:07" 2>/dev/null
命令解析
-type f
指定查找文件,而不是目录-newerat
这不是命令其实是 -newerXY 下面会详细讲解!
是取反2>/dev/null
是不显示标准错误
-newerXY 官方解析如下
这里的 X 和 Y 分别代表两种时间标记,如果被查找范围内文件的 X 的时间比参数指定的文件的 Y 更加 新 一些,则执行成功,其中 X 和 Y 取值如下:
- a 访问时间
- B 创建时间
- c inode 状态改变时间,一般认为是属性修改时间
- m 修改时间
- t 通过命令参数指定的时间
其中 X 不可以取值 t
假设我们想查找属性修改时间(元数据修改,即ctime) 在 test.txt 文件的内容修改时间之后的文件
修改内容后,又被修改过属性的文件,即 ctime > mtime ,我们可以执行下列命令
目前 Ubuntu Server 22.04 还不支持 B 选项
0x15 内存中搜索字符串¶
使用如下脚本 scan_memory.sh
#!/bin/bash
# 要搜索的字符串
SEARCH_STRING="your_string_here"
# 遍历所有进程
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
echo "Scanning PID $pid..."
# 获取进程的内存映射
map_file="/proc/$pid/maps"
if [ ! -e "$map_file" ]; then
continue
fi
# 遍历内存映射中的每一行
while IFS= read -r line; do
# 提取内存区域的起始地址和结束地址
address=$(echo "$line" | awk '{print $1}')
start_addr=$(echo "$address" | cut -d- -f1)
end_addr=$(echo "$address" | cut -d- -f2)
# 将起始地址和结束地址转换为十进制
start_addr_dec=$((0x$start_addr))
end_addr_dec=$((0x$end_addr))
# 计算内存区域的大小
size=$((end_addr_dec - start_addr_dec))
# 读取并搜索内存区域
mem_file="/proc/$pid/mem"
if [ -e "$mem_file" ]; then
dd if="$mem_file" bs=1 skip=$start_addr_dec count=$size 2>/dev/null | grep -a "$SEARCH_STRING" && echo "Found in PID $pid"
fi
done < "$map_file"
done
例如搜索 www.baidu.com
可能同时搜索出来的进程不止一个,此时就需要根据实际情况进行测试和判断了
0x16 配置文件检查小技巧¶
Linux 上的程序配置文件较多,基本上都是 shell 脚本形式,普遍注释比较多,空行比较多,可以使用下面的命令进行筛选
直接查看结果如下
使用筛选命令查看如下
0x17 进程&容器抓包¶
这里主要介绍一个工具 —— ptcpdump
https://github.com/mozillazg/ptcpdump
这款工具对标 tcpdump 工具,基于 bpf ,要求 Linux kernel version >= 5.2
,增强功能有很多,比较重要的例如会保留流量对应进程、可以抓容器的包
这里演示两个功能,一个是抓包,查看包对应的进程信息;一个是抓指定进程的包
1. 安装¶
https://github.com/mozillazg/ptcpdump/releases
直接下载编译好的二进制即可
2. 演示抓包包含进程¶
使用方法几乎与 tcpdump 类似
使用 Wireshark 打开此数据包
可以看到在 Packet comments
部分包含进程 id、命令行、参数等信息,这是 tcpdump 没有的
手册中使用的 ptcpdump 版本为 0.17.0
,目前 icmp
数据包还没有进程相关的标记
这个项目还在开发过程中,相信在后续的版本应该会加上此功能
3. 演示抓指定进程的包¶
看来目前通过筛选 pid 查 icmp 数据包也是不行的,我们换一个
其他协议目前是没问题的