| --- |
| license: other |
| tags: |
| - security |
| - security-research |
| - vulnerability-poc |
| - caffe |
| - ncnn |
| - do-not-load |
| viewer: false |
| --- |
| |
| # ncnn `caffe2ncnn` Caffe-parser crashes β security-research PoC artifacts |
|
|
| > β οΈ **SECURITY RESEARCH ARTIFACTS β DO NOT CONVERT OR LOAD THESE FILES OUTSIDE AN ISOLATED, INTENTIONAL TEST ENVIRONMENT.** |
| > These `.prototxt` / `.caffemodel` files are **intentionally malformed** to crash a model converter. They are not neural networks, contain no useful weights, and must never be fed to a production or shared conversion pipeline. |
|
|
| This repository hosts the malicious model artifacts for a **coordinated, authorized vulnerability disclosure** submitted through the [huntr](https://huntr.com) Model File Vulnerability (MFV) program against `Tencent/ncnn`. |
|
|
| ## What this is |
|
|
| Three deterministic crashes in `tools/caffe/caffe2ncnn.cpp` (the Caffe β ncnn converter) β one root class: ncnn uses **file-controlled blob counts and kernel dimensions as divisors and array indices without validation**: |
|
|
| - **V1 β CWE-369 divide-by-zero (SIGFPE) at `caffe2ncnn.cpp:515`.** A `Deconvolution` layer with `kernel_w: 0, kernel_h: 1` makes `maxk = kernel_w * kernel_h = 0`; the next line divides `weight_blob.data_size()` by `maxk` β integer divide-by-zero. |
| - **V2 β CWE-129 / CWE-125 out-of-range `blobs(0)` (SEGV) at `caffe2ncnn.cpp:459`.** A `Deconvolution` layer whose `.caffemodel` entry has **zero blobs** makes `blobs(0)` a `RepeatedPtrField::Get(0)` on an empty field; in a release protobuf build (DCHECK compiled out) this dereferences unmapped memory. |
| - **V3 β CWE-476 null-pointer dereference (SEGV) at `caffe2ncnn.cpp:304`.** A `BatchNorm` layer with **3 blobs where the 3rd (scale) blob has empty `data`** passes the `blobs_size() < 3` guard but makes `blobs(2).data().data()[0]` dereference protobuf's null default pointer at address `0x0`. |
|
|
| Trust boundary: a developer downloads an untrusted pretrained Caffe model from a model zoo and runs `caffe2ncnn model.prototxt model.caffemodel out.param out.bin`. All three crashes are **denial-of-service only** β no controllable write, out-of-bounds read disclosure, or code execution is claimed. The same unvalidated-count class recurs in other layer branches (`BatchNorm` `:282`/`:283`, `Convolution` `:344`, etc.). |
|
|
| ## Files |
|
|
| | File | Triggers | |
| |------|----------| |
| | `evil.prototxt` + `evil.caffemodel` | **V1** β divide-by-zero (SIGFPE) at `:515`. Deconvolution `kernel_w=0 β maxk=0`. | |
| | `oob.prototxt` + `oob.caffemodel` | **V2** β out-of-range `blobs(0)` (SEGV) at `:459`. Deconvolution layer with zero blobs. | |
| | `bn.prototxt` + `bn.caffemodel` | **V3** β null-pointer deref (SEGV @ `0x0`) at `:304`. BatchNorm with 3 blobs, empty 3rd blob. | |
| | `craft.py` / `craft_oob.py` / `craft_bn.py` | Scripts that regenerate the three model pairs from ncnn's bundled `caffe.proto`. | |
| | `ASAN-OUTPUT.txt` / `ASAN-OUTPUT-oob.txt` / `ASAN-OUTPUT-bn.txt` | AddressSanitizer transcripts for V1, V2, V3 (FPE at `:515`; SEGV in `RepeatedPtrField::Get` via `:459`; null-deref SEGV at `:304`). | |
|
|
| ## Reproduce (isolated environment only) |
|
|
| Build `caffe2ncnn` from ncnn @ `dda2e28` (release protobuf; add `-fsanitize=address -g` for a deterministic signal with a source line), then: |
|
|
| ```bash |
| # V1 β SIGFPE at caffe2ncnn.cpp:515 |
| ./caffe2ncnn evil.prototxt evil.caffemodel out.param out.bin |
| |
| # V2 β SEGV at caffe2ncnn.cpp:459 |
| ./caffe2ncnn oob.prototxt oob.caffemodel out.param out.bin |
| |
| # V3 β SEGV (null deref) at caffe2ncnn.cpp:304 |
| ./caffe2ncnn bn.prototxt bn.caffemodel out.param out.bin |
| ``` |
|
|
| See the huntr report for the full build recipe and write-up. |
|
|
| ## Responsible use |
|
|
| Published solely to give the huntr triage team a reproducible artifact for coordinated disclosure. Do not redeploy, repackage, or convert these files against any system you do not own and intend to test. Reporter: **Ano1X8** (@ano1x8). |
|
|