SSTI
| Po angielsku | server-side template injection (SSTI) |
|---|---|
| Którą formą pisać | po angielsku Polski odpowiednik istnieje, ale w praktyce nikt tak nie pisze. Zostaw angielski, polski trzymaj jako synonim. |
| Inne formy | Server-Side Template Injection · wstrzyknięcie szablonu po stronie serwera · wstrzyknięcie do szablonu |
| Kategoria | Podatności i klasy błędów |
SSTI (Server-Side Template Injection) to podatność, w której dane od użytkownika trafiają do szablonu renderowanego na serwerze jako kod szablonu, a nie jako zwykły tekst. PortSwigger definiuje ją jako sytuację, w której atakujący może użyć natywnej składni szablonów, by wstrzyknąć do szablonu złośliwy ładunek, wykonywany następnie po stronie serwera [1]. MITRE klasyfikuje ten błąd jako CWE-1336, czyli brak neutralizacji elementów specjalnych używanych przez silnik szablonów [2]. Najpoważniejszym skutkiem jest zdalne wykonanie kodu (RCE) [1].
Jak działa
Silnik szablonów, taki jak Twig, Jinja2 czy Smarty, oddziela wygląd strony od danych. Szablon zawiera znaczniki z wyrażeniami, a silnik podstawia pod nie wartości i wykonuje proste operacje. MITRE zwraca uwagę, że silniki te interpretują własną składnię wyrażeń, więc dane atakującego, które dotrą do szablonu bez neutralizacji, zostaną potraktowane jak wyrażenie [2].
Według PortSwigger źródłem problemu jest doklejanie danych od użytkownika do treści szablonu zamiast przekazywania ich jako osobnych danych [1]. Różnicę widać w przykładzie z Twigiem. W pierwszym wariancie tekst z żądania staje się częścią kodu szablonu, w drugim szablon jest stały, a imię trafia do niego jako zmienna.
// podatne: tekst od użytkownika staje się kodem szablonu
$szablon = $twig->createTemplate( 'Witaj ' . $_GET['imie'] );
echo $szablon->render();
// bezpieczne: stały szablon, imię przekazane jako dane
$szablon = $twig->createTemplate( 'Witaj {{ imie }}' );
echo $szablon->render( array( 'imie' => $_GET['imie'] ) );
Test takiego miejsca polega na podaniu prostego wyrażenia arytmetycznego w składni szablonu. MITRE opisuje, że jeśli w odpowiedzi pojawi się wynik działania zamiast wpisanego tekstu, wyrażenie zostało wykonane [2]. PortSwigger opisuje metodykę w trzech krokach, pokazanych na schemacie poniżej [1].
Odmiany i silniki
PortSwigger rozróżnia dwa konteksty wstrzyknięcia: tekstowy, gdy dane trafiają do zwykłej treści szablonu, i kodowy, gdy lądują wewnątrz istniejącego wyrażenia [1]. MITRE podaje też odmianę kliencką, CSTI, gdy szablon renderuje przeglądarka [2]. Podatne mogą być silniki w wielu językach [7]. MITRE wśród przykładów wymienia Twig, Jinja2, Pug, FreeMarker i Velocity [2].
| Silnik | Język | Przykład z publikacji |
|---|---|---|
| Twig | PHP | CVE-2020-12790 [2], WPML [4] |
| Smarty | PHP | omówiony przez Sekuraka [7] |
| Jinja2 | Python | CVE-2024-34359 [2] |
| FreeMarker, Velocity | Java | omówione przez Sekuraka [7] |
W WordPressie
Rdzeń WordPressa nie używa zewnętrznego silnika szablonów; motywy są plikami PHP. SSTI pojawia się więc w podatnych wtyczkach, które dołączają własny silnik, najczęściej Twig.
Głośny przypadek dotyczył wtyczki WPML. Według Qualys luka CVE-2024-6386 otrzymała wynik CVSS 9,9 i obejmowała wszystkie wersje do 4.6.12 włącznie [4]. Źródłem była niewystarczająca walidacja w funkcji render() przy obsłudze shortcode'u [wpml_language_switcher], który przetwarzał szablony Twig [4]. Atakujący z kontem na poziomie Contributor mógł wykonać kod na serwerze [4]. Wtyczka ma ponad milion aktywnych instalacji, a poprawkę przyniosła wersja 4.6.13 [4].
Przykład pokazuje, że role i uprawnienia użytkowników same nie zatrzymują SSTI: do wykonania kodu wystarczyło konto o niskich uprawnieniach [4]. Każda wtyczka, która składa szablon z treści wpisu, atrybutów shortcode'u albo pól formularza, powinna być oceniona pod tym kątem.
Zagrożenia i skutki
PortSwigger wskazuje, że SSTI może dać atakującemu pełną kontrolę nad serwerem przez zdalne wykonanie kodu, a nawet gdy to się nie uda, dostęp do danych wrażliwych i dowolnych plików [1]. Sekurak podkreśla, że w większości przypadków rezultatem wykorzystania podatności jest wykonanie dowolnego kodu na maszynie ofiary [7]. MITRE jako skutek podaje wykonanie nieautoryzowanego kodu lub poleceń [2].
James Kettle z PortSwigger zwrócił uwagę, że SSTI łatwo pomylić z XSS (Cross-Site Scripting) albo w ogóle przeoczyć [3]. Objawy bywają podobne, bo dane wracają w odpowiedzi strony, lecz skutki są inne: XSS uderza w przeglądarkę użytkownika, a SSTI w serwer. Wśród przykładów MITRE jest luka CVE-2018-20465, w której wstrzyknięcie do szablonu ujawniało dane dostępowe do bazy [2], czyli ujawnienie informacji. W polskim przypadku opisanym niżej skutkiem było zdalne wykonywanie poleceń systemu [6], co odpowiada wstrzyknięciu poleceń.
Jak się bronić
Podstawą jest zasada, by dane użytkownika nigdy nie stawały się treścią szablonu, tylko wartościami przekazywanymi do stałego szablonu [1]. PortSwigger zaleca także silniki bez logiki, takie jak Mustache, uruchamianie niezaufanego kodu w piaskownicy i umieszczanie środowiska szablonów w zamkniętym kontenerze [1]. MITRE radzi wybierać silniki z trybem piaskownicy lub trybem ograniczonym i z tych trybów korzystać [2].
Twig oferuje rozszerzenie Sandbox. Dokumentacja opisuje je jako sposób na ocenę niezaufanego kodu, w którym polityka bezpieczeństwa wymienia dozwolone znaczniki, filtry, funkcje oraz właściwości i metody obiektów [5]. Użycie niedozwolonej operacji kończy się błędem bezpieczeństwa [5]. Dopełnieniem są sanityzacja danych wejściowych, zasada najmniejszych uprawnień dla procesu serwera WWW i szybkie wdrażanie poprawek wtyczek.
Historia i przykłady
Klasę SSTI opisał James Kettle z PortSwigger w publikacji z 5 sierpnia 2015 roku [3]. Kettle podkreślał, że w odróżnieniu od XSS wstrzyknięcie szablonu pozwala atakować bezpośrednio wnętrze serwera i często prowadzi do zdalnego wykonania kodu [3]. W Polsce Sekurak pisał w 2017 roku, że o tej klasie podatności zrobiło się głośno dopiero w ostatnim czasie [7].
W ekosystemie WordPressa lukę w WPML zgłoszono w czerwcu 2024 roku, a w pełni usunięto w sierpniu tego samego roku [4]. Qualys opublikował swój opis 27 sierpnia 2024 roku i zalecał aktualizację do wersji 4.6.13 [4].
CERT Polska 2 czerwca 2026 roku opisał lukę CVE-2026-34906 w systemie Wirtualna Uczelnia firmy Simple SA [6]. Niewystarczająca walidacja w punkcie końcowym redirectToUrl pozwalała nieuwierzytelnionemu atakującemu wstrzykiwać wyrażenia wykonywane po stronie serwera, co prowadziło do zdalnego wykonania poleceń [6]. Lukę sklasyfikowano jako CWE-1336 [6].
Przypisy
7- [1] Server-side template injection — Web Security Academy · PortSwigger
- [2] CWE-1336: Improper Neutralization of Special Elements Used in a Template Engine · MITRE
- [3] Server-Side Template Injection (James Kettle) · PortSwigger Research
- [4] WordPress Plugin WPML Multilingual CMS Server-Side Template Injection Vulnerability (CVE-2024-6386) · Qualys ThreatPROTECT
- [5] Twig Sandbox Extension · Symfony / Twig
- [6] Podatności w oprogramowaniu Wirtualna Uczelnia (CVE-2026-34906, CVE-2026-34907) · CERT Polska
- [7] Podatność Server-Side Template Injections · Sekurak