Skip to content

v4.0.0 — Hardened output directory and shutdown, look-alike hosts kept, real-dump CI

Latest

Choose a tag to compare

@gl0bal01 gl0bal01 released this 29 Oct 14:35

A hardening release. Output can no longer be redirected or mixed up through the output directory, and an interrupted run no longer leaves a broken symbol file in Volatility's cache. IOC lists keep look-alike hosts instead of dropping them. A monthly workflow now runs the latest Volatility 3 on real Linux, Windows 10 and macOS images. It is a major release because the output directory must now be new or empty.

Changed

  • Breaking: the output directory must be new or empty, the default volatility_output included: a second plain vol-analyze run in the same directory stops with "Output directory is not empty". Pass a new -o directory per dump. Why: see the first two Security entries.

Security

  • The output directory is entered once and then written through relative paths. Every write used to resolve the path again, so someone who can write to a parent directory (a shared case folder, or the current directory of a sudo run) could swap in a directory with planted symlinks mid-run: it received the hashdump, and strings/all.txt could overwrite any file the analyst can write.
  • An existing output directory must be empty, as with bulk_extractor. Entries planted earlier (symlinks, world-readable files) were written through, and a second run into the same directory mixed two dumps' results: the text report named the new dump while analysis_summary.json kept the old one's hashes. Scripts that reuse an output directory must pass a new one.
  • strings/domains_lowconf.txt: names that match a noise filter (minified JS, file names, all-numeric, all-caps or mixed-case TLDs, ELF section names) are kept there instead of being dropped, so a host registered to look like noise (evil.app, navigator.top, 4444.top, q.ai, Evil-C2.Top) is never lost. Only names that cannot be registered (no IANA TLD, closed brand TLDs) are dropped. 28,277 entries on Windows 10, 1,058 on Windows 7, 8,029 on Debian 7, 5,121 on macOS 10.9.
  • Control characters (C0, DEL, and C1 as UTF-8) in any argument (dump, output, --symbols and --isf-url paths, option values, VOL3_CMD) are refused, also when a symlinked directory brings them into a resolved path: a file name with newlines forged lines (MD5, plugin status) in the text report, and escape sequences reached the terminal. Unknown options are shown shell-quoted.
  • A relative dump path is made absolute before vol sees it: vol read http://host/mem.raw (a local directory named http:) as a URL and fetched it, so the recorded hashes and the analysis covered different data.
  • -o through a symlink to a system directory (/etc), or to a directory below one that did not exist yet (/tmp/../etc/new/dir), got past the blocklist; the nearest existing parent is resolved to its physical path now (macOS /private/etc included), and the directory is checked again once entered. .. after a directory that does not exist yet (-o new/../../etc/x) is refused, as it cannot be resolved before mkdir.
  • A backslash in the output path (-o 'case\001') silently emptied domains.txt (awk -v decodes escapes) and could redirect a temporary file outside the output directory.
  • CI checkouts no longer keep the GITHUB_TOKEN in .git/config (persist-credentials: false).

Added

  • Monthly "Real dumps" workflow (make real-test locally, make ci-real for every CI step): runs vol-analyze with the latest Volatility 3 release on public Linux (Debian), Windows 10 and macOS 10.9 images, all pinned by SHA-256, with OS auto-detection, as in the Quick Start, and fails when the OS is misdetected, a plugin fails (outside a short list of known Volatility 3 bugs), the reports miss the symbols used, or the IOC lists lose a known host. The fake-vol tests cannot catch upstream plugin or CLI changes; this does.
  • make check-tlds fails when IANA's TLD list has changed since the last make update-tlds; it runs in the monthly workflow.
  • strings/reverse_dns.txt: reverse-DNS identifiers (com.apple.audio, org.example.app) are split out of domains.txt instead of being dropped. On a macOS 10.9 image they were 36% of all domain hits (com.apple alone 43,596): 537 names move out, leaving 20,136 domains.
  • SECURITY.md with private vulnerability reporting, and a bug report form.
  • make hooks runs make ci before every git push (versioned .githooks/pre-push).
  • Release tags are SSH-signed, starting with v4.0.0.
  • The text and JSON reports name the symbol table Volatility actually used ("Symbols Used" / execution.symbols_used): the ISF file or URL on Linux/macOS, the kernel PDB name and GUID on Windows. It is read from the first plugin's debug log (vol.log). "ISF URL: none" could hide a remote ISF that Volatility had cached on an earlier --isf-url run and kept using.
  • strings/domains.txt matches all-caps hosts with three or more labels and a 2–3 letter TLD (LOGIN.LIVE.COM). Names are counted lower-cased, so GitHub.com and github.com add up.
  • strings/ipv4.txt on macOS dumps reads netstat's address.port form (10.0.0.5.443 → 10.0.0.5).

Fixed

  • OS auto-detection stopped a slow probe with SIGTERM, which kills vol without running its cleanup: a probe cut short while vol downloaded the Windows kernel PDB could leave a broken symbol file behind for every later run. Probes are now stopped with SIGINT (and killed 10 s later if that is ignored). The script times the probes itself, so timeout/gtimeout is no longer needed (uutils timeout, the default on Ubuntu 26.04, does not deliver -s INT); VOL_DETECT_TIMEOUT=0 means no limit. Likewise, Ctrl-C or SIGTERM to vol-analyze stops running vol processes with SIGINT (after 2 s, which a Ctrl-C in the terminal needs to reach them first), and with SIGTERM only if they are still running 5 s after that.
  • analysis_summary.json was not valid UTF-8 for a file name in another encoding (caf\xe9.raw); such a path is written shell-quoted ($'caf\351.raw').
  • strings output is folded into lines of at most 8 KiB: one printable run of gigabytes in the image made grep and sed hold all of it in memory. An interrupted run stops strings too, and a strings failure partway through is reported.
  • -o with a directory name starting with - failed in mkdir.
  • Ctrl-C did not stop a shell loop over several dumps (for f in *.raw; do vol-analyze "$f" -o "$f.out"; done): vol-analyze exited with status 130, which tells the calling shell the interrupt was handled; it now ends by SIGINT.
  • A name followed by an underscore, alone or before a number (c2.evil.top_, c2.evil.top_443), was lost from domains.txt.
  • Bash completion of --isf-url offered nothing once the URL contained : (https:), because readline splits words at colons.
  • strings/domains.txt noise on real dumps (Windows 10, Windows 7 CTF image, Debian 7). Moved to domains_lowconf.txt: minified JavaScript (this.id, t.name; one-letter names stay domains on .com/.net/.org/.me: x.org, t.me), Windows prefetch names (CMD.EXE-CD245F9E.pf), .NET names (System.IO), ELF section and GNU tar header names by exact name (note.gnu.build, data.rel.ro, gnu.linkonce.td, rela.got, text.hot, gnu.sparse.map). Dropped: closed brand TLDs that clash with code names (e.target, Date.now, microsoft.windows, wscript.shell). URL escapes no longer glue onto names (2Fwww.w3.org, %252F double encoding included). Rules keyed on a first label (JS globals such as self, window) only apply to two-label names, so a subdomain an attacker picks (self.c2-panel.top) stays in domains.txt. 81,370 → 78,781 entries on Windows 10, 810 → 761 on Windows 7, 9,327 → 9,147 on Debian 7 (reverse-DNS identifiers now go to reverse_dns.txt: 190, 0 and 30).
  • strings/ipv4.txt kept 0.x.x.x addresses, which are version strings: 784 → 511 entries on Debian 7, 2,531 → 2,503 on Windows 10, 269 → 266 on Windows 7.