Skip to content
Exploit for Improperly Controlled Sequential Memory Allocation in Php

Exploit for Improperly Controlled Sequential Memory Allocation in Php

Sploitus • October 26, 2026

| `pocphp2shell.py` | One-click exploit (Proof of Concept) | eksploitasi penuh (heap leak + RCE) |

> Alat ini hanya boleh digunakan pada sistem yang Anda **miliki sendiri** atau

> yang Anda punya **izin tertulis eksplisit** untuk diuji. Penggunaan tanpa izin

> terhadap sistem orang lain adalah tindakan ilegal. Penulis tidak bertanggung

1. [Ringkasan Kerentanan](#ringkasan-kerentanan)

2. [Struktur Repositori](#struktur-repositori)

6. [Pemindai `php2shell.py`](#pemindai-php2shellpy)

7. [PoC `pocphp2shell.py`](#poc-pocphp2shellpy)

11. [Target di Belakang WAF / CDN](#target-di-belakang-waf--cdn)

14. [Pemecahan Masalah](#pemecahan-masalah)

15. [Etika dan Lisensi](#etika-dan-lisensi)

| CVE-2026-109618 | CVSS 9.2 - OOM -> `longjmp()` meninggalkan state Zend yang tidak valid -> RCE |

| CVE-2026-109619 | CVSS 9.2 - State global basi lintas worker FPM -> Use-After-Free -> RCE |

| Permukaan serangan | `session.upload_progress` (upload progres sesi PHP) |

| SAPI terdampak | `mod_php`, `php-fpm`, `cgi` |

| Versi rentan | PHP 5.4.0 - 8.5.11 (sekitar 14 tahun kode rentan) |

| Versi sudah ditambal | 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 dan seterusnya |

| Cabang EOL (tanpa patch resmi) | 5.4 / 5.5 / 5.6 / 7.0 / 7.1 / 7.2 / 7.3 / 7.4 / 8.0 / 8.1 |

- `GHSA-w8hw-w9fx-j79w` (CVE-2026-109618)

- `GHSA-6wmf-4rv5-p3rp` (CVE-2026-109619)

|-- php2shell.py # Pemindai + mode eksploitasi ringan

|-- pocphp2shell.py # PoC eksploitasi penuh (heap leak + RCE)

| `-- offsets.py # Helper opsional: baca simbol libphp dari container

|-- out/ # Hasil runtime (proof file, offsets.env)

| |-- p1 # Contoh proof file (keluaran perintah)

| `-- offsets.env # Offset simbol terdeteksi (dibuat otomatis)

Catatan: direktori `out/` dan berkas `offsets.env` dibuat saat runtime dan tidak

disertakan ke dalam repositori (lihat `.gitignore`).

- Python 3.8 atau lebih baru (disarankan 3.9+)

- Hanya pustaka standar Python - **tanpa dependensi eksternal**

- Tidak ada `pip install` yang diperlukan

git clone

Tidak ada langkah build atau instalasi berkas. Jalankan langsung dengan `python`.

# 1. Periksa satu target (aman, hanya GET)

python php2shell.py check -u

# 2. Periksa banyak target dari berkas dan simpan ke JSONL

python php2shell.py check -l targets.txt --output hasil.jsonl

# 3. Uji trigger eksploitasi pada target terkontrol (POST multipart)

python php2shell.py exploit -u

python pocphp2shell.py -u -c "id>/out/p1"

# 5. Jalankan unit test bawaan (tanpa jaringan)

Hanya mengirim permintaan **GET** untuk fingerprint target. Tidak ada permintaan

yang mengubah state. Aman dijalankan terhadap sistem produksi (dengan izin).

python php2shell.py check -u

python php2shell.py check -l targets.txt --workers 10 --timeout 20

python php2shell.py check -u --json

python php2shell.py check -u --output hasil.jsonl

Mengirim permintaan **POST multipart** yang mengandung

`PHP_SESSION_UPLOAD_PROGRESS` untuk menguji apakah trigger aktif. Gunakan hanya

python php2shell.py exploit -u

python php2shell.py exploit -u \

--call-address --cmd id

Menjalankan seluruh unit test bawaan dan keluar dengan kode status sesuai hasil.

| `-u, --url URL` | Satu URL target | wajib (salah satu) |

| `-l, --list FILE` | Berkas berisi satu URL per baris (`#` diabaikan) | wajib (salah satu) |

| `-q, --quiet` | Keluaran minimal, satu baris per target | nonaktif |

| `--json` | Keluaran setiap hasil sebagai baris JSON (JSONL) | nonaktif |

| `--workers N` | Jumlah worker konkuren | `5` |

| `--timeout DETIK` | Batas waktu permintaan | `15` |

| `--no-color` | Nonaktifkan warna ANSI | nonaktif |

| `--output FILE` | Simpan hasil ke berkas JSONL | - |

| `--assume VERSI` | Paksa versi PHP bila fingerprint diblokir WAF (mis. `7.4.33`) | - |

| `--deep-body` | Coba fingerprint versi dari badan respons / jalur phpinfo() umum | nonaktif |

| `--cmd PERINTAH` | Perintah untuk pengujian Chain A. Memerlukan `--call-address` |

| `--call-address URL` | URL spesifik tempat mengirim trigger POST (menimpa penemuan otomatis) |

1. **Header respons** - `X-Powered-By`, `Server`, `Via`, `X-Generator`

2. **Badan respons HTML** - halaman phpinfo (`PHP Version x.y.z`), meta generator,

3. **Jalur phpinfo umum** (bila `--deep-body`) - `/phpinfo.php`, `/info.php`,

4. **Paksa versi** (`--assume`) - hanya dipakai bila deteksi otomatis gagal, dan

Deteksi SAPI (`mod_php`, `fpm`, `cgi`) dilakukan secara heuristik dari header.

PoC eksploitasi satu-klik yang menjalankan rantai penuh: pemetaan heap,

kebocoran alamat `libphp`, lalu pemanggilan `zif_system`.

python pocphp2shell.py -u

python pocphp2shell.py -u -c "id>/out/p1" --proof-file out/p1

# Ambil bukti lewat HTTP bila berkas tidak dapat dibaca langsung

python pocphp2shell.py -u --fetch /out/p1

# Kalibrasi otomatis ukuran OOM (escalate sampai stage-1 berhasil)

python pocphp2shell.py -u --huge-mb 0

# Mode paralel (butuh --huge-mb tetap hasil kalibrasi serial)

python pocphp2shell.py -u --huge-mb 64 --threads 2

| `-c, --cmd PERINTAH` | Perintah (`/out/p1` |

| `--proof-file FILE` | Berkas tempat bukti keluaran perintah dibaca | `out/p1` |

| `--fetch PATH` | Ambil bukti lewat HTTP bila berkas tidak terbaca | - |

| `--profile {lab,bookworm}` | Profil offset build target | `bookworm` |

| `--zif-offset OFFSET` | Offset simbol `zif_system` (basis 0) | per profil |

| `--dtor-offset OFFSET` | Offset destruktor | per profil |

| `--htdata-offset OFFSET` | Offset HTDATA (basis 0) | per profil |

| `--offsets-file FILE` | Berkas offset yang dimuat | `out/offsets.env` |

| `--no-auto-offsets` | Jangan baca simbol `libphp` otomatis | nonaktif |

| `--docker-container NAMA` | Nama container untuk pembacaan offset | `php2shell-target` |

| `--huge-mb MB` | Ukuran field OOM; `0` = naik bertahap otomatis | `12` |

| `--no-auto-huge` | Jangan naikkan `--huge-mb` saat stage-1 gagal | nonaktif |

| `--save-path PATH` | `session.save_path` target (perintah panjang butuh path = 2` menjalankan stage 1 & 2 bersamaan | `1` |

| `--no-pre-rotate` | Lewati rotasi worker awal | nonaktif |

| `--no-retry-rotate` | Jangan rotasi worker saat gagal | nonaktif |

| `-q, --quiet` | Keluaran minimal | nonaktif |

| `--no-banner` | Sembunyikan banner ASCII art (untuk keluaran yang di-parse) | nonaktif |

Offset bersifat spesifik terhadap build. Untuk build selain profil bawaan,

sediakan berkas `out/offsets.env` atau gunakan `--docker-container` agar helper

`docker/offsets.py` membaca simbol dari container target.

Mode `--json` dan `--output` menghasilkan JSONL (satu objek JSON per baris) dengan

"timestamp": "2026-10-26T13:00:00+00:00",

"evidence": ["X-Powered-By: PHP/7.4.33", "PHP-FPM terdeteksi"],

| `timestamp` | Waktu pemindaian (UTC, ISO 8601) |

| `verdict` | Verdict dalam bahasa Indonesia |

| `verdict_en` | Verdict dalam bahasa Inggris |

| `php_version` | Versi PHP terdeteksi/diasumsikan |

| `sapi` | `mod_php`, `fpm`, `cgi`, `apache_unknown`, atau `null` |

| `version_source` | `header`, `body`, atau `assume` |

| `waf_detected` | Ada indikator WAF/CDN |

| `upload_trigger_accepted` | Trigger POST diterima (mode `exploit`) |

| `chains_at_risk` | Daftar chain serangan yang berpotensi berlaku |

| `evidence` | Daftar bukti yang dikumpulkan |

| `http_status` | Kode status HTTP terakhir |

| `response_time_ms` | Waktu respons (milidetik) |

| `kemungkinan rentan` | `likely vulnerable` | Versi PHP rentan terdeteksi |

| `sudah ditambal` | `patched` | Versi PHP sudah mengandung perbaikan |

| `siap dieksploitasi` | `exploit-ready` | Trigger diterima dan versi rentan |

| `tidak dapat disimpulkan` | `inconclusive` | Versi tidak dapat ditentukan (mis. disembunyikan WAF) |

`assess_chains()` memperkirakan chain yang berlaku berdasarkan SAPI dan versi.

Bila versi sudah ditambal, daftar kembali kosong.

| `A` | Injeksi sesi + LFI (session file inclusion) | Semua SAPI |

| `B` | Injeksi via upload progres sesi | Semua SAPI |

| `C` | Handler mismatch / konfigurasi FPM | `fpm`, tidak diketahui |

| `D` | RCE zero-dependency via OOM (mod_php) | `mod_php`, `apache_unknown`, tidak diketahui |

| `E` | State global basi lintas worker (UAF) | `fpm`, tidak diketahui |

WAF/CDN seperti Cloudflare sering menghapus header `X-Powered-By`, sehingga

fingerprint versi gagal dan verdict menjadi `tidak dapat disimpulkan`. Ini

perilaku **yang benar**, bukan bug - alat tidak dapat menyimpulkan apa yang

# Coba fingerprint versi dari badan respons & jalur phpinfo umum (tetap GET, aman)

python php2shell.py check -u --deep-body

# Paksa versi bila deteksi otomatis gagal (ditandai sebagai asumsi)

python php2shell.py check -u --assume 7.4.33

# Kombinasi: deteksi otomatis tetap diprioritaskan sebelum asumsi dipakai

python php2shell.py check -u --deep-body --assume 7.4.33

- `--deep-body` dan `--assume` mengisi celah informasi yang disembunyikan WAF,

tetapi hasilnya jujur ditandai (`version_source` = `body` atau `assume`).

- Untuk pengujian akurat pada mesin PHP lokal (mis. 7.4.33), arahkan langsung ke

origin-nya: IP asli tanpa CDN, atau `

- `--assume` hanya dipakai bila header **dan** badan tidak membocorkan versi.

| `0` | Selesai, tidak ada target rentan |

| `1` | Ada target dengan verdict rentan / siap dieksploitasi |

| `2` | Galat penggunaan / berkas tidak dapat dibaca |

| `130` | Dibatalkan oleh pengguna (Ctrl+C) |

| `0` | Eksploitasi berhasil (bukti diperoleh) |

| `1` | Eksploitasi gagal (tidak ada bukti) |

| `130` | Dibatalkan oleh pengguna (Ctrl+C) |

Suite unit test terintegrasi mencakup parsing versi, fingerprint badan respons,

validasi `--assume`, logika kerentanan, deteksi SAPI, deteksi WAF, logika verdict,

penilaian chain, encoding multipart, normalisasi target, keluaran JSONL, deteksi

cookie sesi, internal CLI, warna lintas platform, banner ASCII, dan stream UTF-8.

**Verdict `tidak dapat disimpulkan` pada target yang seharusnya rentan.**

Kemungkinan besar target berada di belakang WAF/CDN yang menghapus

`X-Powered-By`. Gunakan `--deep-body` dan/atau `--assume`. Lihat

[Target di Belakang WAF / CDN](#target-di-belakang-waf--cdn).

**Perintah panjang pada PoC tidak tereksekusi.**

Perintah `> 14` byte dikirim lewat berkas sesi dan memerlukan

`session.save_path` pendek (maksimal 4 karakter, mis. `/tmp`). Perintah panjang

juga tidak boleh memuat `|` atau baris baru; gunakan `;` sebagai pemisah.

Tersedia fallback verifikasi singkat (`id>/out/p1`).

Ukuran field OOM berada di luar rentang yang valid. Gunakan `--huge-mb 0` untuk

kalibrasi otomatis (butuh `memory_limit = 2` menolak berjalan.**

Mode paralel memerlukan `--huge-mb` tetap. Kalibrasi terlebih dahulu secara

serial dengan `--huge-mb 0`, lalu jalankan ulang dengan nilai yang berhasil.

**Karakter aneh pada keluaran di Windows / lokasi non-UTF-8.**

Kedua alat memaksa stdout/stderr ke UTF-8 dan banner memakai ASCII murni,

sehingga aman di semua terminal dan saat keluaran dialihkan ke berkas.

Gunakan `--json` pada pemindai, dan `--no-banner` pada PoC.

- Gunakan hanya pada sistem yang Anda miliki atau yang Anda punya izin

- Alat ini dibuat untuk riset keamanan, verifikasi patch, dan pengujian defensif.

- Penulis tidak bertanggung jawab atas kerusakan atau penyalahgunaan.

- Github: [github.com/gagaltotal](

- `GHSA-w8hw-w9fx-j79w` - CVE-2026-109618

- `GHSA-6wmf-4rv5-p3rp` - CVE-2026-109619