UNIX系统下的应急响应工具介绍
第二部分 文件系统工具
原作者:Holt Sorenson 原文:《Incident Response Tools For Unix, Part Two: File-System Tools》 last updated October 17, 2003 来源:http://www.securityfocus.com/infocus/1738 翻译:Refdom www.xfocus.org
这是关于应急响应工具介绍的三个系列文章中的第二部分。第一部分聚焦在系统工具上,本部分将主要讨论文件系统工具,下一部分则主要是网络工具和其他工具。这三部分都是基于 OpenBSD 3.2, Debian GNU/Linux 3.0 (woody), RedHat 8.0 (psyche), and Solaris 9 (aka Solaris 2.9 or SunOS 5.9)的。这些工具都是系统中比较通用的工具,除了少部分外。如果某个工具在操作系统中不存在,那么在文章的参考部分中应该可以找到相关信息。
文章中的这些工具都执行在用户空间。如果攻击者安装一些核心模块,或者root-kit来替换系统上的二进制文件,那么这些工具就可能不会很准确。这就是将数据离线在安全的系统中分析的一个原因。除非这些数据能够确认是可信的,否则绝对不能信任它们。介绍多个工具来做相类似的事情,可以在响应事件的时候有更多选择。
必须强调的是,这些工具都应该仅仅在只读介质中执行,或者一个安全的系统中用来作离线分析。使用只读介质可以确认这些工具不能被更改。
在应对事件的时候,安全人员应该首先知道的是,他们优先捕获纪录的是哪些数据。这些数据是存在被更改的趋势的。应急响应队伍需要讨论处理的优先级,是否需要让机器离线,还是应该先作好系统的镜像,或者捕获那些活动数据,比如当前的进程、建立的网络连接,内存分配和使用情况,用户登录情况。在事件发生后,系统在线的时间越长,那么,从(远程的、本地)攻击者或者系统造成破坏的威胁就更大。 通过法律的介入可以来检验安全队伍的事件处理过程是否符合必要的法律取证。类似HTCIA(US)和NHTCU(UK)这样的组织能够帮助处理技术专家同应对计算机犯罪进行取证的法律官员之间的联系。
第一部分文章中最后找到了密码破解工具,John the Ripper,在本文,我们将利用文件系统工具来继续去挖掘信息来揭露这个是怎么被入侵的。
Sum packages need to be checked
攻击者是在03:17开始破解密码的,现在从03:17开始进行搜索,但是这个时间并不是攻击者闯入的时间。攻击者通常使用一些自动化的程序来扫描和攻击有漏洞的系统,这就意味着攻击者使用的工具通常会在一些时间之前就留下了一些痕迹。
现在深入到一些可以帮助我们来检测文件系统的改变的工具。一些工具在系统中默认存在的,而一些需要另外指定安装或者是一些第三方的工具。
在Solaris和Linux上,有一些自身存在的命令来比较当前系统安装的包。命令是: rpm -Vva(RH8.0),pkgchk -vn(Solaris 9),和debsums -ac(Deb3.0)。rpm和debian格式化都能用RFC2440 (OpenPGP)来根据签名验证这些包。也可以用MD5来作为校验和。在Solaris系统上,pkgchk用SystemV(SYSV)算法来验证二进制是否被篡改。SYSV运算法则可以检测出只改变文件内容而不改变文件长度的变化。然而,不可能根据SYSV算法来进行完整性检查。它只是更多地依赖于文件大小和时间戳。用惯了十六进制编辑器和touch命令的人都知道改变文件内容而不改变文件大小,以及改变文件的时间戳,这些操作是多么的容易。在Debian GNU/Linux,可以指定一套包来进行对比检查。如果在/mnt上装载了一套只读的包 ,可以通过这个命令来检查包文件:debsums -cagp /mnt/* 。这相当于rpm命令:rpm -Vvp /mnt/Redhat/RPMS/*.rpm 。用rpm -Vva --dbpath <some_path> 可以来验证备用数据库。在Debian系统上相似的命令是: debsums -cagd <some_path>。这些数据库应该保存在只读介质上并且来自可信系统。如果你想获得rpm的详细数量,可以加上参数-v。这些命令可以帮助检查攻击者做的一些改变。
package tools verifying current file system state against package metadata: {redhat80} $ rpm -vVa [ snip lots of output ] ..5....T /bin/ls [ snip lots of output ]
{solaris9} $ pkgchk -vn [ snip lots of output ] ERROR: /usr/bin/ls modtime <04/06/02 10:54:41 PM> expected <09/08/03 01:04:01 AM> actual file cksum <63074> expected <63042> actual /usr/bin/ls [ snip lots of output ]
{debian30} $ debsums -ac [ snip lots of output ] bin/ls [ snip lots of output ]
比较当前的系统上的安装的包的数据库有很多帮助,但是,如果系统被高度自定义过了,打包系统和当前的文件系统上的metadata可能是完全不同的。所以用包工具来比较当前文件系统状态和程序包数据库可能不会得到期望的结果。OpenBSD上有一个工具叫mtree,它可以用hash函数[5]来确信文件系统上的文件从上次数据库更新起是否被改变过。如果攻击者附加或者修改已经在mtree的数据库中存储了hash的文件,那么这些改变就可以被mtree检测出来。另外一些第三方的工具也有类似功能,比如:AIDE, integrit, Osiris和tripwire。另外一些工具,比如:changedfiles, dnotify, 和FAM用核心模块,或者监控查询文件系统来检测文件改变,这些工具可以比文件系统完整性检测工具更快地得到文件改变的通知。这是因为文件系统完整性检查工具是通过周期性地用hash函数来检测的。当然,所有这些工具都应该在被入侵之前先安装配置好。
如果上面这些工具还没有安装配置,或者需要进行进一步的挖掘,这里还有一些其它工具可以用到。这些工具通常可以用在文件上,在Solaris系统,也可以用于目录。当然,这需要拥有一个可信系统,在其上运行相同的工具,来比较两者的运行结果,这些工具才是有用的。如果信任 The Shmoo Group(http://www.shmoo.com/),那么就可以参考这里的 Known Goods(http://www.knowngoods.org/)数据库来查询hash和文件大小。 md5sum工具可以在Linux系统上进行MD5 hash的计算。在OpenBSD上,类似的工具是md5,OpenBSD也有基于SHA1和RIPEMD 160 hash算法功能的工具:sha1和rmd160 。命令openssl可以利用OpenSSL库来进行hash计算。 openssl dgst <some_file> 默认使用MD5算法。用openssl dgst -?可以察看这个命令的使用方法以及提供的不同hash算法。实际上,执行命令的时候可以不需要'dgst'符号。比如,如果用MD5对文件来进行hash,可以执行 openssl md5 <filename>。 另外一个工具:shash [8]可以用前面提到的hash算法来进行校验(详见 shash -l),它也可以用一对另外的算法来计算校验和。
那些不是通过hash函数来进行校验和的命令,则并不应该使用在应急响应中。比如命令chsum和sum。校验和(checksum)算法(CRC*, BSD和SYSV)不能到达hash函数所能提供的断言等级。事实上也是这样,checksum算法根本不能在取证中值得信任。checksum算法主要用于检测数据传输和存储中是否发生错误,而不是用于保护和警报数据被恶意攻击者修改。很容易可以找到多种数据的组合,而有相同的校验和。即使先得到数据的checksum,并且把checksum和它们的数据都存储在只读介质中,可以确保这些数据不会被修改,而应对的策略则是可以创建另一些数据,并且有相同的checksum,这种应对办法导致的结果就是这些数据会被怀疑,但是checksum并没有提供足够的断言:这些数据是被篡改了。依赖checksum算法要匹配的复杂度是很小的,而基于MD5算法的复杂度是2^128,SHA1则是2^160。对于MD5和SHA1算法,是很难找到两组数据能够产生相同的hash值。checksum算法可以对付数据的意外干扰,而不是对付恶意攻击的。这就是为什么使用基于hash函数如MD5或SHA1的必须的。
Hash/Checksum tools in action: {deb30} $ md5sum /bin/ls a5c720b6776331b9695d9a1f4f5c2194 /bin/ls {deb30} $ openssl dgst /bin/ls MD5(/bin/ls)= a5c720b6776331b9695d9a1f4f5c2194 {deb30} $ shash /bin/ls # MD5 HASH a5c720b6776331b9695d9a1f4f5c2194 /bin/ls {deb30} $ cksum /bin/ls 2890986056 43784 /bin/ls {deb30} $ sum -r /bin/ls 56701 43 {deb30} $ sum -s /bin/ls 6968 86 /bin/ls
Hey MAC, what time ya got?
UNIX或者类UNIX文件系统存储一套时间戳元数据,这些时间戳包括modify、access和change时间,即MAC时间。这些时间戳都保存在文件系统索引节点(inode)结构中。除了这些时间戳外,inode也包含其他的文件信息,比如:文件类型、许可、所属、组、大小、硬连接数,以及文件占用的数据块。目录也有它们自己的inode,这包括目录下的文件名,以及包含文件信息的inode数量。
mtime (modify time)反映的是文件数据最后被修改的时间,系统调用比如write, trucate, mknod 都会改变mtime。 ctime(change time)反映的是文件的inode结构最后被改变的时间,atime(access time)反映的是文件数据最后被访问的时间。当系统调用execve, read, mknode, utime, pipe等都会修改atime。你可以在stat(2)的帮助中找到更多关于mtime, atime, ctime的细节。
要改变MAC时间有多种不同的命令和不同的方法。下面的表格现实了一些普通命令对MAC时间的作用。这些表是基于使用ext2文件系统的Debian3.0,其中包含加载在loopback设备上的flat file。如果在LINUX系统的loopback设备上加载许多镜像,可以在引导程序中设置max_loop = 255,来在启动前传递给系统核心。那么就可以加载255个镜像,而不是默认限制的8个。一旦文件系统加载到loopback设备上,就可以用debugfs检查。建议在你自己的系统上对下面表格中的内容进行试验[9]验证。下面表中基本是可以通用的。
(译注:因为文本的排版问题,可参考原文的表格)
How common commands change MACtimes for a directory (foo): Action atime ctime mtime creation (mkdir foo) X X X directory move (mv foo bar) X X file creation (touch foo/foo) X X file creation (dd if=/dev/zero of=foo/foo count=1) X X list directory (ls foo) X change directory (cd foo) file test (-f foo) file move/rename (mv foo foo_mvd) X X permissions change (chmod/chown <some_perm> foo) X file copy (mv foo_mvd foo) X X file edit (vim foo) X X file edit (emacs foo) X X X file edit (nvi/nano foo)
How common commands change MACtimes for a file (f1): Action atime ctime mtime creation (touch foo) X X X creation (dd if=/dev/zero of=foo count=1) X X X rename (mv foo bar) permissions change (chmod <some_perm> foo) X copy (cp foo bar) X copy overwrite (cp bar foo) X X append (cat >> foo) X X overwrite (cat > foo) X X truncate (cp /dev/null foo) X X list file (ls foo) edit (vim/emacs/xemacs/joe/jed foo) X X X edit (ed/nvi/vi (sun)/vi (obsd)/nano/pico foo) X1 X1 X1
1 - all times changed, but atime is slightly older than mtime and ctime
ls命令可以用来现实文件的MAC时间,下表显示的是多个ls命令,来按最后修改时间的排序列举。
displaying MACtimes using ls: Linux (ls from GNU fileutils) OpenBSD Solaris mtime ls -latr --full-time ls -latTr ls -latr atime ls -laur --full-time ls -lauTr ls -laur ctime ls -lacr --full-time ls -lacTr ls -lacr
find命令也是非常有用的,可以用来查询被修改了的文件,只需要使用-ctime, -atime, -mtime参数。当使用find命令的时候,注意,那些目录下的文件的atime都会被改变。如果要更正规的使用find命令,那么应该使用在只读的镜像中。
多数Linux都有find[10],GNU版的find有很强的功能,可以指定一个时间区域,这样让find来显示这个区域的时间戳。如果你想查询多个至少7天前被修改的文件,并现实它们的mtime,ctime,atime和inode,可以用下面的命令:
# find / \( -mtime +2 -a -mtime -7 \) -a -printf "M:%t C:%c %i\t%p\n"
如果使用Linux,但是没有GNU的find,那么可以用stat命令,如果没有stat命令的权限,但可以用perl,那么可以用perl来当作stat(2):
# find / \( -mtime +2 -a -mtime -7 \)|perl -ne 'chomp;($i,$m,$c)=(stat)[1,9,10];printf"M:%s\t$i\t$_\n",localtime($m)." C:".localtime($c)'
攻击者可能通过有问题的suid或sgid的二进制来提升权限。攻击者有是也留下可以suid root 的shell,这样让他们更方便。find命令可以捕获到这样的文件。可以使用这样的命令:
find / -perm -6000 -ls
下面是一些find命令的例子:
the find command in action: ##== ##== find all files which have had their status changed in ##== the last 24 hrs (display ctime, inode, and filename) # find / -ctime -1 -printf "%c %i\t%p\n" Fri Sep 7 11:55:14 2003 174945 /var/lib/rpm Fri Sep 7 11:55:14 2003 174946 /var/lib/rpm/__db.001 Fri Sep 7 11:55:17 2003 174947 /var/lib/rpm/__db.002 Fri Sep 7 11:55:17 2003 174948 /var/lib/rpm/__db.003 Fri Sep 7 11:55:55 2003 160125 /var/lib/random-seed Fri Sep 7 11:55:16 2003 222706 /var/log Fri Sep 7 12:17:05 2003 224545 /var/log/messages [ output deleted ] ##== ##== find all files which have had their status changed from ##== 5 to 30 (inclusive) days ago and display the ctime, inode, and filename # find / -ctime +4 -ctime -31 -printf "%c %i\t%p\n" Sat Aug 30 19:49:52 2003 414661 /boot/System.map-2.4.20-20.8bigmem Sat Aug 30 19:49:52 2003 414662 /boot/config-2.4.20-20.8bigmem Sat Aug 30 19:49:52 2003 414663 /boot/module-info-2.4.20-20.8bigmem Sat Aug 30 19:49:53 2003 414664 /boot/vmlinux-2.4.20-20.8bigmem Sat Aug 30 19:49:53 2003 414665 /boot/vmlinuz-2.4.20-20.8bigmem [ output deleted ]
If I had a photograph of you... something to remind me...
在Linux和Unix上创建文件系统镜像的最通常的命令是dd。 dd命令按位从输入中读取,并保存在输出中。dd不显示进度,因此如果是输入的块同输出块大小不相同的时候就会非常慢。比dd更友好的是sdd[11],它就没有这些缺点。sdd可以显示当前的统计,也可以显示当前的进度。
在使用dd来制作文件系统镜像之前,可以先用工具创建需要镜像的文件系统的hash。假设在Linux平台上要创建/dev/hda的镜像,可以运行md5sum /dev/hda,然后开始dd。 dd完成后,对保存的镜像运行相同的工具。如果这些值不匹配,应该检查为什么出现了差异。在openBSD和Solaris上进行应急响应的时候,应该用raw device。
对于Linux,工具e2image可以用来创建ext2和ext3文件系统的镜像。e2image只解释需要被镜像的文件系统,而不是保存原始bit。e2image就不能保存那种聪明的攻击者存储在磁盘上的文件系统结构之外的数据。 e2image可以创建“raw”和“nomal”镜像,这两种方法都可以节约空间。因此,用e2image创建的镜像同硬盘上的文件系统有不同的hash,这很难让你对捕获的数据进行断言。这导致e2image在取证上,依然是不能替代dd的。
另一个创建系统镜像的工具是partimage[12],可以将镜像文件通过ssl传输到一个partimage服务器上,当前可以支持ext2,ext3,ReiserFS,JFS,和XFS,也支持FAT16/32和HPFS(OS/2),并且正在逐步增加支持UFS(Solaris, *BSD), HFS(MaxOS)和NTFS。
partimage只能镜像被使用的分区块,因此跟e2image一样,用partimage制作的镜像并不能精确地反映镜像制作的时候磁盘的真实状态。这跟流行的PC产品ghost一样可以创建镜像,但是不适合于取证。在面对很严重的状态下,在使用ghost之前,应该先阅读手册,确信是否适合你使用。
可能你要问,为什么在这篇文章中介绍这些不适合于取证的工具。这是基于下面的原因:
当选择工具[13]来创建取证镜像的时候,所选用的工具必须能够精确反映创建镜像的时候磁盘的真实状态。
当制作文件系统镜像的时候,你需要理解工具作者是怎么理解“image”的。可以用下面方法进行测试:
1,离线测试计算机的文件系统 2,对包含文件系统的设备,运行md5sum或者执行SHA1的工具 3,用工具制作镜像 4,对镜像执行md5sum或者SHA1的工具
如果指纹不匹配,那么就不要在取证中用该工具。
Would you like some file system to go with that debugger?
类似ls, stat,和find这样的命令,并不能对需要分析的文件系统提供足够的可见度。也许你想处理用dd创建的文件系统镜像,你可能担心被安装了rootkit,而ls可能已经被替换了,或者有些东西已经被删除,但还可以恢复,或者在文件系统之外还有一些有用的数据。
这些系统都有文件系统调试器,在OpenBSD和Solaris上这个调试器就是fsdb。Solaris的调试器最复杂,需要花些时间去了解怎么使用。OpenBSD上的fsdb和对ext2,ext3的debugfs,都可以通过help得到足够的帮助。对于其他一些流行的Linux文件系统比如JFS,ReiserFS,还没有交互的文件系统调试器。xfs_db可以支持XFS。但是本文不讨论它,因为XFS还不是一个广泛使用的文件系统。
Linux可以加载外来的文件系统,对于只读取证非常有用。*BSD的ffs和Solaris的ufs可以用核心模块的ufs来加载。Linux上的文件系统,如ext2,ext3, JFS, ReiserFS和XFS都可以加载,MSDOS(fat16), fat32和大多数的NTFS镜像也支持。但是Linux没有对这些外来文件系统的文件系统调试器。
可以知道下面的命令来找出正在运行的Linux支持的文件系统:find /lib/modules/`uname -r`/kernel/fs/* -type f|grep -v 'nls\/'。 要察看当前装载了哪些文件系统,可以用:grep -v '^nodev' /proc/filesystems. 要了解更多信息,可以看mount(8)
要以只读模式加载镜像,可以使用:mount -t ext2 -o ro,loop=/dev/loop0 /var/tmp/2003_02_17_attack.bin /mnt. 现在可以用工具来检查加载的文件系统了。在检查镜像的时候,你会改变那些正在操作的目录或者文件的访问时间。这些改变只在内存中。一定要记住,用-o以只读属性加载镜像,这样那些改变就不会直接影响到镜像文件。而且,最好对镜像的拷贝进行操作。可以用md5sum来确信拷贝和原始镜像文件是一样的。对拷贝进行操作能保证原始镜像不会被修改。可以在mount(8)察看更多的关于loop 设备的信息。
mounting a file system image in Linux: ##== ##== mount the image read-only so that the image doesn't change on disk # mount -o ro,loop=/dev/loop0 /var/space/images/2003_02_17_linux.bin /mnt ##== ##== list of files # ls -la /mnt total 146 drwxr-xr-x 19 root root 1024 Feb 17 2003 . drwxr-xr-x 19 root root 4096 Sep 12 11:55 .. -rw-r--r-- 1 root root 0 Sep 12 11:55 .autofsck -rw------- 1 root root 186 Sep 6 19:58 .bash_history drwxr-xr-x 2 root root 2048 Feb 8 2003 bin drwxr-xr-x 3 root root 1024 Sep 6 19:59 boot drwxr-xr-x 20 root root 116736 Feb 17 2003 dev drwxr-xr-x 41 root root 3072 Sep 12 14:13 etc [ output deleted ] ##== ##== unmount /mnt # umount /mnt
可以用debugfs <path_to_image>来执行debugfs。如果不太了解,可以用help察看debugfs的帮助。如果还不够,就用man debugfs。 debugfs以只读模式开始,因此几乎不会对镜像文件有改变。但是,还是尽量对镜像拷贝来操作,而把原始镜像放安全点。下面是一个使用debugfs的实例:
using debugfs on an ext2 file system image in Linux: ##== ##== # debugfs /var/space/images/2003_02_17_openbsd_attack.bin debugfs 1.27 (8-Mar-2002) ##== show file system statistics debugfs: stats Filesystem volume name: Last mounted on: Filesystem UUID: 93bfa3ee-d684-4d07-a5d0-1654f488aabd Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: filetype sparse_super Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 65536 Block count: 262144 Reserved block count: 13107 Free blocks: 214567 Free inodes: 57335 First block: 1 Block size: 1024 Fragment size: 1024 Blocks per group: 8192 Fragments per group: 8192 Inodes per group: 2048 Inode blocks per group: 256 Last mount time: Fri Jan 9 14:13:42 2003 Last write time: Fri Feb 17 23:13:04 2003 Mount count: 1 Maximum mount count: 27 Last checked: Fri Jan 9 14:13:35 2003 Check interval: 15552000 (6 months) Next check after: Wed Jul 9 14:13:35 2003 Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 128 Group 0: block bitmap at 3, inode bitmap at 4, inode table at 5 7928 free blocks, 2033 free inodes, 3 used directories [output deleted] ##== print the contents of the current inode in directory format debugfs: ls -l 2 40755 (2) 0 0 1024 17-Feb-2003 23:13 . 2 40755 (2) 0 0 1024 17-Feb-2003 23:13 .. 4097 40700 (2) 0 0 1024 8-Feb-2003 15:17 lost+found 8193 40755 (2) 0 0 116736 17-Feb-2003 23:13 dev 57345 40755 (2) 0 0 1024 8-Feb-2003 16:20 var 43010 41755 (2) 0 0 1024 17-Feb-2003 23:13 tmp 47106 40755 (2) 0 0 3072 17-Feb-2003 11:55 etc [ output deleted ]
##== show inode information for etc debugfs: stat etc Inode: 47106 Type: directory Mode: 0755 Flags: 0x0 Generation: 461325 User: 0 Group: 0 Size: 3072 File ACL: 0 Directory ACL: 0 Links: 41 Blockcount: 6 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x3f61d525 -- Fri Feb 17 14:16:05 2003 atime: 0x3f61d4ff -- Fri Feb 17 14:15:27 2003 mtime: 0x3f61d496 -- Fri Feb 17 14:13:42 2003 BLOCKS: (0):188678, (1):189498, (2):189746 TOTAL: 3
##== chdir into directory inode etc debugfs: cd etc ##== show inode information for passwd debugfs: stat passwd Inode: 47121 Type: regular Mode: 0644 Flags: 0x0 Generation: 461394 User: 0 Group: 0 Size: 1282 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 4 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x3f61d505 -- Fri Feb 17 14:50:04 2003 atime: 0x3f61d4b2 -- Fri Feb 17 23:14:10 2003 mtime: 0x3e5e259c -- Thu Feb 17 14:50:04 2003 BLOCKS: (0-1):188692-188693 TOTAL: 2
##== dump the contents of inode that corresponds to passwd debugfs: cat passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin [ output deleted ] debugfs: quit
在OpenBSD上会多些步骤,在加载之前,镜像需要被配置在vnode磁盘设备上,下面是一个实例:
mounting a file system image in OpenBSD: ##== ##== associate the image with the vnode pseudo disk device # vnconfig -v -c svnd0 /var/space/images/2003_02_17_openbsd_attack.bin svnd0: 7277544448 bytes on /var/space/images/2003_02_17_openbsd_attack.bin ##== ##== mount the image read-only so that the image doesn't change on disk # mount -o ro /dev/svnd0c /mnt ##== ##== mount the image read-only so that the image doesn't change on disk # ls -la /mnt total 9026 drwxr-xr-x 14 root wheel 512 Nov 4 2002 . drwxr-xr-x 14 root wheel 512 Nov 4 2002 .. -rw-r--r-- 2 root wheel 685 Nov 4 2002 .cshrc -rw-r--r-- 2 root wheel 179 Nov 4 2002 .profile drwxr-xr-x 2 root wheel 512 Oct 4 2002 altroot drwxr-xr-x 2 root wheel 1024 Oct 4 2002 bin -r-xr-xr-x 1 root wheel 53248 Nov 4 2002 boot -rw-r--r-- 1 root wheel 4515116 Nov 4 2002 bsd drwxr-xr-x 4 root wheel 19968 Sep 12 11:56 dev drwxr-xr-x 19 root wheel 2048 Mar 28 12:44 etc [ output deleted ] ##== ##== unmount the image # umount /mnt ##== ##== dis-associate the image from the vnode pseudo disk device # vnconfig -v -u svnd0 svnd0: cleared
fsdb是OpenBSD的FFS(fast file system)编辑器。 fsdb没有只读属性,因此镜像拷贝在这里就更重要了。而且在fsdb中的cd命令也可能跟ci命令一样有写操作,这会改变[active]inode。
using fsdb on a file system image in OpenBSD: ##== ##== associate the image with the vnode pseudo disk device # vnconfig -vc svnd0 /var/space/images/2003_02_17_openbsd_attack.bin svnd0: 7277544448 bytes on /var/space/images/2003_02_17_openbsd_attack.bin ##== ##== start fsdb on /dev/svnd0c # fsdb -f /dev/rsvnd0c ** /dev/rsvnd0c ** File system is already clean Editing file system `/dev/rsvnd0c' Last Mounted on /mnt current inode: directory I=2 MODE=40755 SIZE=512 MTIME=Nov 4 19:49:30 2002 [0 nsec] CTIME=Nov 4 19:49:30 2002 [0 nsec] ATIME=Apr 11 14:06:57 2003 [0 nsec] OWNER=root GRP=wheel LINKCNT=14 FLAGS=0 BLKCNT=2 GEN=e32f2a77 fsdb (inum: 2)> ls slot 0 ino 2 reclen 12: directory, `.' slot 1 ino 2 reclen 12: directory, `..' slot 2 ino 0 reclen 16: regular, `boot' slot 3 ino 7488 reclen 16: directory, `altroot' slot 4 ino 33216 reclen 12: directory, `bin' slot 5 ino 14016 reclen 12: directory, `dev' slot 6 ino 42816 reclen 12: directory, `etc' slot 7 ino 42048 reclen 16: directory, `home' slot 8 ino 59904 reclen 12: directory, `mnt' slot 9 ino 6528 reclen 16: directory, `root' slot 10 ino 5568 reclen 16: directory, `sbin' slot 11 ino 45888 reclen 16: directory, `stand' slot 12 ino 27072 reclen 12: directory, `tmp' slot 13 ino 41472 reclen 12: directory, `usr' slot 14 ino 6336 reclen 12: directory, `var' slot 15 ino 6529 reclen 16: regular, `.cshrc' slot 16 ino 6532 reclen 20: regular, `.profile' slot 17 ino 4 reclen 12: symlink, `sys' slot 18 ino 0 reclen 260: regular, `bsd' fsdb (inum: 2)> cd etc/passwd component `passwd': current inode: regular file I=42860 MODE=100644 SIZE=1033 MTIME=Feb 27 21:38:23 2003 [0 nsec] CTIME=Feb 27 21:38:23 2003 [0 nsec] ATIME=Apr 11 13:49:57 2003 [0 nsec] OWNER=root GRP=wheel LINKCNT=1 FLAGS=0 BLKCNT=4 GEN=4bf628a5 fsdb (inum: 42860)> quit ##== ##== dis-associate the image from the vnode pseudo disk device # vnconfig -vu svnd0 svnd0: cleared
类似OpenBSD,在Solaris上处理镜像也需要多点步骤。Solaris有一个被称为lofi(即 loopback file)的驱动。在用lofiadm之前,核心不会表明lofi模块被安装了,启用lofiadm后,应该找到加载到核心的lofi驱动。用modinfo命令来显示当前加载的核心模块。lofiadm命令包含在SUNWcsu包中,而不需要安装任何其他的包或者工具。下面是一个实例:
mounting a file system image in Solaris: ##== ##== register the image available as a block device via the loopback driver: # lofiadm -a /mnt/images/2003_02_17_attack.bin /dev/lofi/1 ##== ##== verify that the image is registered # lofiadm Block Device File /dev/lofi/1 /var/space/images/2003_02_17_attack.bin ##== ##== mount the image read-only so that the image doesn't change on disk # mount -o ro /dev/lofi/1 /mnt ##== ##== mount the image read-only so that the image doesn't change on disk # ls -la /mnt /mnt: total 586 drwxr-xr-x 21 root root 512 Dec 3 04:10 . drwxr-xr-x 21 root root 512 Dec 3 04:10 .. -rw------- 1 root other 4432 Feb 17 04:25 .sh_history lrwxrwxrwx 1 root root 9 Nov 28 06:07 bin -> ./usr/bin drwxr-xr-x 2 root nobody 512 Nov 28 07:32 cdrom drwxr-xr-x 15 root sys 4096 Feb 17 04:14 dev drwxr-xr-x 4 root sys 512 Nov 28 06:29 devices drwxr-xr-x 41 root sys 3584 Feb 16 17:00 etc [ output deleted ] ##== ##== un-mount the image # umount /mnt ##== ##== unregister the image from the loopback driver # lofiadm -d /dev/lofi/1
fsdb是一个值得花时间的工具。如果你能够掌握这个工具,那么它的命令可能很复杂。最有用的文档是OS提供的fsdb_ufs(1M) man手册。
using fsdb on a file system image in Solaris: ##== ##== register the image available as a block device via the loopback driver: # lofiadm -a /mnt/images/2003_02_17_attack.bin /dev/lofi/1 ##== ##== verify that the image is registered: # lofiadm Block Device File /dev/lofi/1 /mnt/images/2003_02_17_attack.bin ##== ##== browse the image using fsdb: # fsdb /dev/lofi/1 fsdb of /dev/lofi/1 (Read only) -- last mounted on / fs_clean is currently set to FSCLEAN fs_state consistent (fs_clean CAN be trusted) ##== ##== print the super block /dev/lofi/1 > :sb super block: magic 11954 format dynamic time Mon Feb 17 18:36:05 2003 nbfree 605536 ndir 6363 nifree 889612 nffree 8252 ncg 290 ncyl 4631 size 8314960 blocks 8187339 bsize 8192 shift 13 mask 0xffffe000 fsize 1024 shift 10 mask 0xfffffc00 frag 8 shift 3 fsbtodb 1 cpg 16 bpg 3591 fpg 28728 ipg 3392 minfree 1% optim time maxcontig 16 maxbpg 2048 rotdelay 0ms fs_id[0] 0x0 fs_id[1] 0x0 rps 120 ntrak 27 nsect 133 npsect 133 spc 3591 trackskew 0 interleave 1 nindir 2048 inopb 64 nspf 2 sblkno 16 cblkno 24 iblkno 32 dblkno 456 sbsize 5120 cgsize 5120 cgoffset 72 cgmask 0xffffffe0 csaddr 456 cssize 5120 shift 9 mask 0xfffffe00 cgrotor 187 fmod 0 ronly 0 blocks available in each of 8 rotational positions cylinder number 0: [ output deleted ] ##== ##== show current entries in this directory: /dev/lofi/1 > :ls -l /: i#: 2 ./ i#: 2 ../ i#: 2bc0 etc/ i#: 8c02 kernel/ i#: 3 lost+found/ i#: 8c0 usr/ [ output deleted ] ##== ##== set the current block to be examined to block 2bc0 (/etc) and display the ##== information in block 2bc0 as an inode: ##== note that :pwd will still show the current location as / because you're ##== examining data blocks on the file system. You haven't actually left /. ##== To navigate the directory hierarchy, you need to use :cd <some_path> /dev/lofi/1 > 2bc0:inode?i i#: 2bc0 md: d---rwxr-xr-x uid: 0 gid: 3 ln: 29 bs: 8 sz : c_flags : 0 e00
db#0: 65a8 accessed: Tue May 27 04:38:06 2003 modified: Mon May 26 17:00:44 2003 created : Tue May 27 04:38:06 2003 /dev/lofi/1 > :ls -l i#: 2c25 nsswitch.conf i#: 2c21 passwd i#: 2c1e path_to_inst i#: 2c3e pwck@ i#: 2bee rc0@ i#: 6042 rc0.d/ i#: 2bef rc1@ i#: 6901 rc1.d/ i#: 2bf0 rc2@ i#: 71c2 rc2.d/ i#: 2bf1 rc3@ i#: 7a82 rc3.d/ i#: 2bf2 rc5@ i#: 2bf3 rc6@ i#: 2bf4 rcS@ i#: 834e rcS.d/ i#: 2c2d shadow i#: 2c27 syslog.conf [ output deleted ] ##== ##== set the current block to be examined to block 2c21 (/etc/passwd) and display the ##== information in block 2c21 as an inode: /dev/lofi/1 > 2c21:inode?i i#: 2c21 md: ----r--r--r-- uid: 0 gid: 3 ln: 1 bs: 2 sz : c_flags : 0 20f
db#0: 6554 accessed: Tue May 27 04:37:58 2003 modified: Thu Nov 28 08:18:06 2002 created : Tue May 27 04:37:58 2003 ##== ##== display the information in current block as ASCII data: ##== you can display the block in hex using: 0:db:block,*/X /dev/lofi/1 > 0:db:block,*/c 1955000: r o o t : x : 0 : 1 : S u p e r 1955010: - U s e r : / : / s b i n / s h 1955020: \n d a e m o n : x : 1 : 1 : : / 1955030: : \n b i n : x : 2 : 2 : : / u s 1955040: r / b i n : \n s y s : x : 3 : 3 1955050: : : / : \n a d m : x : 4 : 4 : A 1955060: d m i n : / v a r / a d m : \n l 1955070: p : x : 7 1 : 8 : L i n e P r 1955080: i n t e r A d m i n : / u s r 1955090: / s p o o l / l p : \n u u c p : 19550a0: x : 5 : 5 : u u c p A d m i n 19550b0: : / u s r / l i b / u u c p : \n 19550c0: n u u c p : x : 9 : 9 : u u c p 19550d0: A d m i n : / v a r / s p o o 19550e0: l / u u c p p u b l i c : / u s 19550f0: r / l i b / u u c p / u u c i c 1955100: o \n s m m s p : x : 2 5 : 2 5 : 1955110: S e n d M a i l M e s s a g e 1955120: S u b m i s s i o n P r o g 1955130: r a m : / : \n l i s t e n : x : 1955140: 3 7 : 4 : N e t w o r k A d m 1955150: i n : / u s r / n e t / n l s : 1955160: \n n o b o d y : x : 6 0 0 0 1 : 1955170: 6 0 0 0 1 : N o b o d y : / : \n 1955180: n o a c c e s s : x : 6 0 0 0 2 1955190: : 6 0 0 0 2 : N o A c c e s s 19551a0: U s e r : / : \n n o b o d y 4 19551b0: : x : 6 5 5 3 4 : 6 5 5 3 4 : S 19551c0: u n O S 4 . x N o b o d y : 19551d0: / : \n k r h : x : 1 1 1 9 : 1 1 19551e0: 1 9 : K r 4 D H a X 0 R y o 19551f0: : / e x p o r t / h o m e / k r 1955200: h : / u s r / b i n / k s h \n [ output deleted ] ##== ##== unregister the image from the loopback driver: # lofiadm -d /dev/lofi/1
有时也需要察看镜像的原始信息,而不是经过文件系统调试器解释过的。这里有几种这样的工具来达到目的。
十六进制编辑器,如hexedit,这个工具作为了Redhat的一部分,也可以在OpenBasd中安装(/usr/ports)[1]。如果没有十六进制编辑器,也可以用emacs或者vim。用emacs <image_name>可以察看镜像,使用'Esc-x toggle-read-only'以只读模式使用。要改变到十六进制编辑器,则使用'Esc-x hexl-mode',要退出,则用'Ctrl-x Ctrl-c'. 要察看emacs的更多信息,可以用'Ctrl-h t'来察看emacs手册。
vim的十六进制编辑支持能力相对emacs来说就差多了。以只读模式而没有交换文件启动vim,可以用:vim -nRb <image_name>。然后输入'Esc:%!xxd'转换文件显示为十六进制。退出则输入'esc:q!'。可以用F1键察看vim的帮助。
因为RAM和swap是有限的,因此也限制了编辑器察看大文件。一旦系统开始交换swap,会话就会慢下来。可以用split和csplit将文件系统镜像分成多个文件。你进行的改变越多(分文件,压缩),那么下结论就更需要小心。
如果emacs和vim不可用,那么对于Solaris可以使用od,并跟上less,more来作页显示。OpenBSD,Redhat,Solaris都有pg.od 。od可以以多种格式导出数据。 od -vxca以十六进制导出数据,并以C类型显示字符,和它们的ASCII字符。
Transferring data from the compromised host
如果需要在创建取证镜像,从在线主机中传输出来,有一些问题需要考虑: * 传输要尽可能小地保证文件系统不会被干扰 * 要通过安全的隧道传输到可信主机 * 不应该运行有问题主机的程序,而应该从CD中运行 * 如果调查需要法律介入,那么就应该遵循法律调查员的步骤流程 * 如果在使用存储数据主机的认证信任证书,那么,有可能攻击者也在用或者盗取你的信任书。
有多种办法可以保存最重要的数据。可以用HUB或者交叉线传输,或者使用ssh或者用其他工具通过TLS/SSL传输。
将需要分析的被入侵的主机连接到保存取证数据的安全主机所在的私有网络,这种办法有一些缺陷: * 一旦主机不再连,那么其他远程主机的连接也丢失了。 * 很难能再观察攻击者的行为 * 观察攻击者安装的程序也会更困难。比如攻击者安装客户端同远程主机连接,当远程主机无法通讯的时候,就很难检查客户端-服务器端之间的交互。 * 因为攻击者无法再连接主机,要指出攻击者怎么连接主机也会更困难。
总之,在作出判断之前,还需要有一些需要权衡考虑计划的地方。 1、建立物理层。 * 用交叉线连接信息中心NIC * 通过HUB连接两个NIC 2、在受入侵主机的相同IP网络架设取证数据存储服务器 3、用netcat和dd传输取证数据到存储服务器。
moving data with dd and netcat: sechost# nc -lp 8091 > <save_file> ##== use a tcp over ethernet friendly block size of 1460 hckdhost# dd if=/dev/hda bs=1460|nc -w10 <sechost> 8091 sechost# od -xvca <save_file>|less
另外一个工具是socat[6],这个工具相对netcat来说功能更多,它可以用多种方式传输数据。注意:下面命令都使用了ignoreof选项。
moving data via socat: ##== use a tcp over ethernet friendly block size of 1460 sechost# /usr/local/socat/bin/socat -b 1460 -t5 OPEN:/dev/hda,ignoreeof,rdonly TCP4:<sechost>:8091 hckdhost# /usr/local/socat/bin/socat -b 1460 -t5 TCP4-LISTEN:8091 OPEN:>save_file<,create,excl,largefile,ignoreeof sechost# od -xvca <save_file>|less
如果不愿意或者不能把主机离线,可以用ssh安全传输数据。下面的脚本将当前的网络连接状态,当前的进程列表,多个系统信息以及文件系统镜像保存在远程主机,
example script for moving data to a secure host via ssh: #!/bin/bash
# This is a quick hack for demonstration purpose only. It needs # to be adapted to your environment. This script works on Linux. # YMMV elsewhere.
rem_host="192.168.27.23"
ssh="ssh forensics@${rem_host}"
# get uname -a, uptime, and Debian or RedHat version info echo -e `uname -a` "\n" `uptime` "\n" `[ -s /etc/debian_version ] && echo Debian $(cat /etc/debian_version) || cat /etc/redhat-release` | ${ssh} "dd of=/var/tmp/incidents/sysinfo"
# save process information ps auwwx | ${ssh} "dd of=/var/tmp/incidents/processes_bsd" ps -eflyc | ${ssh} "dd of=/var/tmp/incidents/processes_sysv"
# save list of open files lsof | ${ssh} "dd of=/var/tmp/incidents/lsof"
# save networking information netstat -A INET -anv | ${ssh} "dd of=/var/tmp/incidents/netstat_infos" lsof -Pni | ${ssh} "dd of=/var/tmp/incidents/lsofnet_infos"
# save loaded modules # use modinfo on Solaris, modstat on OpenBSD lsmod | ${ssh} "dd of=/var/tmp/incidents/modules"
# wtmp info from last # snagging /var/log/[wu]tmp* might not be bad idea last | ${ssh} "dd of=/var/tmp/incidents/last"
# info from process accounting # snagging /var/account/* might not be a bad idea # lastcomm is used here, dump-acct can work too # system accounting (sar) if enable can be useful too. files are usually ing # /var/log/sysstat lastcomm | ${ssh} "dd of=/var/tmp/incidents/last"
# save /etc and logs tar cvjf - /etc /var/log/* | ${ssh} "dd of=/var/tmp/incidents/files_and_logs.tar.bz2"
# use mount to determine currently mounted drives to image. This might need # tweaking depending on your system, so that it only picks up the drives you want. # Is compressing with bzip2 ok for forensics in your world? Since you're applying # a transform before taking an md5sum, it's possible it could cause an issue. Consult # LE or Legal. # # This doesn't handle swap if swap lives on a drive that isn't in the list that # mount generates. Use 'swapon -s'. # # bzip2 can run on whichever machine is faster, or it can be used before the # data goes over the network. If your network is fast enough, bziping on the remote # host is a good idea to conserve space. Software compression can take more time than # it takes to move uncompressed data across a network, if the network is fast enough. # In these situations compress only if you're worried about space, or compress after # the transfer is done. for drive in `mount |grep '^\/dev.* (rw'|awk '{print $1}'|sed 's/[0-9]\+$//'|sort|uniq` do drive_name=`basename ${drive}` dd if=${drive} |${ssh} "bzip2 -9c|dd of=/var/tmp/incidents/${drive_name}.raw.bz2" done
另一种安全传输信息的方法是使用socat[16]。socat目前不支持接受TLS/SSL连接,如果要用这种方式,可以使用stunnel[17]来代替。
下面的步骤表示怎么用socat和stunnel来传输数据: 1、创建自签名证书[18] 2、将diffe-hellman 参数附加到自签名证书 3、用cert的hash创建到cert的symlink 4、编辑主机上的hosts.allow,以便合适的主机可以连接 5、启动stunnel,并对每个接入的连接执行frecv.pl 6、用socat发送需要的文件。
moving data using socat and stunnel: ##== 1 sechost# openssl req -new -x509 -nodes -days 365 -out stunnel.pem -keyout stunnel.pem ##== 2 sechost# dd if=/dev/urandom count=8 |openssl dhparam 512 >> stunnel.pem ##== 3 sechost# ln -sf stunnel.pem `openssl x509 -noout -hash < stunnel.pem`.0 ##== 4 sechost# vi /etc/hosts.allow ##== 5 sechost# stunnel -fd <sechost>:9001 -l ./frecv.pl -p stunnel.pem -P none ##== use a tcp over ethernet friendly block size of 1460 ##== 6 hckdhost# /usr/local/socat/bin/socat -b 1460 -t5 OPEN:/dev/hda,ignoreeof,rdonly OPENSSL:<sechost>:9001 sechost# od -xvca <save_file>|less
在上面的示例中,stunnel执行frecv.pl程序。dd来写流数据,但是dd不能很聪明地创建一个文件名,如果stunnel重复执行dd就会覆盖先前保存的文件。frecv.pl就创建随机的文件名,并且用file来猜测后面写入的数据类型。它写入相关信息到一个描述文件来帮助取证调查员理解他们要处理的是什么数据。frecv.pl的一个协同程序是fsend.l,它发送文件或者执行一个命令,并发送结果给frecv.pl,而且也创建hash来验证数据是完整无误的。下面的地址可以下载到这两个脚本。[Further Study and Resourses: http://www.securityfocus.com/infocus/1738#furtherstudy]
在进一步研究和更多资源(Further Study and Resourses) 一节中,可以获得更多的工具和资源。因为Infocus作者和其他的文章也进行了描述,所以这里就不再挨个介绍了。
总结
本文覆盖了一些在进行调查取证检查文件系统的时候用到的工具。一定要使用多种工具来验证某个工具的显示结果。如果要用到ls,最好是先用find -ls来验证一下。一定要使用强hash算法比如MD5或SHA1的工具。确认在不离线情况下移动数据的时候,要保证这些数据的安全。创建有效的事件响应处理流程更能帮助你规范地收集信息。保持技术和经验领先趋势,你的调查就更容易!
关于作者:
Holt Sorenson 是 The Shmoo Group [http://www.shmoo.com/]的成员。他处理了多起网络和计算机安全案例。
(译注:作者的介绍就不翻译完了,真对不住。下面的内容,因为文本COPY的原因,具体连接地址请参考原文)
References
[1] Acquiring/Installing software
OpenBSD ports system FreeBSD ports system Freeware for Solaris HOWTO install packages on a Debian system Installing packages on a RedHat system GNU binutils (readelf) lsof top sudo
[2] CD-ROM and Floppy distributions
F.I.R.E. (Forensic and Incident Response Environment) Bootable CD Knoppix Linux How to Make a Bootable, Full System OpenBSD CD-ROM LNX-BBC mini-linux distribution Google's Tiny Linux distributions list
[3] Package Formats
Debian Linux (deb) package format RedHat Linux (RPM) package format Solaris package format packages on OpenBSD: [1], [2] package format comparisons
[4] OpenBSD's mtree
mtree (OpenBSD 3.3)
[5] Hash functions
An Introduction to OpenSSL, Part One: Cryptographic Functions, 4th section RSA Labs FAQ Internet Encyclopedia - Hash functions The MD5 hash function algorithm The Secure Hash Standard: SHA1 and SHA-256...512,
[6] File-system integrity verification tools
AIDE integrit Osiris tripwire (open source), tripwire (commercial)
[7] changedfiles, dnotify, and FAM
changedfiles dnotify FAM
[8] shash
shash lib mhash (shash dependency)
[9] Creating file systems for experimentation
Linux create a file that is about the size of a file system that you'd like to test: dd if=/dev/zero of=/var/tmp/testfs bs=1048576 count=<number of MB> create the file system: mke2fs -m0 /var/tmp/testfs turn off forced fsck: tune2fs -c 0 /var/tmp/testfs mount the file system or use debugfs: mount -o loop=/dev/loop0 /var/tmp/testfs /mnt debugfs /var/tmp/testfs unmount the file system if necessary: umount /mnt OpenBSD create a file that is about the size of a file system that you'd like to test using: dd if=/dev/zero of=/var/tmp/testfs bs=1048576 count=<number of MB> configure the pseudo file system as vnode disk device: vnconfig -v -c svnd0 /var/tmp/testfs create the file system: newfs /dev/rsvnd0c mount the pseudo file system or use fsdb: mount /dev/svnd0c /mnt fsdb -f /dev/rsvnd0c unmount the file system if necessary: umount /mnt unconfigure the vnode disk device: vnconfig -v -u svnd0 Solaris create a file that is about the size of a file system that you'd like to test: dd if=/dev/zero of=/var/tmp/testfs bs=1048576 count=<number of MB> register the file system with the loopback device driver: lofiadm -a /var/tmp/testfs create the file system: newfs /dev/lofi/1 mount the file system or use fsdb: mount /dev/lofi/1 /mnt fsdb /dev/lofi/1 unregister the file system from the loopback device driver: lofiadm -d /dev/lofi/1 unmount the file system if necessary: umount /mnt [10] GNU Coreutils
GNU file utilities GNU core utilities
[11] Shily's dd
sdd (schily dd)
[12] Partition Image
partimage - Partition Image
[13] Forensics Tools
September 2000 Market Survey Computer Forensics Open Source Digital Forensic Tools: The Legal Argument Gatekeeping Out Of The Box: Open Source Software As A Mechanism To Assess Reliability For Digital Evidence
[14] Cross-over cables
Section 12.2 of the comp.dcom.cabling FAQ - 10/100 Ethernet Crossover cable Gigabit Crossover cable map Gigabit Ethernet RJ-45 Port Pinouts (Cisco)
[15] netcat
netcat
[16] socat
socat
[17] stunnel
stunnel stunnel examples stunnel FAQ
[18] OpenSSL
OpenSSL An Introduction to OpenSSL, Part Three: PKI- Public Key Infrastructure
Further Study and Resources
Freeware Forensics Tools for Unix An introduction to the The Coroner's Toolkit Forensics resources (Dan Farmer), Forensics resources (Wietse Venema) The Sleuth Kit Dave Dittrich's Forensics Resources fsend.pl and frecv.pl |