| joblib-01 PoC: MemorizedFunc / MemorizedResult pickle state forgery |
|
|
| Two crafted joblib artifacts, each 403 and 317 bytes. Neither contains a |
| dangerous pickle opcode; picklescan and modelscan both report 0 issues on |
| both files. The bug is not in joblib.load itself, it is in what happens |
| when victim code calls the documented .clear() or .get() method on the |
| object joblib.load just returned. |
|
|
| joblib01_malicious_clear_gadget.joblib |
| Forged MemorizedFunc with a path-traversal func_id. Loading it is inert. |
| Calling .clear(warn=False) on the loaded object reaches |
| StoreBackendMixin.clear_path -> shutil.rmtree on a path outside the |
| configured cache directory, deleting an attacker-chosen directory tree |
| anywhere the process can write. |
| |
| joblib01_malicious_get_gadget.joblib |
| Forged MemorizedResult with a path-traversal _call_id. Loading it is |
| inert. Calling .get() on the loaded object reaches |
| StoreBackendMixin.load_item -> numpy_pickle.load on a second, |
| attacker-planted file at a predictable redirected path. That second file |
| (joblib01_stage2_output.pkl in this repo, normally placed at |
| output.pkl inside the redirected directory) is a fresh, unrestricted |
| pickle stream and can contain any REDUCE-based payload, giving full code |
| execution. The delivered .joblib file itself never contains that payload, |
| so a scanner that only inspects the delivered file sees nothing. |
|
|
| Full root cause, call chain, and reproduction script are in the huntr |
| report and in the workspace finding joblib-01-memorizedfunc-memorizedresult-state-forgery-path-escape.md. |
|
|