攻击取证 取证人员通常是在发现缺陷事件后,或者是为了确定是否发生了“事件”而被叫来的人。他们通常需要受影响机器的 RAM (笔者注: Random Access Memory,随机存取存储器)的快照,以便捕获仅临时存储在内存中的加密密钥或其他信息。幸运的是,一个有才华的开发团队已经创建了一个完整的 Python 框架 Volatility ,它适合这个任务,被称为高级内存取证框架。事件响应者、取证人员和恶意软件分析师也可以将 Volatility 用于其他各种任务,包括检查内核对象、检查和转储进程信息等。
(笔者注: Volatility 是一款开源内存取证框架,能够对导出的内存镜像进行分析,通过获取内核数据结构,使用插件获取内存的详细情况以及系统的运行状态。特点:开源: Python 编写,易于和基于 python 的主机防御框架集成;支持多平台:Windows,Mac,Linux 全支持;易于扩展:通过插件来扩展 Volatility 的分析能力)
尽管 Volatility 是防御方的软件,但任何足够强大的工具都可以用于进攻或防守。我们将使用 Volatility 对目标用户执行侦察,并编写自己的攻击性插件来搜索在虚拟机(VM)上运行的防御能力较弱的进程。
假设你潜入一台机器,发现用户使用虚拟机进行敏感工作。很有可能用户还制作了虚拟机的快照作为安全措施以防出现任何错误问题,这更是好机会。我们将使用 Volatility 内存分析框架来分析快照,以了解 VM 是如何工作的以及哪些进程正在运行。我们还将调查可能存在的漏洞,以便进一步利用这些漏洞进行攻击。
我们开始吧!
安装 Volatility 已经存在了好几年,刚刚经历了一次彻底的改写。现在不仅代码库建立在 Python 3 上,而且整个框架都经过了重构,因此组件也是独立的;运行插件所需的所有情况都是自包含的。
让我们创建一个虚拟环境来处理 Volatility 。对于本例,我们在 Windows 机器上的 PowerShell 终端使用 Python 3。如果您也在 Windows 机器上工作,请确保安装了 git 。你可以在 https://git-scm.com/downloads/ 下载。
1 2 3 4 5 6 7 [1 ] PS> python3 -m venv vol3 PS> vol3/Scripts/Activate.ps1 PS> cd vol3/ [2 ] PS> git clone https://github.com/volatilityfoundation/volatility3.git PS> cd volatility3/ PS> python setup.py install [3 ] PS> pip install pycryptodome
首先,我们创建一个名为 vol3 的新虚拟环境并将其激活[1]。接下来,我们进入虚拟环境目录并克隆 Volatility 3 的GitHub 存储库[2],将其安装到虚拟环境中,最后安装 pycryptodome [3],稍后我们将需要它。
要查看 Volatility 提供的插件和选项列表,请在 Windows 上使用以下命令:
在 Linux 或 Mac 上,使用虚拟环境中的 Python 可执行文件,如下所示:
在本章中,我们将从命令行使用 Volatility ,但是您可能会遇到各种各样的框架。例如,请参阅 Volatility 的 Volumetric 项目,一个免费的基于 web 的 Volatility GUI( https://github.com/volatilityfoundation/volumetric/ )。您可以深入到 Volumetric 项目中的代码示例,看看如何在自己的程序中使用 Volatility 。此外,您还可以使用 volshell 接口,它为您提供了对 Volatility 框架的访问,并作为一个普通的交互式 Python shell 工作。
在下面的示例中,我们将使用 Volatility 命令行。为了节省空间,将输出编辑为仅显示已讨论的输出,因此请注意,您的输出将有更多的行和列。
现在让我们深入研究一些代码,看看框架内部:
1 2 3 4 5 6 7 8 9 PS> cd volatility/framework/plugins/windows/ PS> ls _init__.py driverscan.py memmap.py psscan.py vadinfo.py bigpools.py filescan.py modscan.py pstree.py vadyarascan.py cachedump.py handles.py modules.py registry/ verinfo.py callbacks.py hashdump.py mutantscan.py ssdt.py virtmap.py cmdline.py info.py netscan.py strings.py dlllist.py lsadump.py poolscanner.py svcscan.py driverirp.py malfind.py pslist.py symlinkscan.py
这个清单显示了 Windows plugin 目录中的 Python 文件。我们强烈建议您花一些时间查看这些文件中的代码。您将看到形成 Volatility 插件结构的循环模式。这将有助于你理解这个框架,但更重要的是,它会让你了解一个防御者的心态和意图。通过了解防御者的能力以及他们是如何完成目标的,你将使自己成为一个更有能力的黑客,并更好地了解如何保护自己不被发现。
现在我们已经准备好了分析框架,我们需要一些内存图像来分析。最简单的方法是拍摄自己的 Windows 10 虚拟机的快照。
首先,打开 Windows 虚拟机并启动一些进程(例如,记事本、计算器和浏览器);我们将检查内存并跟踪这些进程是如何启动的。然后,使用您选择的虚拟机监控程序拍摄快照。在管理程序存储虚拟机的目录中,您将看到名称以 .vmem 或 .mem 结尾的新快照文件。让我们开始侦察吧!
请注意,您还可以在网上找到许多内存图像。本章中我们看到的一个图像是 PassMark Software 提供的([https://www .osforensics.com/tools/volatility-workbench.html/](https://www .osforensics.com/tools/volatility-workbench.html/))。Volatility Foundation 网站也有一些图像可以使用(https://github.com/volatilityfoundation/volatility/wiki/Memory-Samples/ )
通用侦察 让我们大致了解一下我们正在分析的机器。 windows.info 插件可以显示内存示例的操作系统和内核信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [1 ] PS>vol -f WinDev2007Eval-Snapshot4 .vmem windows.info Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner Variable Value Kernel Base 0 xf80067a18000 DTB 0 x1aa000 primary 0 WindowsIntel32e memory_layer 1 FileLayer KdVersionBlock 0 xf800686272f0 Major/Minor 15.19041 MachineType 34404 KeNumberProcessors 1 SystemTime 2020 -09 -04 00 :53 :46 NtProductType NtProductWinNt NtMajorVersion 10 NtMinorVersion 0 PE MajorOperatingSystemVersion 10 PE MinorOperatingSystemVersion 0 PE Machine 34404
我们使用 -f 选项和要使用的 Windows 插件, windows.info ,指定快照文件名[1]。 Volatility 读取并分析内存文件,并输出有关此 Windows 计算机的通识信息。我们可以看到,我们正在处理一个 Windows 10.0 虚拟机 ,它有一个单处理器和一个内存层。
在查看插件代码时,您可能会发现在内存映像文件上尝试几个插件很有实践教育意义。花时间阅读代码并查看相应的输出将向您展示代码应该如何工作以及防御者大体上的心态。
接下来是 registry.printkey 插件,可以打印注册表中某个键的值。注册表有大量有价值的信息, Volatility 提供了一种找到我们想要的所有值的方法。在这里,我们寻找已安装的服务。键 /ControlSet001/Services 显示 Service Control Manager (服务控制管理器)数据库,其中列出了所有已安装的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.registry.printkey --key 'ControlSet001\Services' Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner ... Key Name Data Volatile \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services .NET CLR Data False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Appinfo False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services applockerfltr False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services AtomicAlarmClock False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Beep False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services fastfat False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services MozillaMaintenance False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services NTDS False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Ntfs False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services ShellHWDetection False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services SQLWriter False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Tcpip False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Tcpip6 False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services terminpt False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services W32Time False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WaaSMedicSvc False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WacomPen False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Winsock False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WinSock2 False \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WINUSB False
此输出显示计算机上已安装服务的列表(因空间原因而缩略了)。
用户侦察 现在让我们对虚拟机的用户进行一些侦察。 cmdline 插件列出了创建快照时每个进程正在运行的命令行参数。这些进程给我们一个关于用户行为和意图的提示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.cmdline Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner PID Process Args 72 Registry Required memory at 0 x20 is not valid (process exited?)340 smss.exe Required memory at 0 xa5f1873020 is inaccessible (swapped)564 lsass.exe C:\Windows\system32\lsass.exe624 winlogon.exe winlogon.exe2160 MsMpEng.exe "C:\ProgramData\Microsoft\Windows Defender\platform\4.18.2008.9-0\ MsMpEng.exe" 4732 explorer.exe C:\Windows\Explorer.EXE4848 svchost.exe C:\Windows\system32\svchost.exe -k ClipboardSvcGroup -p 4920 dllhost.exe C:\Windows\system32\DllHost.exe /Processid:{AB8902B4-09CA -4BB6 -B78D -A8F59079A8D5} 5084 StartMenuExper "C:\Windows\SystemApps\Microsoft.Windows. . ." 5388 MicrosoftEdge. "C:\Windows\SystemApps\Microsoft.MicrosoftEdge_. . ." 6452 OneDrive.exe "C:\Users\Administrator\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background 6484 FreeDesktopClo "C:\Program Files\Free Desktop Clock\FreeDesktopClock.exe" 7092 cmd.exe "C:\Windows\system32\cmd.exe" [1 ]3312 notepad.exe notepad [2 ]3824 powershell.exe "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" 6448 Calculator.exe "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_. . ." 6684 firefox.exe "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" 6432 PowerToys.exe "C:\Program Files\PowerToys\PowerToys.exe" 7124 nc64.exe Required memory at 0 x2d7020 is inaccessible (swapped)3324 smartscreen.ex C:\Windows\System32\smartscreen.exe -Embedding 4768 ipconfig.exe Required memory at 0 x840308e020 is not valid (process exited?)
该列表显示进程 ID 、进程名和命令行以及启动进程的参数。您可以看到,大多数进程都是由系统本身启动的,很可能是在引导时启动的。 cmd.exe [1]和 notepad.exe [2]进程是用户启动进程的典型。
让我们用 pslist 插件更深入地研究正在运行的进程,它列出了拍摄快照时正在运行的进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.pslist Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 4 0 System 0 xa50bb3e6d040 129 - N/A False72 4 Registry 0 xa50bb3fbd080 4 - N/A False6452 4732 OneDrive.exe 0 xa50bb4d62080 25 - 1 True6484 4732 FreeDesktopClo 0 xa50bbb847300 1 - 1 False6212 556 SgrmBroker.exe 0 xa50bbb832080 6 - 0 False1636 556 svchost.exe 0 xa50bbadbe340 8 - 0 False7092 4732 cmd.exe 0 xa50bbbc4d080 1 - 1 False3312 7092 notepad.exe 0 xa50bbb69a080 3 - 1 False3824 4732 powershell.exe 0 xa50bbb92d080 11 - 1 False6448 704 Calculator.exe 0 xa50bb4d0d0c0 21 - 1 False4036 6684 firefox.exe 0 xa50bbb178080 0 - 1 True6432 4732 PowerToys.exe 0 xa50bb4d5a2c0 14 - 1 False4052 4700 PowerLauncher. 0 xa50bb7fd3080 16 - 1 False5340 6432 Microsoft.Powe 0 xa50bb736f080 15 - 1 False8564 4732 python-3 .8.6 -a 0 xa50bb7bc2080 1 - 1 True7124 7092 nc64.exe 0 xa50bbab89080 1 - 1 False3324 704 smartscreen.ex 0 xa50bb4d6a080 7 - 1 False7364 4732 cmd.exe 0 xa50bbd8a8080 1 - 1 False8916 2136 cmd.exe 0 xa50bb78d9080 0 - 0 False4768 8916 ipconfig.exe 0 xa50bba7bd080 0 - 0 False
这里我们看到了实际的进程及其内存偏移量。为了节省空间,所以省略了一些列。下面列出了几个有趣的进程,包括我们在 cmdline 插件的输出中看到的 cmd 和 notepad 进程。
最好将进程看作一个层次结构,这样我们就可以知道是什么进程启动了其他进程。为此,我们将使用到 pstree 插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.pstree Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 4 0 System 0 xa50bba7bd080 129 N/A False* 556 492 services.exe 0 xa50bba7bd080 8 0 False ** 2176 556 wlms.exe 0 xa50bba7bd080 2 0 False ** 1796 556 svchost.exe 0 xa50bba7bd080 13 0 False ** 776 556 svchost.exe 0 xa50bba7bd080 15 0 False ** 8 556 svchost.exe 0 xa50bba7bd080 18 0 False *** 4556 8 ctfmon.exe 0 xa50bba7bd080 10 1 False *** 5388 704 MicrosoftEdge. 0 xa50bba7bd080 35 1 False *** 6448 704 Calculator.exe 0 xa50bba7bd080 21 1 False *** 3324 704 smartscreen.ex 0 xa50bba7bd080 7 1 False ** 2136 556 vmtoolsd.exe 0 xa50bba7bd080 11 0 False *** 8916 2136 cmd.exe 0 xa50bba7bd080 0 0 False **** 4768 8916 ipconfig.exe 0 xa50bba7bd080 0 0 False * 4704 624 userinit.exe 0 xa50bba7bd080 0 1 False ** 4732 4704 explorer.exe 0 xa50bba7bd080 92 1 False *** 6432 4732 PowerToys.exe 0 xa50bba7bd080 14 1 False **** 5340 6432 Microsoft.Powe 0 xa50bba7bd080 15 1 False *** 7364 4732 cmd.exe 0 xa50bba7bd080 1 - False **** 2464 7364 conhost.exe 0 xa50bba7bd080 4 1 False *** 7092 4732 cmd.exe 0 xa50bba7bd080 1 - False **** 3312 7092 notepad.exe 0 xa50bba7bd080 3 1 False **** 7124 7092 nc64.exe 0 xa50bba7bd080 1 1 False *** 8564 4732 python-3 .8.6 -a 0 xa50bba7bd080 1 1 True **** 1036 8564 python-3 .8.6 -a 0 xa50bba7bd080 5 1 True
现在我们得到了一个更清晰的画面。每行中的星号表示进程的父子关系。例如, userinit 进程(PID 4704)生成了 explorer.exe 进程。同样, explorer.exe 进程(PID 4732)启动 cmd.exe 进程(PID 7092)。从这个进程中,用户启动了 notepad.exe 和另一个名为 nc64.exe 的进程。
现在让我们用 hashdump 插件检查密码:
1 2 3 4 5 6 7 8 9 10 11 PS> vol -f WinDev2007Eval-7d959ee5 .vmem windows.hashdump Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner User rid lmhash nthash Administrator 500 aad3bXXXXXXaad3bXXXXXX fc6eb57eXXXXXXXXXXX657878 Guest 501 aad3bXXXXXXaad3bXXXXXX 1 d6cfe0dXXXXXXXXXXXc089c0 DefaultAccount 503 aad3bXXXXXXaad3bXXXXXX 1 d6cfe0dXXXXXXXXXXXc089c0 WDAGUtilityAccount 504 aad3bXXXXXXaad3bXXXXXX ed66436aXXXXXXXXXXX1bb50f User 1001 aad3bXXXXXXaad3bXXXXXX 31 d6cfe0XXXXXXXXXXXc089c0 tim 1002 aad3bXXXXXXaad3bXXXXXX afc6eb57XXXXXXXXXXX657878 admin 1003 aad3bXXXXXXaad3bXXXXXX afc6eb57XXXXXXXXXXX657878
输出显示帐户用户名及其密码的 LM 和 NT 散列。攻击者的一个共同目标是在入侵后恢复 Windows 机器上的密码哈希值。这些散列可以脱机破解以试图恢复目标的密码,也可以用于传递散列攻击以获得对其他网络资源的访问。无论目标用户是只在虚拟机上执行高风险操作的偏执用户,还是试图将其用户的某些活动包含到虚拟机的企业用户,查看系统上的虚拟机或快照都是在获得对主机硬件的访问权限后尝试恢复这些散列的最佳时机。
Volatility 使得这一复苏过程极为容易。
我们已经混淆了输出中的散列。您可以使用自己的输出作为散列破解工具的输入,以找到进入 VM 的方法。有几个在线哈希破解网站;或者,你可以在你的 kali 机上使用 John the Ripper 。
(笔者注: John the Ripper 是一个快速的密码破解工具,用于在已知密文的情况下尝试破解出明文,支持目前大多数的加密算法,如 DES、MD4、MD5 等。它支持多种不同类型的系统架构,包括 Unix、Linux、Windows、DOS 模式、 BeOS 和 OpenVMS ,主要目的是破解不够牢固的 Unix/Linux 系统密码。除了在各种 Unix 系统上最常见的几种密码哈希类型之外,它还支持 Windows LM 散列,以及社区增强版本中的许多其他哈希和密码。它是一款开源软件。Kali中自带John。)
漏洞侦察 现在,让我们使用 Volatility 来发现目标 VM 是否存在可以利用的漏洞。 malfind 插件检查可能包含注入代码的进程内存范围。 Potential 是这里的关键词——插件正在寻找具有读、写和执行权限的内存区域。调查这些进程是值得的,因为它们可能帮助我们能够利用一些已经可用的恶意软件。或者,我们可以用自己的恶意软件覆盖这些区域。
1 2 3 4 5 6 7 8 9 10 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.malfind Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner PID Process Start VPN End VPN Tag Protection CommitCharge 1336 timeserv.exe 0 x660000 0 x660fff VadS PAGE_EXECUTE_READWRITE 1 2160 MsMpEng.exe 0 x16301690000 0 x1630179cfff VadS PAGE_EXECUTE_READWRITE 269 2160 MsMpEng.exe 0 x16303090000 0 x1630318ffff VadS PAGE_EXECUTE_READWRITE 256 2160 MsMpEng.exe 0 x16304a00000 0 x16304bfffff VadS PAGE_EXECUTE_READWRITE 512 6484 FreeDesktopClo 0 x2320000 0 x2320fff VadS PAGE_EXECUTE_READWRITE 1 5340 Microsoft.Powe 0 x2c2502c0000 0 x2c2502cffff VadS PAGE_EXECUTE_READWRITE 15
我们遇到了一些潜在的问题。 timeserv.exe 进程(PID 1336)是 FreeDesktopClock (PID 6484)免费软件的一部分。只要他们被安装到 C:\Program Files 目录下,这些不一定是问题。否则,该进程可能是伪装成时钟的恶意软件。
使用搜索引擎,你会发现进程 MsMpEng.exe (PID 2160)是一个防恶意软件服务。尽管这些进程包含可写和可执行的内存区域,但它们看起来并不危险。也许我们可以通过在这些内存区域中编写 shellcode 来使这些进程变得危险,所以值得注意它们。
netscan 插件提供了快照时计算机拥有的所有网络连接的列表,如下所示。任何看起来可疑的东西我们都可以用来发动袭击。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 PS>vol -f WinDev2007Eval-7d959ee5 .vmem windows.netscan Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner Offset Proto LocalAddr LocalPort ForeignAdd ForeignPort State PID Owner 0 xa50bb7a13d90 TCPv4 0.0 .0.0 4444 0.0 .0.0 0 LISTENING 7124 nc64.exe [1 ]0 xa50bb9f4c310 TCPv4 0.0 .0.0 7680 0.0 .0.0 0 LISTENING 1776 svchost.exe0 xa50bb9f615c0 TCPv4 0.0 .0.0 49664 0.0 .0.0 0 LISTENING 564 lsass.exe0 xa50bb9f62190 TCPv4 0.0 .0.0 49665 0.0 .0.0 0 LISTENING 492 wininit.exe0 xa50bbaa80b20 TCPv4 192.168 .28.128 50948 23.40 .62.19 80 CLOSED [2 ]w0xa50bbabd2010 TCPv4 192.168 .28.128 50954 23.193 .33.57 443 CLOSED 0 xa50bbad8d010 TCPv4 192.168 .28.128 50953 99.84 .222.93 443 CLOSED0 xa50bbaef3010 TCPv4 192.168 .28.128 50959 23.193 .33.57 443 CLOSED0 xa50bbaff7010 TCPv4 192.168 .28.128 50950 52.179 .224.121 443 CLOSED0 xa50bbbd240a0 TCPv4 192.168 .28.128 139 0.0 .0.0 0 LISTENING
我们看到一些来自本地机器(192.168.28.128)的连接,显然到一些 web 服务器[2];这些连接现在已经关闭。更重要的是标记为 LISTENING 的连接。那些属于可识别的 Windows 进程( svchost , lsass , wininit )的进程可能没有问题,但 nc64.exe 进程是未知的[1]。它正在侦听端口4444,通过使用第2章中的 netcat 替代品来探测该端口对它进行更深入的研究也是很有价值的。
volshell 接口 (笔者注: volshell ,内存镜像中的shell )
除了命令行界面,您还可以使用 volshell 命令在自定义 Python shell 中使用 Volatility 。这为您提供了 Volatility 的所有功能以及完整的 Python shell 。下面是一个在 Windows 映像上使用 volshell 利用 pslist 插件的例子:
1 2 3 4 5 6 7 8 9 PS> volshell -w -f WinDev2007Eval-7d959ee5 .vmem [1 ] >>> from volatility.plugins.windows import pslist [2 ] >>> dpo(pslist.PsList, primary=self.current_layer, nt_symbols=self.config['nt_symbols' ]) [3 ] PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 4 0 System 0 xa50bb3e6d040 129 - N/A False72 4 Registry 0 xa50bb3fbd080 4 - N/A False6452 4732 OneDrive.exe 0 xa50bb4d62080 25 - 1 True6484 4732 FreeDesktopClo 0 xa50bbb847300 1 - 1 False...
在这个简短的示例中,我们使用 -w 选项来告诉 Volatility 我们正在分析一个 Windows 图像,使用 -f 选项来指定图像本身[1]。一旦进入 volshell 接口,我们就可以像使用普通的 Python shell 一样使用它。也就是说,您可以像往常一样导入包或编写函数,但是现在您还在 shell 中嵌入了 Volatility 。我们导入 pslist 插件[2]并利用 dpo 函数显示插件[3]的输出。
你可以通过输入 volshell --help
找到更多关于使用 volshell 的信息。
自定义 Volatility 插件 我们刚刚看到了如何使用 Volatility 插件来分析存在漏洞的 VM 快照,通过检查正在使用的命令和进程来分析用户,并转储密码散列。但是由于您可以编写自己的自定义插件,所以只有您的想象力才能限制您可以用 Volatility 做什么。如果您需要根据从标准插件找到的线索中获得额外的信息,那么您可以制作自己的插件。
只要您遵循 Volatility 团队的模式,就可以很容易地创建插件。您甚至可以让您的新插件调用其他插件,从而使您的工作更加容易。
让我们来看看一个典型插件的框架:
1 2 3 4 5 6 7 8 9 imports . . . [1 ] class CmdLine (interfaces.plugin.PluginInterface) : @classmethod [2 ] def get_requirements (cls) : pass [3 ] def run (self) : pass [4 ] def generator (self, procs) : pass
这里的主要步骤是创建从 PluginInterface [1]继承的新类,定义插件的需求[2],定义 run 类函数[3],以及定义 generator 类函数[4]。 generator 类函数是可选的,但是将它与 run 类函数分离是您将在许多插件中看到的有用模式。通过分离它并将其作为 Python 生成器使用,您可以获得更快的结果,并使代码更容易理解。
让我们遵循这个通用模式来创建一个自定义插件,该插件将检查不受 address space layout randomization (ASLR,地址空间布局随机化)保护的进程。 ASLR 混合了脆弱进程的地址空间,这影响了堆、栈和其他操作系统分配的虚拟内存位置。这意味着攻击者无法确定在攻击时受害进程的地址空间是如何布置的。 Windows Vista 是第一个支持 ASLR 的 Windows 版本。在 Windows XP 等较旧的内存镜像中,默认情况下不会启用 ASLR 保护。现在,在最新的电脑 (Windows 10) 中,几乎所有的进程都受到了保护。
ASLR 并不意味着攻击者就一定失败了,但它使工作变得更加复杂。作为侦察进程的第一步,我们将创建一个插件来检查流程是否受到 ASLR 的保护。
让我们开始吧。创建一个名为 plugins 的目录。在该目录下,创建一个名为 windows 目录,以存放用于 Windows 机器的自定义插件。如果您创建插件以 Mac 或 Linux 机器为目标,请分别创建一个名为 mac 或 linux 的目录。
现在,在 plugins/windows 目录下,让我们编写我们的 ASLR 检查插件, aslrcheck.py :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from typing import Callable, Listfrom volatility.framework import constants, exceptions, interfaces, renderersfrom volatility.framework.configuration import requirementsfrom volatility.framework.renderers import format_hintsfrom volatility.framework.symbols import intermedfrom volatility.framework.symbols.windows import extensionsfrom volatility.plugins.windows import pslistimport ioimport loggingimport osimport pefilevollog = logging.getLogger(__name__) IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040 IMAGE_FILE_RELOCS_STRIPPED = 0x0001
我们首先处理所需的导入,再加上用于分析 Portable Executable file (PE,可移植可执行文件)的 pefile 库。现在让我们编写一个辅助函数来进行分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [1 ] def check_aslr (pe) : pe.parse_data_directories([ pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG' ] ]) dynamic = False stripped = False [2 ] if (pe.OPTIONAL_HEADER.DllCharacteristics & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE): dynamic = True [3 ] if pe.FILE_HEADER.Characteristics & IMAGE_FILE_RELOCS_STRIPPED: stripped = True [4 ] if not dynamic or (dynamic and stripped): aslr = False else : aslr = True return aslr
我们将一个 PE 文件对象传递给 check_aslr 函数[1],解析它,然后检查它是否已经用 DYNAMIC 基础设置编译[2],以及是否存在文件重定位数据段[3]。如果它不是动态的,或者可能编译为动态的但没有重定位数据段,那么 PE 文件也就不受 ASLR 保护[4]。
check_aslr 辅助函数已经准备好了,让我们创建我们的 AslrCheck 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [1 ] class AslrCheck (interfaces.plugins.PluginInterface) : @classmethod def get_requirements (cls) : return [ [2 ] requirements.TranslationLayerRequirement( name='primary' , description='Memory layer for the kernel' , architectures=["Intel32" , "Intel64" ]), [3 ] requirements.SymbolTableRequirement( name="nt_symbols" , description="Windows kernel symbols" ), [4 ] requirements.PluginRequirement( name='pslist' , plugin=pslist.PsList, version=(1 , 0 , 0 )), [5 ] requirements.ListRequirement(name = 'pid' , element_type = int, description = "Process ID to include (all others are excluded)" , optional = True ), ]
创建插件的第一步是从 PluginInterface 对象继承[1]。接下来,定义需求。通过查看其他插件,您可以很好地了解自己需要什么。每个插件都需要内存层,我们首先定义这个需求[2]。除了内存层,我们还需要符号表[3]。您会发现几乎所有插件都会使用这两个需求。
为了从内存中获取所有进程并从进程中重新创建PE文件[4],我们还需要 pslist 插件。然后,我们将从每个进程传递重新创建的 PE 文件,并检查它是否有 ASLR 保护。
我们可能想要检查给定进程 ID 的单个进程,因此我们创建另一个可选设置,允许我们传入一个进程 ID 列表,以限制只检查那些进程[5]。
1 2 3 4 5 6 7 8 @classmethod def create_pid_filter (cls, pid_list: List[int] = None) -> Callable[[interfaces.objects.ObjectInterface], bool]: filter_func = lambda _: False pid_list = pid_list or [] filter_list = [x for x in pid_list if x is not None ] if filter_list: filter_func = lambda x: x.UniqueProcessId not in filter_list return filter_func
为了处理可选的进程 ID ,我们使用一个类函数创建一个过滤函数,该函数为列表中的每个进程 ID 返回 False ;也就是说,我们询问过滤函数的问题是是否过滤掉一个进程,所以只有 PID 不在列表中时才返回 True :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 def _generator (self, procs) : pe_table_name = intermed.IntermediateSymbolTable.create( [1 ] self.context, self.config_path, "windows" , "pe" , class_types=extensions.pe.class_types) procnames = list() for proc in procs: procname = proc.ImageFileName.cast("string" , max_length=proc.ImageFileName.vol.count, errors='replace' ) if procname in procnames: continue procnames.append(procname) proc_id = "Unknown" try : proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() except exceptions.InvalidAddressException as e: vollog.error(f"Process {proc_id} : invalid address {e} in layer {e.layer_name} " ) continue peb = self.context.object( [2 ] self.config['nt_symbols' ] + constants.BANG + "_PEB" , layer_name = proc_layer_name, offset = proc.Peb) try : dos_header = self.context.object( pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER" , offset=peb.ImageBaseAddress, layer_name=proc_layer_name) except Exception as e: continue pe_data = io.BytesIO() for offset, data in dos_header.reconstruct(): pe_data.seek(offset) pe_data.write(data) pe_data_raw = pe_data.getvalue() [3 ] pe_data.close() try : pe = pefile.PE(data=pe_data_raw) [4 ] except Exception as e: continue aslr = check_aslr(pe) [5 ] yield (0 , (proc_id, [6 ] procname, format_hints.Hex(pe.OPTIONAL_HEADER.ImageBase), aslr, ))
我们创建了一个名为 pe_table_name [1]的特殊数据结构,用于循环内存中的每个进程。然后我们得到与每个进程相关联的Process Environment Block (PEB,进程环境块)内存区域,并将其放入对象中[2]。 PEB 是当前进程的数据结构,它包含了关于进程的大量信息。我们向该区域写入一个类文件对象 (pe_data) [3],使用 pefile 库创建一个 PE 对象[4],并将其传递给 check_aslr 辅助函数[5]。最后,我们生成包含进程 ID 、进程名、进程内存地址的信息元组,以及来自 ASLR 保护检查[6]的 Boolean (布尔值)结果。
现在我们创建 run 类函数,它不需要任何参数,因为所有的设置都被填充到 config 对象中:
1 2 3 4 5 6 7 8 9 10 11 12 def run (self) : 1 procs = pslist.PsList.list_processes(self.context, self.config["primary" ], self.config["nt_symbols" ], filter_func = self.create_pid_filter(self.config.get('pid' , None ))) 2 return renderers.TreeGrid([ ("PID" , int), ("Filename" , str), ("Base" , format_hints.Hex), ("ASLR" , bool)], self._generator(procs))
我们使用 pslist 插件获取进程列表[1],并使用 TreeGrid 渲染器从生成器返回数据[2]。许多插件都使用 TreeGrid 渲染器。它确保我们为每个分析的进程得到一行结果。
(笔者注: TreeGrid 是一种 DHTML 控件,其完全使用 JavaScript 语言编写,用以在HTML页面上展示具有层次结构的数据项 ,其核心技术为多叉树。)
Kicking the Tires 让我们看一看在 Volatility 网站上提供的其中一个有效映像: Malware - Cridex 。对于您的自定义插件,提供 -p 选项与您的 plugins 文件夹路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 PS>vol -p .\plugins\windows -f cridex.vmem aslrcheck.AslrCheck Volatility 3 Framework 1.2 .0 -beta .1 Progress: 0.00 Scanning primary2 using PdbSignatureScanner PID Filename Base ASLR 368 smss.exe 0 x48580000 False584 csrss.exe 0 x4a680000 False608 winlogon.exe 0 x1000000 False652 services.exe 0 x1000000 False664 lsass.exe 0 x1000000 False824 svchost.exe 0 x1000000 False1484 explorer.exe 0 x1000000 False1512 spoolsv.exe 0 x1000000 False1640 reader_sl.exe 0 x400000 False788 alg.exe 0 x1000000 False1136 wuauclt.exe 0 x400000 False
如您所见,这是一台 Windows XP 机器,在任何进程上都没有 ASLR 保护。
下面是纯净的全新的 Windows 10 机器的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 PS>vol -p .\plugins\windows -f WinDev2007Eval-Snapshot4 .vmem aslrcheck.AslrCheck Volatility 3 Framework 1.2 .0 -beta .1 Progress: 33.01 Scanning primary2 using PdbSignatureScanner PID Filename Base ASLR 316 smss.exe 0 x7ff668020000 True428 csrss.exe 0 x7ff796c00000 True500 wininit.exe 0 x7ff7d9bc0000 True568 winlogon.exe 0 x7ff6d7e50000 True592 services.exe 0 x7ff76d450000 True600 lsass.exe 0 x7ff6f8320000 True696 fontdrvhost.ex 0 x7ff65ce30000 True728 svchost.exe 0 x7ff78eed0000 TrueVolatility was unable to read a requested page: Page error 0 x7ff65f4d0000 in layer primary2_Process928 (Page Fault at entry 0 xd40c9d88c8a00400 in page entry) * Memory smear during acquisition (try re-acquiring if possible) * An intentionally invalid page lookup (operating system protection) * A bug in the plugin/volatility (re-run with -vvv and file a bug) No further results will be produced
这里没什么可看的。每个列出的进程都受到 ASLR 的保护。然而,我们也看到了 memory smear ,内存污染。当拍摄内存映像时,内存存储的内容发生变化时,就会发生 memory smear 。这会导致内存表描述与内存本身不匹配;或者,虚拟内存指针可能引用无效数据。黑客攻击就会困难。正如错误描述所说,您可以尝试重新获取映像(寻找或创建一个新的快照)。
(笔者注: memory smear ,在内存采集过程中,运行中系统对数据的修改。)
让我们检查 PassMark Windows 10 样本内存映像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 PS>vol -p .\plugins\windows -f WinDump.mem aslrcheck.AslrCheck Volatility 3 Framework 1.2 .0 -beta .1 Progress: 0.00 Scanning primary2 using PdbSignatureScanner PID Filename Base ASLR 356 smss.exe 0 x7ff6abfc0000 True2688 MsMpEng.exe 0 x7ff799490000 True2800 SecurityHealth 0 x7ff6ef1e0000 True5932 GoogleCrashHan 0 xed0000 True5380 SearchIndexer. 0 x7ff6756e0000 True3376 winlogon.exe 0 x7ff65ec50000 True6976 dwm.exe 0 x7ff6ddc80000 True9336 atieclxx.exe 0 x7ff7bbc30000 True9932 remsh.exe 0 x7ff736d40000 True2192 SynTPEnh.exe 0 x140000000 False7688 explorer.exe 0 x7ff7e7050000 True7736 SynTPHelper.ex 0 x7ff7782e0000 True
几乎所有进程都受到保护。只有一个进程 SynTPEnh.exe 不受 ASLR 保护。在线搜索显示,这是 Synaptics Pointing Device 的一个软件组件,可能用于触摸屏。只要这个进程被安装在 c:\Program Files 中,就没有问题的,但它可能值得以后去弄清楚。
在本章中,您看到了您可以利用 Volatility 框架的强大功能来查找关于用户行为和连接的更多信息,以及分析任何进程运行内存中的数据。您可以使用这些信息来更好地理解目标用户和机器,以及理解防御者的心态。
Onward! (前进吧) 现在您应该已经注意到, Python 是一种非常适合黑客编程的语言,特别是当您考虑到许多可用的库和基于 Python 的框架时。虽然黑客拥有大量的工具,但没有什么能替代编写自己的工具,因为这能让你更深入地了解其他工具在做什么。
继续前进,为您的特殊需求编写一个自定义工具。无论它是 Windows 的 SSH 客户端, web scraper (笔者注: Web Scraper ,一个插件,轻量数据爬取利器),还是命令和控制系统, Python 都帮你搞定了。