-
Notifications
You must be signed in to change notification settings - Fork 605
Sandbox Checking Volatility3 Plugin #1906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
# live.py – Volatility 3 Live System Analysis Plugin `live.py` is a custom plugin for **Volatility 3** designed to extend its capabilities for **real-time forensic data collection and threat hunting** directly on a **live Windows system**, eliminating the need for a full memory dump. This tool provides an **interactive command-line shell** for dynamic investigation, leveraging system APIs through libraries like `psutil` and `pywin32` to quickly triage and analyze active endpoints. --- ## Key Capabilities ### **Live Analysis Mode** Performs immediate, low-overhead forensic data collection from an active operating system, bypassing traditional memory dump requirements. ### **Interactive Shell** Includes an integrated CLI environment offering a suite of commands for efficient, step-by-step investigation via the `LiveShellCommand` interface. ### **Advanced Threat Hunting** Provides built-in commands for targeted analysis: - **fileless** – Detects fileless malware and suspicious in-memory activity, focusing on processes such as `powershell.exe`. - **detect_sandbox** – Identifies virtualized or sandboxed environments by inspecting artifacts, process behavior, and MAC address prefixes. ### **Comprehensive Forensic Data Collection** Collects essential artifacts and system information for deep analysis: - **Process and Module Data:** `pslist`, `psscan`, `dlllist`, `handles`, `sids`, `cmdline` - **Network Activity:** `netscan` for active connections and sockets - **Persistence & Services:** Analysis of `services`, `drivers`, `registry`, and autorun entries - **Artifact Analysis:** Extraction of `shimcache`, `prefetch`, `userassist`, and `jumplists` - **Timeline Generation:** Unified event correlation using `timeliner` ---
# sandbox_detect.py – Virtualization and Sandbox Environment Detection (Volatility 3 Plugin) `sandbox_detect.py` is a specialized **Volatility 3 plugin** designed for **post-mortem forensic analysis** of **Windows memory dumps**. Its primary goal is to detect and score artifacts indicating that the analyzed system was operating within a **Virtual Machine (VM)**, **Sandbox**, or **Malware Analysis Environment**. This plugin is particularly valuable for investigators who need to determine whether a captured memory sample originated from a **controlled analysis setup** or a **real-world victim system**. --- ## Key Capabilities ### **Multi-Layered Artifact Scanning** Performs deep inspection across multiple memory and system layers to ensure comprehensive detection: - **Process Analysis:** Identifies running processes related to virtualization or analysis environments, such as `vmtoolsd.exe`, `vboxservice.exe`, `prl_cc.exe`, `wireshark.exe`, and `ollydbg.exe`. - **Driver and Module Checks:** Detects kernel modules and drivers named after virtualization platforms, including `vmmouse.sys`, `vboxguest.sys`, and `vmhgfs.sys`. - **Registry and System Keys:** Examines critical registry entries and system identifiers for virtualization traces, such as hardware IDs, BIOS strings, and known VM installation paths. --- ### **Heuristic Scoring System** Implements a scoring engine that assigns severity levels to each identified artifact. Instead of a binary result, the plugin produces a **confidence-based verdict**, such as: - **HIGH CONFIDENCE – Virtual Machine Detected** - **MODERATE CONFIDENCE – Sandbox Environment** - **LOW CONFIDENCE – Physical Host** This scoring model provides analysts with clearer, evidence-weighted conclusions. ---
# sandbox_detect.py – Virtualization and Sandbox Environment Detection (Volatility 3 Plugin) `sandbox_detect.py` is a specialized **Volatility 3 plugin** designed for **post-mortem forensic analysis** of **Windows memory dumps**. Its primary goal is to detect and score artifacts indicating that the analyzed system was operating within a **Virtual Machine (VM)**, **Sandbox**, or **Malware Analysis Environment**. This plugin is particularly valuable for investigators who need to determine whether a captured memory sample originated from a **controlled analysis setup** or a **real-world victim system**. --- ## Key Capabilities ### **Multi-Layered Artifact Scanning** Performs deep inspection across multiple memory and system layers to ensure comprehensive detection: - **Process Analysis:** Identifies running processes related to virtualization or analysis environments, such as `vmtoolsd.exe`, `vboxservice.exe`, `prl_cc.exe`, `wireshark.exe`, and `ollydbg.exe`. - **Driver and Module Checks:** Detects kernel modules and drivers named after virtualization platforms, including `vmmouse.sys`, `vboxguest.sys`, and `vmhgfs.sys`. - **Registry and System Keys:** Examines critical registry entries and system identifiers for virtualization traces, such as hardware IDs, BIOS strings, and known VM installation paths. --- ### **Heuristic Scoring System** Implements a scoring engine that assigns severity levels to each identified artifact. Instead of a binary result, the plugin produces a **confidence-based verdict**, such as: - **HIGH CONFIDENCE – Virtual Machine Detected** - **MODERATE CONFIDENCE – Sandbox Environment** - **LOW CONFIDENCE – Physical Host** This scoring model provides analysts with clearer, evidence-weighted conclusions. ---
# sandbox_detect.py – Virtualization and Sandbox Environment Detection (Volatility 3 Plugin) `sandbox_detect.py` is a specialized **Volatility 3 plugin** designed for **post-mortem forensic analysis** of **Windows memory dumps**. Its primary goal is to detect and score artifacts indicating that the analyzed system was operating within a **Virtual Machine (VM)**, **Sandbox**, or **Malware Analysis Environment**. This plugin is particularly valuable for investigators who need to determine whether a captured memory sample originated from a **controlled analysis setup** or a **real-world victim system**. --- ## Key Capabilities ### **Multi-Layered Artifact Scanning** Performs deep inspection across multiple memory and system layers to ensure comprehensive detection: - **Process Analysis:** Identifies running processes related to virtualization or analysis environments, such as `vmtoolsd.exe`, `vboxservice.exe`, `prl_cc.exe`, `wireshark.exe`, and `ollydbg.exe`. - **Driver and Module Checks:** Detects kernel modules and drivers named after virtualization platforms, including `vmmouse.sys`, `vboxguest.sys`, and `vmhgfs.sys`. - **Registry and System Keys:** Examines critical registry entries and system identifiers for virtualization traces, such as hardware IDs, BIOS strings, and known VM installation paths. --- ### **Heuristic Scoring System** Implements a scoring engine that assigns severity levels to each identified artifact. Instead of a binary result, the plugin produces a **confidence-based verdict**, such as: - **HIGH CONFIDENCE – Virtual Machine Detected** - **MODERATE CONFIDENCE – Sandbox Environment** - **LOW CONFIDENCE – Physical Host** This scoring model provides analysts with clearer, evidence-weighted conclusions. ---
ikelos
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in general, this is pretty good and I like the functionality, well done. 5:) The main issue with this at the moment is that it's designed exclusively to be used as part of the CLI and for human output, requiring interpretation or parsing of some fields for anything that programmatically wishes to use the data produced.
To tidy this up, there should be as many fields as there are separate pieces of information to communicate. This means splitting up the info field, and putting the summary data into fields of their own that aren't used in the rest of the lines. Please use a BaseAbsentValue derivative for any fields that aren't used (such as NotAvailableValue or NotApplicableValue). This may mean the plugin returns a lot of columns, and may be more difficult to read through the CLI, but it will vastly improve the mobility of the data this plugin produces.
That would mean returning something like:
Overall verdict | Total score | Detections | Confidence | Detection Type | Indicator | Description | Severity | PID | Process count | ...
SANDBOX | 89 | 10 | High | - | - | - | - | - | - |....
- | - | - | - | System | Low Process Count | Minimal process environment | High | - | 19 | ...
This won't give a nice document, if you want that, then I'd write a shell script that runs the output and interprets the JSON output data or similar. We offer the TreeGrid as a means to return a tree/table of data relevant to the plugin. It is the most modular mechanism we can provide while still allowing interpretation of the results by other programs and systems.
| process_params = peb.ProcessParameters | ||
| if process_params: | ||
| image_path = process_params.ImagePathName.get_string() | ||
| proc_path = image_path if image_path else "N/A" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than using the string "N/A" (which can't be differentiated from the string "N/A" please use something derived from BaseAbsentValue such as NotAvailableValue.
| 'indicator': proc_name, | ||
| 'description': self.SANDBOX_PROCESSES[proc_name], | ||
| 'severity': 'High', | ||
| 'info': f'PID: {proc_pid} | Path: {proc_path}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't include two fields as a string. This makes the data difficult to use programmatically. It would be better to return the two fields separately (particularly since if they're not available they should be derived from BaseAbsentValue).
| break | ||
|
|
||
| except Exception: | ||
| continuenue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a typo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may also be worth logging the error that occurs here, particularly if you're blanket catching all exceptions. Ideally you'd only catch expected exceptions, but if you want to catch them all, there should be at least a way for developers to know something's gone wrong (such as a vollog.debug message).
| continue | ||
|
|
||
| # Check for very low process count | ||
| if process_count < 20: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like an arbitrary value. It might be worth parameterizing it, and collecting it at the top of the class, to allow other plugins to change it without having to rewrite the code completely.
| 'indicator': f'Missing critical processes: {", ".join(missing_processes)}', | ||
| 'description': 'Essential Windows processes not running', | ||
| 'severity': 'High', | ||
| 'info': f'Found processes: {", ".join(process_names[:10])}...' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, combining values into a single string is very useful for humans but would require any automatic system using the plugin to parse the string you've constructed. Typically we'd expect this to output one entry per process_name (repeating all the rest of the data). It's up to you, and I won't push it, but please think of other uses of the plugin besides only the CLI and humans reading it. This is supposed to be a library that parses data that can be programmatically read by a consumer for use by all kinds of programs.
| total_score = 0 | ||
|
|
||
| # Run all checks | ||
| vollog.info("Checking for sandbox processes...") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a progress_callback call, rather than a log message? It takes a float value showing the percentage progress, and a message indicating what's being progressed.
| "" | ||
| )) | ||
|
|
||
| yield (0, ("", "", "", "", "")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't do this, you're abusing the data return to try to format the results for humans. As I've mention twice elsewhere, these plugins may be used by any tool that uses the library, and having to handle unusual results like this will make things more difficult for them.
| # Yield detailed detections if verbose or if detections found | ||
| if verbose or all_detections: | ||
| for detection in all_detections: | ||
| yield (0, ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can yield these with a 1, to indent them in a tree view, instead of 0 here, if you wish to differentiate them.
| # Yield summary | ||
| yield (0, ( | ||
| "SUMMARY", | ||
| verdict, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This value isn't an indicator, please find a different way of present summary information (such as a completely different field in output, only used in this row).
| yield (0, ( | ||
| "SUMMARY", | ||
| verdict, | ||
| f"Score: {total_score} | Detections: {len(all_detections)}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is two pieces of information and therefore should be two separate fields. Please don't textually combine two different pieces of data.
|
Salam ,
I hope you are doing well , Thanks for your point . I would like to ask if
this plugin has any chances for the next release Inshallah ?
…On Wed, Nov 19, 2025 at 1:16 AM ikelos ***@***.***> wrote:
***@***.**** commented on this pull request.
So in general, this is pretty good and I like the functionality, well
done. 5:) The main issue with this at the moment is that it's designed
exclusively to be used as part of the CLI and for human output, requiring
interpretation or parsing of some fields for anything that programmatically
wishes to use the data produced.
To tidy this up, there should be as many fields as there are separate
pieces of information to communicate. This means splitting up the info
field, and putting the summary data into fields of their own that aren't
used in the rest of the lines. Please use a BaseAbsentValue derivative
for any fields that aren't used (such as NotAvailableValue or
NotApplicableValue). This may mean the plugin returns a lot of columns,
and may be more difficult to read through the CLI, but it will vastly
improve the mobility of the data this plugin produces.
That would mean returning something like:
Overall verdict | Total score | Detections | Confidence | Detection Type | Indicator | Description | Severity | PID | Process count | ...
SANDBOX | 89 | 10 | High | - | - | - | - | - | - |....
- | - | - | - | System | Low Process Count | Minimal process environment | High | - | 19 | ...
This *won't* give a nice document, if you want that, then I'd write a
shell script that runs the output and interprets the JSON output data or
similar. We offer the TreeGrid as a means to return a tree/table of data
relevant to the plugin. It is the most modular mechanism we can provide
while still allowing interpretation of the results by other programs and
systems.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + proc_name = proc.ImageFileName.cast(
+ "string",
+ max_length=proc.ImageFileName.vol.count,
+ errors="replace"
+ ).lower()
+
+ proc_pid = proc.UniqueProcessId
+
+ # Get process path
+ try:
+ peb = proc.get_peb()
+ if peb:
+ process_params = peb.ProcessParameters
+ if process_params:
+ image_path = process_params.ImagePathName.get_string()
+ proc_path = image_path if image_path else "N/A"
Rather than using the string "N/A" (which can't be differentiated from the
string "N/A" please use something derived from BaseAbsentValue such as
NotAvailableValue.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + proc_path = image_path if image_path else "N/A"
+ else:
+ proc_path = "N/A"
+ else:
+ proc_path = "N/A"
+ except Exception:
+ proc_path = "N/A"
+
+ if proc_name in self.SANDBOX_PROCESSES:
+ score += 10
+ detections.append({
+ 'type': 'Process',
+ 'indicator': proc_name,
+ 'description': self.SANDBOX_PROCESSES[proc_name],
+ 'severity': 'High',
+ 'info': f'PID: {proc_pid} | Path: {proc_path}'
Please don't include two fields as a string. This makes the data difficult
to use programmatically. It would be better to return the two fields
separately (particularly since if they're not available they should be
derived from BaseAbsentValue).
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> +
+ # Check for VM-related DLL names
+ for artifact in self.VM_ARTIFACTS:
+ if artifact in dll_name and dll_name not in self.SANDBOX_DLLS:
+ score += 3
+ detections.append({
+ 'type': 'DLL',
+ 'indicator': dll_name,
+ 'description': f'VM-related DLL: {artifact}',
+ 'severity': 'Low',
+ 'process': proc_name
+ })
+ break
+
+ except Exception:
+ continuenue
This looks like a typo?
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + process_count = 0
+ process_names = []
+ for proc in pslist.PsList.list_processes(self.context, kernel_module_name):
+ process_count += 1
+ try:
+ proc_name = proc.ImageFileName.cast(
+ "string",
+ max_length=proc.ImageFileName.vol.count,
+ errors="replace"
+ ).lower()
+ process_names.append(proc_name)
+ except Exception:
+ continue
+
+ # Check for very low process count
+ if process_count < 20:
This seems like an arbitrary value. It might be worth parameterizing it,
and collecting it at the top of the class, to allow other plugins to change
it without having to rewrite the code completely.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + 'severity': 'Medium',
+ 'info': 'Limited process environment'
+ })
+
+ # Check for missing common Windows processes
+ common_processes = ['explorer.exe', 'svchost.exe', 'lsass.exe', 'services.exe', 'winlogon.exe']
+ missing_processes = [p for p in common_processes if p not in process_names]
+
+ if len(missing_processes) >= 2:
+ score += 8
+ detections.append({
+ 'type': 'System',
+ 'indicator': f'Missing critical processes: {", ".join(missing_processes)}',
+ 'description': 'Essential Windows processes not running',
+ 'severity': 'High',
+ 'info': f'Found processes: {", ".join(process_names[:10])}...'
Again, combining values into a single string is very useful for humans but
would require any automatic system using the plugin to parse the string
you've constructed. Typically we'd expect this to output one entry per
process_name (repeating all the rest of the data). It's up to you, and I
won't push it, but please think of other uses of the plugin besides only
the CLI and humans reading it. This is supposed to be a library that parses
data that can be programmatically read by a consumer for use by all kinds
of programs.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + elif total_score >= 30 or detection_count >= 3:
+ return "LIKELY SANDBOX", "Medium confidence - Several suspicious indicators"
+ elif total_score >= 15 or detection_count >= 1:
+ return "SUSPICIOUS", "Low confidence - Few indicators detected"
+ else:
+ return "REAL MACHINE", "No significant sandbox indicators found"
+
+ def _generator(self):
+ kernel_module_name = self.config["kernel"]
+ verbose = self.config.get("verbose", False)
+
+ all_detections = []
+ total_score = 0
+
+ # Run all checks
+ vollog.info("Checking for sandbox processes...")
This should probably be a progress_callback call, rather than a log
message? It takes a float value showing the percentage progress, and a
message indicating what's being progressed.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + all_detections.extend(drv_detections)
+ total_score += drv_score
+
+ # Calculate verdict
+ verdict, confidence = self._calculate_verdict(total_score, len(all_detections))
+
+ # Yield summary
+ yield (0, (
+ "SUMMARY",
+ verdict,
+ f"Score: {total_score} | Detections: {len(all_detections)}",
+ confidence,
+ ""
+ ))
+
+ yield (0, ("", "", "", "", ""))
Please don't do this, you're abusing the data return to try to format the
results for humans. As I've mention twice elsewhere, these plugins may be
used by any tool that uses the library, and having to handle unusual
results like this will make things more difficult for them.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> +
+ # Yield summary
+ yield (0, (
+ "SUMMARY",
+ verdict,
+ f"Score: {total_score} | Detections: {len(all_detections)}",
+ confidence,
+ ""
+ ))
+
+ yield (0, ("", "", "", "", ""))
+
+ # Yield detailed detections if verbose or if detections found
+ if verbose or all_detections:
+ for detection in all_detections:
+ yield (0, (
You can yield these with a 1, to indent them in a tree view, instead of 0
here, if you wish to differentiate them.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + sys_score, sys_detections = self._check_system_info(kernel_module_name)
+ all_detections.extend(sys_detections)
+ total_score += sys_score
+
+ vollog.info("Checking for VM drivers...")
+ drv_score, drv_detections = self._check_drivers(kernel_module_name)
+ all_detections.extend(drv_detections)
+ total_score += drv_score
+
+ # Calculate verdict
+ verdict, confidence = self._calculate_verdict(total_score, len(all_detections))
+
+ # Yield summary
+ yield (0, (
+ "SUMMARY",
+ verdict,
This value isn't an indicator, please find a different way of present
summary information (such as a completely different field in output, only
used in this row).
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> + all_detections.extend(sys_detections)
+ total_score += sys_score
+
+ vollog.info("Checking for VM drivers...")
+ drv_score, drv_detections = self._check_drivers(kernel_module_name)
+ all_detections.extend(drv_detections)
+ total_score += drv_score
+
+ # Calculate verdict
+ verdict, confidence = self._calculate_verdict(total_score, len(all_detections))
+
+ # Yield summary
+ yield (0, (
+ "SUMMARY",
+ verdict,
+ f"Score: {total_score} | Detections: {len(all_detections)}",
This is two pieces of information and therefore should be two separate
fields. Please don't textually combine two different pieces of data.
------------------------------
In vmcheck.py
<#1906 (comment)>
:
> +
+ # Check for VM-related DLL names
+ for artifact in self.VM_ARTIFACTS:
+ if artifact in dll_name and dll_name not in self.SANDBOX_DLLS:
+ score += 3
+ detections.append({
+ 'type': 'DLL',
+ 'indicator': dll_name,
+ 'description': f'VM-related DLL: {artifact}',
+ 'severity': 'Low',
+ 'process': proc_name
+ })
+ break
+
+ except Exception:
+ continuenue
It may also be worth logging the error that occurs here, particularly if
you're blanket catching all exceptions. Ideally you'd only catch expected
exceptions, but if you want to catch them all, there should be at least a
way for developers to know something's gone wrong (such as a vollog.debug
message).
—
Reply to this email directly, view it on GitHub
<#1906 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BJBFUM63EX3HQLR7O3LZTTT35OLE5AVCNFSM6AAAAACLWSYIG2VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTINZZG44TOOBVGE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
Well, you've created a lot of plugins, and I generally go through them in order so that plugins don't get forgotten and so that people can't jump the queue to the front of the queue. If you have specific plugins you'd like me to review, I can pick those ones out for you. Once they've been reviewed, it's up to you to make the changes to a point that they're acceptable for inclusion and then they'll get merged. If that happens before the code freeze for the next release, then they'll be included in the next release. So far the code you've been writing has been good, but you've abused the output mechanism to include data to make it more human readable at the expense of programs trying to use volatility as a library. So you'll need to fix up any suggestions (or defend why you feel they're better as they are, and then we look for solutions that keep everybody happy). You can also take on board any comments I make and pre-emptively update your other submissions with those comments in mind, so that when I get time to review them, potentially issues have already been resolved. I hope this explains the process suitably for you? I wouldn't recommend becoming fixated on a specific release. As long as you can resolve any issues identified, they'll likely get merged. Exactly which version they'll make their debut in depends on how quickly that happens, and when the releases and code freezes happen too... |
sandbox_detect.py – Virtualization and Sandbox Environment Detection (Volatility 3 Plugin)
sandbox_detect.pyis a specialized Volatility 3 plugin designed for post-mortem forensic analysis of Windows memory dumps.Its primary goal is to detect and score artifacts indicating that the analyzed system was operating within a Virtual Machine (VM), Sandbox, or Malware Analysis Environment.
This plugin is particularly valuable for investigators who need to determine whether a captured memory sample originated from a controlled analysis setup or a real-world victim system.
Key Capabilities
Multi-Layered Artifact Scanning
Performs deep inspection across multiple memory and system layers to ensure comprehensive detection:
vmtoolsd.exe,vboxservice.exe,prl_cc.exe,wireshark.exe, andollydbg.exe.vmmouse.sys,vboxguest.sys, andvmhgfs.sys.such as hardware IDs, BIOS strings, and known VM installation paths.
Heuristic Scoring System
Implements a scoring engine that assigns severity levels to each identified artifact.
Instead of a binary result, the plugin produces a confidence-based verdict, such as:
This scoring model provides analysts with clearer, evidence-weighted conclusions.