# gdImageTrueColorToPaletteBody allows arbitrary write/read access

Negative transparent color in gdImageTrueColorToPaletteBody causes OOB index into alpha array, enabling arbitrary null write, memory leak, and full RCE in PHP GD.

- Payout: $500
- Severity: high
- Program: Internet Bug Bounty
- Credited: fms
- Disclosed: 2019-10-31
- Write-up quality: 9/10
- Original: https://hackerone.com/reports/153776
- Library page: https://bugbountylibrary.com/r/h1%3A153776
- Tags: domain:oss impact:data-leak impact:rce kind:bounty platform:hackerone sev:high tech:php technique:chained technique:source-review vuln:info-disclosure vuln:memory-corruption vuln:rce

**Target:** PHP ext/gd libgd (gdImageTrueColorToPaletteBody, gdImageColorTransparent, imagescale)
**Root cause:** gdImageColorTransparent sets im->transparent to any int (including negative) on truecolor images without bounds check; gdImageTrueColorToPaletteBody then uses it as an array index into im->alpha, causing OOB read/write.
**Steps:**
1. Create truecolor image wide enough to reach target address: `imagecreatetruecolor($plt_strlen+0x10, 1)`
2. Set negative transparent index: `imagecolortransparent($img, -24060)` to point before pixels array
3. Convert: `imagetruecolortopalette($img, TRUE, 3)` so transparent becomes colorsTotal
4. Call `imagecolortransparent($img, 0xff)` to write null at OOB index `im->alpha[im->transparent]`
5. Allocate 256 palette colors, then `imagesetpixel($img, $plt_strlen, 0, 0x41)` etc. to overwrite strlen@plt with 0x44434241
6. For leak: use `imagescale` on palette image with OOB transparent index to read `im->red/green/blue/alpha[transparent]` into new_img->transparent
7. For RCE: leak libc base via /proc/self/maps, overwrite write@plt with pivot gadget, build ROP chain calling mprotect on shellcode buffer, trigger via fwrite/tmpfile
**How found:** Code review of gd_topal.c noticed `if (oim->transparent >= 0)` guard but gdImageColorTransparent lacks bounds check on truecolor images, allowing negative index; then traced downstream uses of im->transparent as array index in alpha[] and imagescale interpolation.
**Exploitation:** Attacker-controlled PHP script (e.g. via web upload) sets negative transparent color, converts to palette, then uses imagecolortransparent to null-write arbitrary addresses. Leaks heap/libc pointers via imagescale OOB read, defeats ASLR using /proc/self/maps, overwrites write@plt with stack pivot, ROPs to mprotect shellcode buffer RWX, executes reverse shell as www-data.
**Escalation:** Chained arbitrary null write + OOB read (imagescale) + PLT overwrite + ROP to achieve full remote code execution from a single PHP script.
**Insight:** When a struct field is validated at one sink but set unchecked at another (setter vs consumer), look for negative/oversized indices that pass the consumer's `>= 0` check; palette conversion and image scaling are rich OOB primitives because they index per-channel arrays with attacker-controlled color indices.
