Last year, I proposed “volatile Indicators of Compromise (IOCs)” based on RAM evidence only at SANS DFIR Summit. We can detect malware using them faster than using disk-evidence-based IOCs. Besides, we can define indicators based on not only metadata (e.g., file path) but also malware function (e.g., code injection sign, imported functions and unpacked codes). The IOCs are described according to OpenIOC specification. IOC Editor is used for defining IOCs and Redline is used for scannning IOCs.
Since then, I continued to make volatile IOCs and detect malware through the tools, but I’ve got some frustrating problems about them. First, We can’t automate IOC scanning for daily task because Redline is a GUI tool. Second, Redline is compliant with OpenIOC 1.0 but the spec doesn’t support regular expression, case sensitiveness. In addition, “AND” combination of different items (e.g., ProcessItem and RegistryItem) does not work. Furthermore, Redline cannot scan unallocated objects (e.g., dead process, unloaded kernel drivers). So I decied to make a new tool for volatile IOCs.
openioc_scan Volatility plugin
I wrote a plugin called “openioc_scan” for Volatility Framework that is a open-source memory forensic tool. The plugin supports only Windows Vista or later Windows versions (Linux and Mac OS X are not supported).
To run this plugin, you need to install the following Python modules.
We also must prepare IOCs for openioc_scan. Openioc_scan accepts only OpenIOC 1.1 XML files. We can define grep pattern (using “matches” condition) and case sensitiveness in the version. But unfortunately, Mandiant doesn’t provide IOC Editor for the latest version yet.
I hope they will publish the updated one. Currently, we should generate IOCs on IOC Editor then convert them into new ones using openioc_10_to_11.py in ioc_writer. (2014/8/25) Sean Gillespie distributes open-source IOC editor, PyIOCe. We can generate OpenIOC 1.1 indicator files using it.
Openioc_scan has several options.
1 2 3 4 5 6 7 8
“—show” option just shows the IOCs included in the directory specified by “—ioc_dir” option.
If we run openioc_scan without -s option, the plugin scans the specified memory image using IOCs then display the result.
Openioc_scan generates a cache database for result because some IOC items to scan may take long time. If there are no records about items in cache, openioc_scan outputs “[time-consuming task]” logs during the scan. Once a cache corresponding to defined items is generated, we can scan the same items rapidly.
For instance, the first run took 2327 secs:
The second run or later took only 149 secs because of cache db extracted by the 1st run:
Supported Terms (2015/6/29)
I show 35 terms supported by openioc_scan.
To make maximal use of openioc_scan, we had better newly add some term definitions in Configuration\IOCTerms*.iocterms file of IOC Editor installed folder (for more detail, see IOCe user guide). (2014/8/25) We can add new definitions on PyIOCe from Terms->Indicator Terms menu as follows: (2014/9/30) Sean added term import/export functions to PyIOCe. You can import the terms for Volatility (download from github) or PyIOCe with all Volatility terms may be released shortly. Thanks Sean!
ProcessItem (19 Terms)
- ProcessItem/name (string) … process name (max 15 characters)
- ProcessItem/ParentProcessName (string) … process name of the parent process
ProcessItem/path (string)… path in the command line of process(replaced by ProcessItem/cmdLIne)
- ProcessItem/cmdLine (string) … process command line
- ProcessItem/DllPath (string) … dll path loaded in process (base on ldrmodules command)
- ProcessItem/DllHidden (bool, should be “true” or “false”) … dll hidden from all PEB linked lists (e.g., InLoadOrderModuleList) in process (base on ldrmodules command)
ProcessItem/arguments (string)… command line arguments(replaced by ProcessItem/cmdLIne)
- ProcessItem/hidden (bool) … process hidden by rootkit (e.g., DKOM). This item is based on part of psxview command, but dead process with exit time is excluded before evaluation.
- ProcessItem/SectionList/MemorySection/Injected (bool) … process with potential section of injected or unpacked code based on malfind command
- ProcessItem/SectionList/MemorySection/InjectedHexPattern (string) … process with potential section of injected or unpacked code with specified hex pattern based on malfind command (matches condition only)
- ProcessItem/StringList/string (string) … strings or binary code sequences in the process
- ProcessItem/SectionList/MemorySection/PEInfo/ImportedModules/Module/ImportedFunctions/string (string) … imported function names based on impscan. The original command scans only base+SizeOfImage of the executable, so I added code-injected sections and DLLs with suspicious paths (e.g., “\$Recycle.Bin”) as scan target. This item doesn’t work on wow64 process due to impscan’s limitation.
- ProcessItem/HandleList/Handle/Name (string), ProcessItem/HandleList/Handle/Type (string) … process handle information based on handles command
- ProcessItem/PortList/PortItem/localPort (integer), ProcessItem/PortList/PortItem/remotePort (integer), ProcessItem/PortList/PortItem/localIP (string), ProcessItem/PortList/PortItem/remoteIP (string) … network information related to the process from the result of netscan command
- ProcessItem/Hooked/API/FunctionName (string) … IAT/EAT/Inline hooked API function name based on apihooks command
- ProcessItem/Hooked/API/HookingModuleName (string) … IAT/EAT/Inline hooking module name based on apihooks command
- ProcessItem/EnabledPrivilege/Name (string) … explicitly enabled privilege name extracted from privs command (e.g., SeDebugPrivilege)
RegistryItem (2 Terms)
RegistryItem/Path (string)… registry key or value paths based on hivelist&printkey. It’s too slow, so I recommend to use handle names instead. For example, it takes 12 hours in 512MB RAM :–((disabled)
- RegistryItem/ShimCache/ExecutablePath (string) … exe/dll/bat file paths included in shimcache artifact
ServiceItem (3 Terms)
- ServiceItem/name (string) … service name
- ServiceItem/descriptiveName (string) … service description name
- ServiceItem/cmdLine (string) … command line of the service
DriverItem (6 Terms)
- DriverItem/DriverName (string) … kernel driver name extracted from lsmod method (to be improved in the future)
- DriverItem/PEInfo/ImportedModules/Module/ImportedFunctions/string (string) … imported function names based on impscan
- DriverItem/StringList/string (string) … strings or binary code sequences in the driver
- DriverItem/IRP/HookingModuleName (string) … kernel module name hooking IRP major function table (e.g., rootkit hooking IRP_MJ_DEVICE_CONTROL in tcpip.sys), based on driverirp command
- DriverItem/CallbackRoutine/Type (string) … kernel callback function type from callbacks command
- DriverItem/TimerRoutineIncluded (bool) … the kernel module includes kernel timer functions or not
HookItem (1 Term)
- HookItem/SSDT/HookedFunctionName (string) … hooked system call function name in SSDT (e.g., NtQueryDirectoryFile)
FileItem (5 Terms)
- FileItem/FileName (string) … file name extracted by mftparser
- FileItem/FileExtension (string) … file extension extracted by mftparser
- FileItem/INode (integer) … MFT entry number extracted by mftparser
- FileItem/FullPath (string) … file path extracted by mftparser
- FileItem/SizeInBytes (integer) … file size extracted by mftparser
Using openioc_scan, we can detect malware based on our own rules. I show some examples for detecting PlugX type II/III and WebInject malware. About PlugX, see this presentation. Actually, all IOCs are generic indicators, so they can be applied to other malware.
unusual executable paths:
malware bypassing UAC pop-up:
WebInject malware (e.g., ZeuS and its variants):
I will support
dead process / unloaded or hidden driver terms in the future. I will also consider the term about auto-startup entries (e.g., registry Run keys) extracted from RAM. Scoring function using OpenIOC parameters may be implemented.
Any comments or feedback are welcome.
I made the repository for openioc_scan. you can download the code, example IOCs and PyIOCe volatility terms/parameters from there.
You can use the plugin by just copying it into volatility\plugins\malware folder. I checked it worked on Volatility 2.4 and 2.3.1.
Let me know if you have any question or problem. Enjoy ;–)