Automatic Linux ISF resolution, YARA scan scope + rule de-duplication, plugin catalog maintenance, and dumpfile fix (#45) - #46
Open
imb0ru wants to merge 7 commits into
Open
Conversation
Collaborator
|
Hi @imb0ru thanks for the PR ! Cheers ! |
…prove plugin status messaging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Feature: automatic Linux kernel symbol (ISF) resolution
Linux memory analysis in Volatility3 requires an Intermediate Symbol File (ISF) matching the exact kernel banner of the image. Until now the analyst had to build that ISF and upload it manually before any Linux plugin could run. This adds end to end automatic resolution.
How it works
When a Linux evidence is added, a background task:
banners.Banners),Abyss-W4tcher/volatility3-symbols,banners_plain.json) and downloads it,linux.pslist,Symbol(so it shows up in the Symbols page) and marks the evidence ready.Plugin extraction and YARA scanning for Linux evidences are gated until symbols are
ready. If no ISF can be imported, the UI shows the detected banner plus precise manual build guidance (the exact dbgsym package anddwarf2jsonsteps, with an Ubuntu specific package/URL derived from the banner). Deleting the ISF re-validates and re-closes the gate, and a re-fetch button plus manual upload re-verification are available.Changes
Backend
backend/volatility_engine/models.py: newLinuxSymbolResolutionmodel (statusdetecting/resolving/verifying/ready/failed_banner/failed_isf, plus banner, method and manual guidance).backend/volatility_engine/isf.py: remote index lookup (exact match, then kernel version + build fallback), download into the Volatility symbol path, and manual build guidance builder.backend/volatility_engine/engine.py:detect_linux_banner()andverify_linux_symbols().backend/volatility_engine/tasks.py:generate_linux_symbols(auto on evidence creation) andreverify_linux_symbols(re-validates on manual ISF upload or deletion, opening or closing the gate).backend/volatility_engine/views.py:SelectiveExtractionTaskandYaraScanTaskreturn409for Linux until the ISF is ready; newIsfResolutionView(GET/POST /api/evidence/<id>/isf/) for status and on demand re-fetch. Triggers wired inevidences/signals.py(creation) andsymbols/signals.py(upload/deletion).volatility_engine(0002_volatilityplugin_error_message,0003_linuxsymbolresolution).Frontend
frontend/src/components/Investigate/PluginSelector.tsx: live ISF status panel (banner, guidance, Retry), a success toast when symbols are ready, and the "Start Analysis" button disabled until ready (Linux only).Maintenance: Volatility3 plugin catalog updates + admin diff tool
The curated plugin list (
volweb_plugins.json/volweb_misc.json) had drifted from the pinned volatility3 version, which had reorganized many plugins into<os>.malware.*and emitted deprecationFutureWarnings.malwarenamespace, fixing two class renames along the way (linux.tty_check.tty_checktolinux.malware.tty_check.Tty_Check,windows.unhooked_system_calls.unhooked_system_callstowindows.malware.unhooked_system_calls.UnhookedSystemCalls). This clears the deprecation warnings.vadinfo,mftscan,etwpatch,registry.printkey.backend/volatility_engine/admin.py): compares the curated list against the plugins actually exposed by the installed volatility3 (framework.list_plugins()), automatically hiding deprecated aliases and YARA scanning plugins (handled separately). It has zero runtime impact and does not touch the shared context optimization; it just makes updating the curated list deliberate when the pinned volatility3 version is bumped.Bug fix: dump_file task 'int' object is not iterable (ISSUE #45)
The error occurred when clicking the "Dump" button on a file found by the FileScan plugin.
In Volatility3, the
virtaddrandphysaddrparameters of theDumpFilesplugin are defined asListRequirement(element_type=int), meaning they expect a list of integers. The code was passing a plainint(offset)instead, causing the'int' object is not iterableerror during the automagic execution phase.Fix: In
backend/volatility_engine/engine.py, in bothdump_file_windowsanddump_file_linuxmethods, the values passed to the configuration are now wrapped in a list:Before
After
Feature: YARA scan scope selection (process memory vs kernel)
Adds an explicit choice between two complementary Volatility plugins when running a YARA scan, fixing a silent zero matches bug on user space malware (e.g. ransomware payloads).
Problem
The original implementation invoked
volatility3.plugins.yarascan.YaraScan, which operates only on the primary (kernel) layer of the dump. As a result, scans against memory dumps containing well known user space malware returned 0 matches even when the payload was known to be present. Every artefact that lives in user space (mutex strings, command lines, registry path strings, encryption routine constants, PE images of injected modules) was outside the scanned region.Fix
Introduces a
scan_scopeparameter end to end that selects the appropriate Volatility plugin, per OS:"vad"(default)windows.vadyarascan.VadYaraScan(Windows, VADs) /linux.vmayarascan.VmaYaraScan(Linux, VMAs)"kernel"yarascan.YaraScanWindows regions are VADs, Linux regions are VMAs, so the two OSes expose the same per process concept under different plugin names.
Changes
Backend
backend/volatility_engine/engine.py:run_yara_scan(..., scan_scope="vad")picks the plugin class and config prefix based on scope and evidence OS. Theyara_fileconfig is set under both the per process prefix andplugins.YaraScanto cover the embedded scanner it delegates to.backend/volatility_engine/tasks.py:start_yarascan(..., scan_scope="vad")threads the parameter through all invocation paths and logs the active scope.backend/volatility_engine/views.py:YaraScanTaskreads and validatesscan_scopeagainst{"vad", "kernel"}.Frontend
frontend/src/components/Investigate/YaraScan.tsx:scanScopestate (default"vad"), aRadioGroupabove the rulesets/rules panels. The "Process memory" option is OS aware and shows the correct plugin id and region (VAD on Windows, VMA on Linux). The scope is sent asscan_scopein the scan payload and the control is disabled while a scan runs.Backwards compatibility
The parameter is optional with a sensible default (
"vad"), so existing clients keep working.Bug fix: Linux process memory YARA scan referenced a non existent plugin
The engine selected
linux.vadyarascan.VadYaraScanfor the Linux "vad" scope, but Linux has novadyarascan(it uses VMAs,linux.vmayarascan.VmaYaraScan), so a Linux process memory YARA scan raised anImportError. Windows was unaffected. Fixed to useVmaYaraScanon Linux, and the frontend scope label was made OS aware accordingly.Bug fix: YARA scan error handling + duplicate-identifier crash
Duplicate rule identifiers aborted the whole scan
When several rules (typically from overlapping community rulesets) declare the same identifier,
yara.compileraises aduplicated identifierSyntaxErrorand the entire scan fails.backend/volatility_engine/engine.pynow de-duplicates the combined rules before compilation (_dedupe_yara_rules): it keeps the first occurrence of each rule identifier, collapses duplicateimport/includestatements, and logs the dropped identifiers. The scan then runs on the union of the distinct rules instead of failing outright.Failed scans were reported as success
run_yara_scannow has a clear contract (True= matches,False= no matches,None= could not run) and raises on real failures instead of swallowing them.start_yarascantreatsNone/failure as an error and notifies the UI accordingly, so a broken scan no longer shows a phantom "completed successfully".Feature: content-based de-duplication of YARA rules
Previously rule de-duplication happened only at scan time (by identifier, in the engine). Nothing prevented the same rule from being stored many times. This adds global, content based de-duplication across the whole database.
How it works
content_hashfield onYaraRule(backend/yararules/models.py): a normalized SHA-256 ofrule_content(stable against line ending / whitespace / blank line differences), kept in sync automatically insave(). Indexed, not unique, so uniqueness is enforced in application code and legacy data with pre existing duplicates migrates cleanly.backend/yararules/utils.py:compute_content_hash,backfill_content_hashes(idempotent) andget_existing_content_hashes.Behaviour by entry point
skipped_duplicates)400with a clear message naming the existing rule400(it is a duplicate)400Bulk imports skip and report (so one duplicate does not fail an import of hundreds of rules), while a single manual submission returns an explicit error.
Changes
Backend
backend/yararulesets/views.py: the chunked upload (CompleteUploadView) and GitHub import (GitHubImportView) check each rule's content hash against the DB and against rules seen earlier in the same batch, skip duplicates, count them, and returnskipped_duplicates. AnetagIntegrityErroris now caught and treated as a duplicate.backend/yararules/serializers.py:YaraRuleSerializer.validaterejects manual create/update whose content duplicates an existing rule (excluding the instance being edited).Frontend
frontend/src/components/Dialogs/YaraRuleCreationDialog.tsx+frontend/src/components/Lists/YaraRuleList.tsx: import dialogs report e.g. "Upload complete: N created, M duplicate(s) skipped".frontend/src/components/Dialogs/YaraRuleEditDialog.tsx: the save error handler surfaces DRF field errors (the duplicate content message) instead of a generic "Request failed with status code 400".Infrastructure fix: versioned migrations + single migrator
Adding schema changes (the
content_hashcolumn, then theLinuxSymbolResolutionmodel) exposed two pre existing problems.Versioned migrations
yararules,yararulesetsandvolatility_enginerelied on the entrypoint regenerating0001_initialon every boot. Django tracks applied migrations by name, so once0001_initialwas recorded, any newly added field or model was never materialized and the schema silently drifted (DuplicateColumnon rebuild). This PR commits real, versioned migrations:backend/yararulesets/migrations/0001_initial.pybackend/yararules/migrations/0001_initial.py+0002_yararule_content_hash.pybackend/volatility_engine/migrations/0002_volatilityplugin_error_message.py+0003_linuxsymbolresolution.pyThe initial migrations reflect the original models (matching what existing databases already have applied) and the incremental ones add the new schema, so changes apply correctly on both fresh and existing deployments.
Single migrator (race condition)
The entrypoint ran
makemigrations+migratein every service (backend + both workers) at startup, so concurrentmigrateruns raced on the same DDL.backend/entrypoint.sh: migrations /collectstatic/initadminnow run only whenRUN_MIGRATIONS=true.docker-compose.yaml/docker-compose-prod.yaml: onlyvolweb-backendsetsRUN_MIGRATIONS=true; the workersdepends_onthe backend so the schema is migrated first.