使用開源工具進行 Linux 內存取證
計算機的操作系統和應用使用主內存(RAM)來執行不同的任務。這種易失性內存包含大量關於運行應用、網路連接、內核模塊、打開的文件以及幾乎所有其他的內容信息,但這些信息每次計算機重啟的時候都會被清除。
內存取證 是一種從內存中找到和抽取這些有價值的信息的方式。Volatility 是一種使用插件來處理這類信息的開源工具。但是,存在一個問題:在你處理這些信息前,必須將物理內存轉儲到一個文件中,而 Volatility 沒有這種能力。
因此,這篇文章分為兩部分:
- 第一部分是處理獲取物理內存並將其轉儲到一個文件中。
- 第二部分使用 Volatility 從這個內存轉儲中讀取並處理這些信息。
我在本教程中使用了以下測試系統,不過它可以在任何 Linux 發行版上工作:
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.3 (Ootpa)
$
$ uname -r
4.18.0-240.el8.x86_64
$
注意事項: 部分 1 涉及到編譯和載入一個內核模塊。不要擔心:它並不像聽起來那麼困難。
一些指南:
- 按照以下的步驟。
- 不要在生產系統或你的主要計算機上嘗試任何這些步驟。
- 始終使用測試的虛擬機(VM)來嘗試,直到你熟悉使用這些工具並理解它們的工作原理為止。
安裝需要的包
在開始之前安裝必要的工具。如果你經常使用基於 Debian 的發行版,可以使用 apt-get
命令。這些包大多數提供了需要的內核信息和工具來編譯代碼:
$ yum install kernel-headers kernel-devel gcc elfutils-libelf-devel make git libdwarf-tools python2-devel.x86_64-y
部分 1:使用 LiME 獲取內存並將其轉儲到一個文件中
在開始分析內存之前,你需要一個內存轉儲供你使用。在實際的取證活動中,這可能來自一個被破壞或者被入侵的系統。這些信息通常會被收集和存儲來分析入侵是如何發生的及其影響。由於你可能沒有可用的內存轉儲,你可以獲取你的測試 VM 的內存轉儲,並使用它來執行內存取證。
Linux 內存提取器 (LiME)是一個在 Linux 系統上獲取內存很常用的工具。使用以下命令獲得 LiME:
$ git clone https://github.com/504ensicsLabs/LiME.git
$
$ cd LiME/src/
$
$ ls
deflate.c disk.c hash.c lime.h main.c Makefile Makefile.sample tcp.c
$
構建 LiME 內核模塊
在 src
文件夾下運行 make
命令。這會創建一個以 .ko 為擴展名的內核模塊。理想情況下,在 make
結束時,lime.ko
文件會使用格式 lime-<your-kernel-version>.ko
被重命名。
$ make
make -C /lib/modules/4.18.0-240.el8.x86_64/build M="/root/LiME/src" modules
make[1]: Entering directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
<< 刪節 >>
make[1]: Leaving directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
strip --strip-unneeded lime.ko
mv lime.ko lime-4.18.0-240.el8.x86_64.ko
$
$
$ ls -l lime-4.18.0-240.el8.x86_64.ko
-rw-r--r--. 1 root root 25696 Apr 17 14:45 lime-4.18.0-240.el8.x86_64.ko
$
$ file lime-4.18.0-240.el8.x86_64.ko
lime-4.18.0-240.el8.x86_64.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=1d0b5cf932389000d960a7e6b57c428b8e46c9cf, not stripped
$
載入LiME 內核模塊
現在是時候載入內核模塊來獲取系統內存了。insmod
命令會幫助載入內核模塊;模塊一旦被載入,會在你的系統上讀取主內存(RAM)並且將內存的內容轉儲到命令行所提供的 path
目錄下的文件中。另一個重要的參數是 format
;保持 lime
的格式,如下所示。在插入內核模塊之後,使用 lsmod
命令驗證它是否真的被載入。
$ lsmod | grep lime
$
$ insmod ./lime-4.18.0-240.el8.x86_64.ko "path=../RHEL8.3_64bit.mem format=lime"
$
$ lsmod | grep lime
lime 16384 0
$
你應該看到給 path
命令的文件已經創建好了,而且文件大小與你系統的物理內存(RAM)大小相同(並不奇怪)。一旦你有了內存轉儲,你就可以使用 rmmod
命令刪除該內核模塊:
$
$ ls -l ~/LiME/RHEL8.3_64bit.mem
-r--r--r--. 1 root root 4294544480 Apr 17 14:47 /root/LiME/RHEL8.3_64bit.mem
$
$ du -sh ~/LiME/RHEL8.3_64bit.mem
4.0G /root/LiME/RHEL8.3_64bit.mem
$
$ free -m
total used free shared buff/cache available
Mem: 3736 220 366 8 3149 3259
Swap: 4059 8 4051
$
$ rmmod lime
$
$ lsmod | grep lime
$
內存轉儲中是什麼?
這個內存轉儲文件只是原始數據,就像使用 file
命令可以看到的一樣。你不可能通過手動去理解它;是的,在這裡邊有一些 ASCII 字元,但是你無法用編輯器打開這個文件並把它讀出來。hexdump
的輸出顯示,最初的幾個位元組是 EmiL
;這是因為你的請求格式在上面的命令行中是 lime
:
$ file ~/LiME/RHEL8.3_64bit.mem
/root/LiME/RHEL8.3_64bit.mem: data
$
$ hexdump -C ~/LiME/RHEL8.3_64bit.mem | head
00000000 45 4d 69 4c 01 00 00 00 00 10 00 00 00 00 00 00 |EMiL............|
00000010 ff fb 09 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 b8 fe 4c cd 21 44 00 32 20 00 00 2a 2a 2a 2a 2a |..L.!D.2 ..*****|
00000030 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
00000040 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 20 00 20 |************* . |
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000080 00 00 00 00 00 00 00 00 00 00 00 00 70 78 65 6c |............pxel|
00000090 69 6e 75 78 2e 30 00 00 00 00 00 00 00 00 00 00 |inux.0..........|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
$
部分 2:獲得 Volatility 並使用它來分析你的內存轉儲
現在你有了要分析的示例內存轉儲,使用下面的命令獲取 Volatility 軟體。Volatility 已經用 Python 3 重寫了,但是本教程使用的是用 Python 2 寫的原始的 Volatility 包。如果你想用 Volatility 3 進行實驗,可以從合適的 Git 倉庫下載它,並在以下命令中使用 Python 3 而不是 Python 2:
$ git clone https://github.com/volatilityfoundation/volatility.git
$
$ cd volatility/
$
$ ls
AUTHORS.txt contrib LEGAL.txt Makefile PKG-INFO pyinstaller.spec resources tools vol.py
CHANGELOG.txt CREDITS.txt LICENSE.txt MANIFEST.in pyinstaller README.txt setup.py volatility
$
Volatility 使用兩個 Python 庫來實現某些功能,所以使用以下命令來安裝它們。否則,在你運行 Volatility 工具時,你可能看到一些導入錯誤;你可以忽略它們,除非你正在運行的插件需要這些庫;這種情況下,工具將會報錯:
$ pip2 install pycrypto
$ pip2 install distorm3
列出 Volatility 的 Linux 配置文件
你將要運行的第一個 Volatility 命令列出了可用的 Linux 配置文件,運行 Volatility 命令的主要入口點是 vol.py
腳本。使用 Python 2 解釋器調用它並提供 --info
選項。為了縮小輸出,查找以 Linux 開頭的字元串。正如你所看到的,並沒有很多 Linux 配置文件被列出:
$ python2 vol.py --info | grep ^Linux
Volatility Foundation Volatility Framework 2.6.1
LinuxAMD64PagedMemory - Linux-specific AMD 64-bit address space.
$
構建你自己的 Linux 配置文件
Linux 發行版是多種多樣的,並且是為不同架構而構建的。這就是為什麼配置文件是必要的 —— Volatility 在提取信息前必須知道內存轉儲是從哪個系統和架構獲得的。有一些 Volatility 命令可以找到這些信息;但是這個方法很費時。為了加快速度,可以使用以下命令構建一個自定義的 Linux 配置文件:
移動到 Volatility 倉庫的 tools/linux
目錄下,運行 make
命令:
$ cd tools/linux/
$
$ pwd
/root/volatility/tools/linux
$
$ ls
kcore Makefile Makefile.enterprise module.c
$
$ make
make -C //lib/modules/4.18.0-240.el8.x86_64/build CONFIG_DEBUG_INFO=y M="/root/volatility/tools/linux" modules
make[1]: Entering directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
<< 刪節 >>
make[1]: Leaving directory '/usr/src/kernels/4.18.0-240.el8.x86_64'
$
你應該看到一個新的 module.dwarf
文件。你也需要 /boot
目錄下的 System.map
文件,因為它包含了所有與當前運行的內核相關的符號:
$ ls
kcore Makefile Makefile.enterprise module.c module.dwarf
$
$ ls -l module.dwarf
-rw-r--r--. 1 root root 3987904 Apr 17 15:17 module.dwarf
$
$ ls -l /boot/System.map-4.18.0-240.el8.x86_64
-rw-------. 1 root root 4032815 Sep 23 2020 /boot/System.map-4.18.0-240.el8.x86_64
$
$
要創建一個自定義配置文件,移動回到 Volatility 目錄並且運行下面的命令。第一個參數提供了一個自定義 .zip 文件,文件名是你自己命名的。我經常使用操作系統和內核版本來命名。下一個參數是前邊創建的 module.dwarf
文件,最後一個參數是 /boot
目錄下的 System.map
文件:
$
$ cd volatility/
$
$ zip volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip tools/linux/module.dwarf /boot/System.map-4.18.0-240.el8.x86_64
adding: tools/linux/module.dwarf (deflated 91%)
adding: boot/System.map-4.18.0-240.el8.x86_64 (deflated 79%)
$
現在自定義配置文件就準備好了,所以在前邊給出的位置檢查一下 .zip 文件是否被創建好。如果你想知道 Volatility 是否檢測到這個自定義配置文件,再一次運行 --info
命令。現在,你應該可以在下邊的列出的內容中看到新的配置文件:
$
$ ls -l volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
-rw-r--r--. 1 root root 1190360 Apr 17 15:20 volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
$
$
$ python2 vol.py --info | grep Redhat
Volatility Foundation Volatility Framework 2.6.1
LinuxRedhat8_3_4_18_0-240x64 - A Profile for Linux Redhat8.3_4.18.0-240 x64
$
$
開始使用 Volatility
現在你已經準備好去做一些真正的內存取證了。記住,Volatility 是由自定義的插件組成的,你可以針對內存轉儲來獲得信息。命令的通用格式是:
python2 vol.py -f <memory-dump-file-taken-by-Lime> <plugin-name> --profile=<name-of-our-custom-profile>
有了這些信息,運行 linux_banner
插件來看看你是否可從內存轉儲中識別正確的發行版信息:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_banner --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Linux version 4.18.0-240.el8.x86_64 ([mockbuild@vm09.test.com][4]) (gcc version 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC)) #1 SMP Wed Sep 23 05:13:10 EDT 2020
$
找到 Linux 插件
到現在都很順利,所以現在你可能對如何找到所有 Linux 插件的名字比較好奇。有一個簡單的技巧:運行 --info
命令並抓取 linux_
字元串。有各種各樣的插件可用於不同的用途。這裡列出一部分:
$ python2 vol.py --info | grep linux_
Volatility Foundation Volatility Framework 2.6.1
linux_apihooks - Checks for userland apihooks
linux_arp - Print the ARP table
linux_aslr_shift - Automatically detect the Linux ASLR shift
<< 刪節 >>
linux_banner - Prints the Linux banner information
linux_vma_cache - Gather VMAs from the vm_area_struct cache
linux_volshell - Shell in the memory image
linux_yarascan - A shell in the Linux memory image
$
使用 linux_psaux
插件檢查內存轉儲時系統上正在運行哪些進程。注意列表中的最後一個命令:它是你在轉儲之前運行的 insmod
命令。
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_psaux --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Pid Uid Gid Arguments
1 0 0 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
2 0 0 [kthreadd]
3 0 0 [rcu_gp]
4 0 0 [rcu_par_gp]
861 0 0 /usr/libexec/platform-python -Es /usr/sbin/tuned -l -P
869 0 0 /usr/bin/rhsmcertd
875 0 0 /usr/libexec/sssd/sssd_be --domain implicit_files --uid 0 --gid 0 --logger=files
878 0 0 /usr/libexec/sssd/sssd_nss --uid 0 --gid 0 --logger=files
<< 刪節 >>
11064 89 89 qmgr -l -t unix -u
227148 0 0 [kworker/0:0]
227298 0 0 -bash
227374 0 0 [kworker/u2:1]
227375 0 0 [kworker/0:2]
227884 0 0 [kworker/0:3]
228573 0 0 insmod ./lime-4.18.0-240.el8.x86_64.ko path=../RHEL8.3_64bit.mem format=lime
228576 0 0
$
想要知道系統的網路狀態嗎?運行 linux_netstat
插件來找到在內存轉儲期間網路連接的狀態:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_netstat --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
UNIX 18113 systemd/1 /run/systemd/private
UNIX 11411 systemd/1 /run/systemd/notify
UNIX 11413 systemd/1 /run/systemd/cgroups-agent
UNIX 11415 systemd/1
UNIX 11416 systemd/1
<< 刪節 >>
$
接下來,使用 linux_mount
插件來看在內存轉儲期間哪些文件系統被掛載:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_mount --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec
cgroup /sys/fs/cgroup/pids cgroup rw,relatime,nosuid,nodev,noexec
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime
/dev/mapper/rhel_kvm--03--guest11-root / xfs rw,relatime
tmpfs /dev/shm tmpfs rw,nosuid,nodev
selinuxfs /sys/fs/selinux selinuxfs rw,relatime
<< 刪節 >>
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,relatime,nosuid,nodev,noexec
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,relatime,nosuid,nodev,noexec
bpf /sys/fs/bpf bpf rw,relatime,nosuid,nodev,noexec
cgroup /sys/fs/cgroup/memory cgroup ro,relatime,nosuid,nodev,noexec
cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,nosuid,nodev,noexec
mqueue /dev/mqueue mqueue rw,relatime
$
好奇哪些內核模塊被載入了嗎?Volatility 也為這個提供了一個插件 linux_lsmod
:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsmod --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
ffffffffc0535040 lime 20480
ffffffffc0530540 binfmt_misc 20480
ffffffffc05e8040 sunrpc 479232
<< 刪節 >>
ffffffffc04f9540 nfit 65536
ffffffffc0266280 dm_mirror 28672
ffffffffc025e040 dm_region_hash 20480
ffffffffc0258180 dm_log 20480
ffffffffc024bbc0 dm_mod 151552
$
想知道哪些文件被哪些進程打開了嗎?使用 linux_bash
插件可以列出這些信息:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_bash --profile=LinuxRedhat8_3_4_18_0-240x64 -v
Volatility Foundation Volatility Framework 2.6.1
Pid Name Command Time Command
-------- -------------------- ------------------------------ ---- 227221 bash 2021-04-17 18:38:24 UTC+0000 lsmod
227221 bash 2021-04-17 18:38:24 UTC+0000 rm -f .log
227221 bash 2021-04-17 18:38:24 UTC+0000 ls -l /etc/zzz
227221 bash 2021-04-17 18:38:24 UTC+0000 cat ~/.vimrc
227221 bash 2021-04-17 18:38:24 UTC+0000 ls
227221 bash 2021-04-17 18:38:24 UTC+0000 cat /proc/817/cwd
227221 bash 2021-04-17 18:38:24 UTC+0000 ls -l /proc/817/cwd
227221 bash 2021-04-17 18:38:24 UTC+0000 ls /proc/817/
<< 刪節 >>
227298 bash 2021-04-17 18:40:30 UTC+0000 gcc prt.c
227298 bash 2021-04-17 18:40:30 UTC+0000 ls
227298 bash 2021-04-17 18:40:30 UTC+0000 ./a.out
227298 bash 2021-04-17 18:40:30 UTC+0000 vim prt.c
227298 bash 2021-04-17 18:40:30 UTC+0000 gcc prt.c
227298 bash 2021-04-17 18:40:30 UTC+0000 ./a.out
227298 bash 2021-04-17 18:40:30 UTC+0000 ls
$
想知道哪些文件被哪些進程打開了嗎?使用 linux_lsof
插件可以列出這些信息:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsof --profile=LinuxRedhat8_3_4_18_0-240x64
Volatility Foundation Volatility Framework 2.6.1
Offset Name Pid FD Path
------------------ ------------------------------ -------- -------- -0xffff9c83fb1e9f40 rsyslogd 71194 0 /dev/null
0xffff9c83fb1e9f40 rsyslogd 71194 1 /dev/null
0xffff9c83fb1e9f40 rsyslogd 71194 2 /dev/null
0xffff9c83fb1e9f40 rsyslogd 71194 3 /dev/urandom
0xffff9c83fb1e9f40 rsyslogd 71194 4 socket:[83565]
0xffff9c83fb1e9f40 rsyslogd 71194 5 /var/log/messages
0xffff9c83fb1e9f40 rsyslogd 71194 6 anon_inode:[9063]
0xffff9c83fb1e9f40 rsyslogd 71194 7 /var/log/secure
<< 刪節 >>
0xffff9c8365761f40 insmod 228573 0 /dev/pts/0
0xffff9c8365761f40 insmod 228573 1 /dev/pts/0
0xffff9c8365761f40 insmod 228573 2 /dev/pts/0
0xffff9c8365761f40 insmod 228573 3 /root/LiME/src/lime-4.18.0-240.el8.x86_64.ko
$
訪問 Linux 插件腳本位置
通過讀取內存轉儲和處理這些信息,你可以獲得更多的信息。如果你會 Python,並且好奇這些信息是如何被處理的,可以到存儲所有插件的目錄,選擇一個你感興趣的,並看看 Volatility 是如何獲得這些信息的:
$ ls volatility/plugins/linux/
apihooks.py common.py kernel_opened_files.py malfind.py psaux.py
apihooks.pyc common.pyc kernel_opened_files.pyc malfind.pyc psaux.pyc
arp.py cpuinfo.py keyboard_notifiers.py mount_cache.py psenv.py
arp.pyc cpuinfo.pyc keyboard_notifiers.pyc mount_cache.pyc psenv.pyc
aslr_shift.py dentry_cache.py ld_env.py mount.py pslist_cache.py
aslr_shift.pyc dentry_cache.pyc ld_env.pyc mount.pyc pslist_cache.pyc
<< 刪節 >>
check_syscall_arm.py __init__.py lsmod.py proc_maps.py tty_check.py
check_syscall_arm.pyc __init__.pyc lsmod.pyc proc_maps.pyc tty_check.pyc
check_syscall.py iomem.py lsof.py proc_maps_rb.py vma_cache.py
check_syscall.pyc iomem.pyc lsof.pyc proc_maps_rb.pyc vma_cache.pyc
$
$
我喜歡 Volatility 的理由是他提供了許多安全插件。這些信息很難手動獲取:
linux_hidden_modules - Carves memory to find hidden kernel modules
linux_malfind - Looks for suspicious process mappings
linux_truecrypt_passphrase - Recovers cached Truecrypt passphrases
Volatility 也允許你在內存轉儲中打開一個 shell,所以你可以運行 shell 命令來代替上面所有命令,並獲得相同的信息:
$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_volshell --profile=LinuxRedhat8_3_4_18_0-240x64 -v
Volatility Foundation Volatility Framework 2.6.1
Current context: process systemd, pid=1 DTB=0x1042dc000
Welcome to volshell! Current memory image is:
file:///root/LiME/RHEL8.3_64bit.mem
To get help, type 'hh()'
>>>
>>> sc()
Current context: process systemd, pid=1 DTB=0x1042dc000
>>>
接下來的步驟
內存轉儲是了解 Linux 內部情況的好方法。試一試 Volatility 的所有插件,並詳細研究它們的輸出。然後思考這些信息如何能夠幫助你識別入侵或安全問題。深入了解這些插件的工作原理,甚至嘗試改進它們。如果你沒有找到你想做的事情的插件,那就寫一個並提交給 Volatility,這樣其他人也可以使用它。
via: https://opensource.com/article/21/4/linux-memory-forensics
作者:Gaurav Kamathe 選題:lujun9972 譯者:RiaXu 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive