tags: SSTI


Il runtime è il linguaggio/ambiente di programmazione su cui gira l’intera applicazione: Python, PHP, Java, Ruby, Node.js. È la “lingua madre” del server. Non lo scegli tu come attaccante, è una proprietà del sistema.

Il motore di template è una libreria che gira dentro quel runtime e che ha un solo compito: prendere un template (testo con dei segnaposto tipo {{nome}}) e riempirlo con dati per produrre l’output finale, di solito HTML. Jinja2, Twig, Handlebars, Django Template Language sono motori.

La relazione è di contenimento: un motore vive sempre dentro un runtime. Jinja2 è una libreria scritta in Python, quindi gira nel runtime Python. Twig è scritta in PHP, gira in PHP. Handlebars è scritta in JavaScript, gira in Node.js. Pensa al runtime come al motore dell’auto e al template engine come al navigatore montato sul cruscotto: il navigatore funziona solo perché c’è l’auto sotto, ma fa un lavoro suo e specifico.

Perché questa distinzione è cruciale per l’SSTI

Ed è qui che la cosa diventa pratica, non accademica. Quando sfrutti un’SSTI, l’attacco si svolge su due piani sovrapposti:

Il motore è la porta d’ingresso: determina la sintassi che devi iniettare ({{...}} vs ${...} vs <%...%>) e quanto è permissivo. È il livello che decide se riesci a evadere dal template.

Il runtime è la destinazione: una volta evaso dal motore, ti ritrovi a eseguire codice nel linguaggio sottostante. Per questo il payload finale di una RCE è sempre scritto nel linguaggio del runtime, non del motore. Guarda i casi che hai già visto:

  • Handlebars (motore) → evadi e finisci a scrivere require('child_process').exec(...), che è JavaScript, perché il runtime è Node.
  • Freemarker (motore) → la RCE passa per freemarker.template.utility.Execute, una classe Java, perché il runtime è la JVM.
  • Jinja2 (motore) → la catena __class__.__mro__.__subclasses__() è Python puro, perché il runtime è Python.

In tutti e tre i casi la tecnica di evasione dipende dal motore, ma l’arma finale dipende dal runtime. Il template engine è la serratura da scassinare; il runtime è la stanza in cui entri una volta aperta, e ciò che puoi rubare lì dentro dipende da come è arredata quella stanza, non dalla serratura.

L’eccezione che chiarisce la regola: Django

Il caso Django che ti ha confuso si spiega esattamente con questa distinzione. Il runtime è Python — potentissimo, capace di RCE. Ma il motore (Django Template Language) è una serratura blindata che non ti lascia raggiungere il runtime sottostante: blocca i dunder, non valuta espressioni arbitrarie. Quindi hai una stanza piena di tesori (Python) dietro una porta che non si scassina dall’interno del template. Ecco perché ripieghi sul leak invece che sulla shell: non perché Python sia limitato, ma perché quel motore specifico non ti fa arrivare a Python.

In una riga: il motore decide come entri, il runtime decide cosa puoi fare una volta dentro.