Share
## https://sploitus.com/exploit?id=2A6F1FD3-4D06-50EA-A607-1FBB54C574D2
# PoC โ `stb_image` v2.30 GIF `stbi__out_gif_code` ๋ฌดํ ์ฌ๊ท (DoS)
๋์: [`nothings/stb`](https://github.com/nothings/stb) โ `stb_image.h` v2.30
์ทจ์ฝ ์์น: `stb_image.h` ๋ผ์ธ 6661 โ `stbi__out_gif_code()`
์นดํ
๊ณ ๋ฆฌ: **CWE-674** (Uncontrolled Recursion) โ Denial of Service via stack exhaustion
์ํฅ: ์์ stack ํ๊ฒฝ(Windows main thread 1 MB ๊ธฐ๋ณธ, pthread ์ถ์ stack, ์๋ฒ ๋๋)์์ SIGSEGV/access violation crash. ํฐ stack ํ๊ฒฝ(Linux 8 MB)์์๋ stack ์๋ฐ ๋ฐ์.
## ๊ฒฐํจ ์์ฝ
```c
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{
...
if (g->codes[code].prefix >= 0)
stbi__out_gif_code(g, g->codes[code].prefix); // โ ๋ฌดํ ์ฌ๊ท, ๊น์ด ์ ํ ์์
...
}
```
LZW prefix chain์ `avail โค 8192`๋ก๋ง ์ ํ๋จ โ ๊ณต๊ฒฉ์๊ฐ ํ๋์ ์ ํ chain์ ์ฝ **8190** entries๊น์ง ๋ง๋ค ์ ์์ โ `stbi__out_gif_code`๊ฐ ์ฝ **8190 ๊น์ด** ์ฌ๊ท.
## ํ๊ฒฝ๋ณ ์ํฅ
| ํ๊ฒฝ | ๊ธฐ๋ณธ stack | ๊ฒฐํจ ์ํฅ |
|---|---|---|
| Linux x86_64 main thread | 8 MB | ์๋ฐ, ๋ณดํต crash ์ ํจ |
| **Windows main thread** | **1 MB** | **stack overflow โ access violation** |
| **pthread default** (`pthread_attr_init`) | **2 MB** | ๋ค๋ฅธ stack ์ฌ์ฉ๋๊ณผ ํฉ์ฐ ์ crash ๊ฐ๋ฅ์ฑ |
| **embedded RTOS / IoT** | 4-64 KB | **์ฆ์ stack overflow** |
| Linux `ulimit -s 256` (256 KB) | 256 KB | ๊ฒฐ์ ๋ก ์ SIGSEGV (PoC๊ฐ ์ด๊ฑธ๋ก ๊ฒ์ฆ) |
## Trigger ๋ฉ์ปค๋์ฆ
LZW chain ๊ตฌ์ฑ:
1. `lzw_min_code_size = 2` โ `clear=4`, `end=5`, `avail` ์์ 6.
2. literal `0` ์ก์ถ โ `oldcode = 0`, `g->codes[0..3]`๋ง init (`prefix = -1`).
3. ๊ฐ iter์์ ํ์ฌ `avail` ๊ฐ์ ๊ทธ๋๋ก ์ก์ถ โ stb_image๊ฐ `codes[avail].prefix = oldcode`๋ก set, ๊ทธ ํ ์ฌ๊ท ํธ์ถ. `oldcode`๋ ์ code๋ก ๊ฐฑ์ .
4. 8000+ iter ๋ฐ๋ณต โ chain ๊ธธ์ด = iter ์ + 1.
5. end-of-stream `5` ์ก์ถ.
๊ฐ ์ entry์ prefix๋ ์ง์ entry โ chain ์ ํ. `out_gif_code(latest)` ํธ์ถ ์ latest โ latest-1 โ latest-2 โ ... โ 0 (prefix=-1) ๊น์ง ์ฌ๊ท.
## ํ์ผ ๊ตฌ์ฑ
| ํ์ผ | ์ค๋ช
|
|---|---|
| `generate_poc_gif.py` | 1ร1 GIF ์์ฑ๊ธฐ (`--depth N`๋ก chain ๊ธธ์ด ์กฐ์ , ๊ธฐ๋ณธ ~8184) |
| `poc.c` | `stbi_load(...)` ํธ์ถ์ + RLIMIT_STACK ์ถ๋ ฅ |
| `build_and_run.sh` | upstream fetch + ๋น๋ + ๋ ๋ฒ ์คํ (๊ธฐ๋ณธ stack / `ulimit -s 256`) |
| `README.md` | ์ด ๋ฌธ์ |
## ์ฌํ (Linux)
```bash
chmod +x build_and_run.sh
./build_and_run.sh
```
์คํฌ๋ฆฝํธ๋ ๋ ๋ฒ ์คํ:
1. **๊ธฐ๋ณธ stack**: ๋ณดํต ์ ์ ์ข
๋ฃ (chain ๋ชจ๋ ์ฒ๋ฆฌ๋๊ณ GIF๋ 1ร1๋ก ๋์ฝ๋ โ stb์ raster boundary ๊ฒ์ฌ๊ฐ ๋ค catch).
2. **`ulimit -s 256`**: SIGSEGV (exit 139). ๊ฒฐํจ ์ฆ๋ช
.
## ์ฌํ (Windows)
```powershell
# wget์ PowerShell ๋ด์ฅ alias
Invoke-WebRequest https://raw.githubusercontent.com/nothings/stb/master/stb_image.h -OutFile stb_image.h
python generate_poc_gif.py poc.gif
gcc -O0 -g poc.c -o poc.exe # MinGW
.\poc.exe poc.gif
# -> EXCEPTION_STACK_OVERFLOW (Windows ๊ธฐ๋ณธ main thread stack 1 MB)
```
`/STACK:524288` ๊ฐ์ ์์ stack์ผ๋ก linkํ๋ฉด ๋ ๊ฒฐ์ ๋ก ์ ์ผ๋ก crash.
## ์ํฅ ๋ถ์
- **Severity**: Medium-High.
- **๊ณต๊ฒฉ ๋ฒกํฐ**: ์ ๋ขฐ๋์ง ์์ GIF๋ฅผ ์ฒ๋ฆฌํ๋ ๋ชจ๋ ์ฌ์ฉ์ฒ.
- ๊ฒ์ ๋ก๋ฉ ์ ์ฌ์ฉ์ mod์ GIF asset
- chat/๋ฉ์ ์ thumbnail ์์ฑ service
- browser/๋ทฐ์ด pre-render
- ์๋ฒ ๋๋ IoT (e.g. e-paper display, ์นด๋ฉ๋ผ)
- **Reliability**: ๋งค์ฐ ๋์. ๊ตฌ์กฐ์ ๊ฒฐํจ (์ฌ๊ท ๊น์ด ์ ํ ์์). ํ๋ฅ ์ฑ ์์.
- **Chain ๊ฐ๋ฅ์ฑ**: stack overflow๊ฐ ์ธ์ ๋ฉ๋ชจ๋ฆฌ(๋ค๋ฅธ thread stack, heap guard ๋ฑ)์ ๋ฟ์ผ๋ฉด ์ถ๊ฐ ์ํฅ. ASLR/canary ์ฐํ์ ๊ฒฐํฉ ์ RCE ๊ฐ๋ฅ์ฑ๋ ์ด๋ก ์ ์ผ๋ก ์กด์ฌ (๋จ, ์ผ๋ฐ์ ์ผ๋ก๋ DoS).
## ํจ์น ์ ์
**์ต์
A** โ ์ฌ๊ท๋ฅผ iterative๋ก ๋ณํ (๊ฐ์ฅ ๊ฒฌ๊ณ ):
```c
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{
/* The prefix chain is at most 8192 entries; resolve it into a
* fixed-size buffer iteratively to avoid stack recursion. */
stbi__uint16 stack[8192];
int sp = 0;
while (g->codes[code].prefix >= 0 && sp codes[code].prefix;
}
stack[sp++] = code;
while (sp > 0) {
stbi__uint16 cur = stack[--sp];
/* original per-code rendering body, factored out: */
stbi__render_gif_pixel(g, cur);
}
}
```
**์ต์
B** โ ๊น์ด ์ ํ:
```c
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code, int depth)
{
if (depth > 4096) return; /* defensive cap */
if (g->codes[code].prefix >= 0)
stbi__out_gif_code(g, g->codes[code].prefix, depth + 1);
...
}
```
์ต์
A๊ฐ ์ ์. stb์ minimal-dependency ์ฒ ํ๊ณผ๋ ๋ง์ (8192 short = 16 KB heap ๋๋ ํฐ stack 1ํ).
## Disclosure
๋ค๋ฅธ ๋ ๊ฒฐํจ (`convert_format16` heap overflow, BMP palette uninit-read)๊ณผ ํจ๊ป nothings/stb GitHub Security Advisory์ ๋ฌถ์ด ๋ณด๊ณ ๊ถ์ฅ.
## ๋ผ์ด์ ์ค
stb ๋ผ์ด์ ์ค(Public Domain / MIT-0)์ ํธํ. ๋ณด์ ์ฐ๊ตฌ ๋ชฉ์ ์ ์ฉ.