TheMrEvil's picture
Remove internal duplicate-check section from card (not part of disclosure)
4fe03f5 verified
|
Raw
History Blame Contribute Delete
2.77 kB
# OpenCV FileStorage `decodeFormat` stack buffer overflow (CWE-787) PoC
Proof of concept for a **stack buffer overflow / out-of-bounds write** in OpenCV's `FileStorage`
data-type parser, triggered when a `Mat` is read from a crafted `.json` or `.yml` model file.
This repository is **gated**: the crafted files are weaponized inputs. Access is pre-granted to
`protectai-bot` for huntr review.
## What it is
`modules/core/src/persistence.cpp` β†’ `decodeFormat(const char* dt, int* fmt_pairs, int max_len)`
writes one `(count, depth)` int pair per type token of the `dt` string into `fmt_pairs`. It does
`max_len *= 2` and only stops when the index reaches `2 * 128 = 256` ints. But two callers declare
the destination at the 1x size:
| caller | line | buffer |
|---|---|---|
| `decodeSimpleFormat()` | persistence.cpp:319 | `int fmt_pairs[CV_FS_MAX_FMT_PAIRS]` (128) |
| `calcElemSize()` | persistence.cpp:269 | `int fmt_pairs[CV_FS_MAX_FMT_PAIRS]` (128) |
| `writeRawData` / `readRaw` / `parseBase64` | 1140 / 1838 / 2645 | `[CV_FS_MAX_FMT_PAIRS * 2]` (256) βœ” |
`CV_FS_MAX_FMT_PAIRS = 128`. A `dt` with more than 64 type pairs overflows the 128-int stack buffer
by up to ~512 bytes. The overflowing values are the pair counts, parsed with `strtol(dt)`, so they
are attacker-controlled.
`decodeSimpleFormat()` is reached at load time from the matrix reader
`read(const FileNode&, Mat&)` (`persistence_types.cpp:130`) on the file's `dt` field, **before**
any validation.
## Files
- `poc.json`, `poc.yml` β€” 1x1 matrix node `x` with a 120-pair `dt` (each count = `0x41414141`).
- `benign.json`, `benign.yml` β€” same files with a normal `dt`; load cleanly.
- `make_poc.py` β€” regenerates the files from a cv2-written valid skeleton.
- `verify.py` β€” child-process differential runner.
- `asan_repro.cpp`, `asan_report.txt` β€” standalone AddressSanitizer reproducer (the exact source of
`decodeFormat`/`decodeSimpleFormat`) and its report, deterministically showing
`stack-buffer-overflow WRITE of size 4`.
- `linux_verify.sh` β€” one-shot driver.
## Reproduce (Linux, `pip install opencv-python` ≀ 4.13.0)
```
python make_poc.py
python verify.py
# benign.json rc=0 loaded ok
# poc.json rc=-11 CRASH (SIGSEGV)
# poc.yml rc=-11 CRASH (SIGSEGV)
clang++ -O0 -g -fsanitize=address asan_repro.cpp -o asan_repro && ./asan_repro 120
# AddressSanitizer: stack-buffer-overflow WRITE of size 4 in decodeFormat
```
## Impact
Reading a `Mat` from an untrusted FileStorage file (directly, or via the `cv2.ml` model loaders
that persist as FileStorage) performs a controllable out-of-bounds stack write. Reliable outcome is
a process crash (DoS); ceiling is memory corruption / control-flow hijack subject to stack-protector
and ASLR.