#投稿37本目。LFIの脆弱性がどのように悪用されるのかを深堀り。
今回の目的
週次計画に基づき、LFI手法とログポイズニングについて分析。
LFIの脆弱性をつくことで、不正に内部ファイルを読み取る事は昨日までのチャレンジに確認した。
ここで疑問になるのが、
- LFI = 不正にファイルを読み取る事が目的 なのだろうか。はたまた、これはただの足掛かりで、本来はもっと別の攻撃手法につなげる事が一般的なんだろうか。
- LFI = 不正にファイルを「結果的に読み取る事ができる」だけの脆弱性なのだろうか。
というところ。
これを少し深堀りしていく。
このチャレンジについて
目的: セキュリティエンジニアとしての技術力向上
手段: シェルスクリプト作成を通じて学習
実施する事: 自動化,監視,ツール開発基礎学習など
目次
実行結果
今回は概念の深堀りだったのでコード作成は未実施だが、設計の作成までは行った。
次回記事で完成を目指すスクリプトとしては、以下のような出力が行われる事を目指す。
[ATTACKER] Log file has been poisoned.
--------------------
[SERVER] Simulating LFI to include log file...
[SERVER] Malicious code found in log!
[SERVER] RCE successful. Would have executed: 'whoami'
実行環境
- クラウド環境: N/A
- コンテナ技術: N/A
- 接続元(ローカルPC): Windows 11
- ターミナルソフト: Windows Terminal
- 接続先(サーバー): N/A
- 使用言語: Python (設計)
- 外部ライブラリ: N/A
- テスト対象: N/A
開発ステップ
本日計画した開発ステップは以下の通り。
- 攻撃の概念理解: Log Poisoningが「ログへの書き込み(汚染)」と「LFIによる読み込み(実行)」の2段階で成立することを理解する。
-
攻撃者のシミュレーション設計: 攻撃者がWebサーバーのログに悪意のあるコード(Webシェル)を書き込ませるプロセスをシミュレートする関数
poison_log_fileを設計する。 -
脆弱なサーバーのシミュレーション設計: LFI脆弱性を持つWebサーバーが、汚染されたログファイルをインクルードし、結果として中の悪意のあるコードを実行してしまうプロセスをシミュレートする関数
simulate_lfi_exploitを設計する。 -
全体のオーケストレーション: 上記の2つの関数を順番に呼び出し、攻撃の全貌をシミュレートする
main関数を設計する。
思考フローと問い
今回の設計にあたり、Log Poisoningの技術的な背景や攻撃者の動機について、いくつかの重要な問いと思考の整理を行った。その要約を以下に示す。
-
なぜLFIからRCEへ昇格させるのか?
- LFI単体ではファイルの「読み取り」しかできず、手動での情報収集には限界がある。RCE(リモートコード実行)権限を得ることで、サーバー内部で
grepやfindコマンドを直接実行でき、情報収集の効率が劇的に向上する。
さらに、バックドアの設置による持続性の確保や、内部ネットワークへの侵入拡大(ラテラルムーブメント)など、攻撃の目的を「情報窃取」から「サーバー支配」へと拡大できるため、攻撃者はそのリスクを冒す価値があると判断するとのこと。
- LFI単体ではファイルの「読み取り」しかできず、手動での情報収集には限界がある。RCE(リモートコード実行)権限を得ることで、サーバー内部で
-
Webシェルとリバースシェルの違いは何か?
-
Webシェル(今回のLog Poisoningで作成)は、HTTPのステートレスな性質上、コマンド実行のたびにリクエストが完結し、セッションが維持されない。これにより、コマンド履歴やTab補完、
vimなどの対話的なターミナル機能が使えず、非常に非効率である。 - リバースシェルは、HTTPを介さず、生のTCP接続を維持する(ステートフル)。これにより、SSHのように安定した対話的なセッションが確立され、攻撃者は効率的に作業を進めることが可能になる。Webシェルの獲得は、この安定したリバースシェルを確立するための「足掛かり」に過ぎない。
-
Webシェル(今回のLog Poisoningで作成)は、HTTPのステートレスな性質上、コマンド実行のたびにリクエストが完結し、セッションが維持されない。これにより、コマンド履歴やTab補完、
-
攻撃の成立条件と対策
- 攻撃が成立するには、「LFI脆弱性の存在」「ログファイルのパスを知っていること」「Webサーバーの実行ユーザーにログへの書き込み権限があること」の3つが必要。逆に言えば、ログをリアルタイムで別サーバーに転送し、即座に削除するような構成(ログローテーション)は、この攻撃を困難にする有効な対策となり得る。
開発中の気づき
本格的な実装に入る前に、まず最終的なゴールとなるスクリプトの全体像を設計した。
とりあえず、各関数が何をすべきかのロジックをコメント形式で記述する。
コード全文
以下が本日作成した、Log Poisoningシミュレーションのブループリントである。
# blueprint.py
# 偽のログファイルと「実行」したいコマンドの定数を定義する。
LOG_FILE = "fake_access.log"
ATTACKER_IP = "192.168.1.101"
TARGET_COMMAND = "whoami"
def poison_log_file(log_path, ip, command):
# 1. 悪意のあるログエントリを作成する。
# この文字列は、実際のサーバーログエントリ(例: Apache)のように見える必要がある。
# 重要なのは、コマンドが埋め込まれた偽のPHP Webシェルが含まれること。
# フォーマット例: f'{ip} - - [...] "GET /<?php system('{command}'); ?> HTTP/1.1" ...'
# 2. ログファイルを追記モード('a')で開く。
# これにより、既存のコンテンツを削除せずに追加する。
# 3. 悪意のあるログエントリをファイルに書き込む。
# 4. 「[ATTACKER] Log file has been poisoned.」のようなステータスメッセージを出力する。
def simulate_lfi_exploit(log_path):
"""
脆弱性のあるWebサーバーがポイズニングを受けたログファイルをインクルードするのをシミュレートする。
"""
# 1. 「[SERVER] Simulating LFI to include log file...」のようなステータスメッセージを出力する。
# 2. ログファイルを開き、全内容を読み込む。
# 3. 正規表現(regex)を使い、コンテンツから特定の
# PHP Webシェルのパターンを検索し、そこからコマンドを抽出する。
# 検索パターン: "<?php system('...'); ?>"
# 4. コマンドが見つかった場合:
# a. 成功メッセージを出力する: "[SERVER] Malicious code found in log!"
# b. 実行されたであろうコマンドを出力する: f"[SERVER] RCE successful. Would have executed: '{command_found}'"
#
# 5. コマンドが見つからない場合は、失敗メッセージを出力する。
def main():
"""
シミュレーション全体を統括する。
"""
# ステップ1: 攻撃者がログを汚染する。
poison_log_file(LOG_FILE, ATTACKER_IP, TARGET_COMMAND)
# 出力の可読性のために空白行を入れる。
print("-" * 20)
# ステップ2: 脆弱なサーバーがログをインクルードする。
simulate_lfi_exploit(LOG_FILE)
# --- メイン実行ブロック ---
if __name__ == "__main__":
main()
コードの詳細な解説
このブループリントは、主要な箇所は2つ。
-
poison_log_file(log_path, ip, command): 攻撃者の役割を担う。Apacheのアクセスログを模倣した文字列を生成し、その中に<?php system('...'); ?>という形式のWebシェルを埋め込む。そして、その文字列をターゲットのログファイルに追記する。 -
simulate_lfi_exploit(log_path): 脆弱なサーバーの役割を担う。指定されたログファイルを読み込み、正規表現を使ってWebシェルのパターンを探索する。パターンが見つかれば、中のコマンドを「抽出」し、実行されたであろうことを示すメッセージを表示する。
実行方法
このファイルはあくまで設計図であるため、このままでは実行できない。
今後のステップとして、このブループリントに記述されたコメントのロジックを、実際のPythonコードで実装していく。完成後、python <filename>.py のようにして実行する。
まとめ
本日は、Log Poisoning攻撃のシミュレーションスクリプトの実装に先立ち、その概念の理解と全体の設計に焦点を当てた。
攻撃のロジックを「汚染フェーズ」と「実行フェーズ」に分け、それぞれを関数として設計することで、攻撃の全体像が非常に明確になった。コードを書き始める前に設計図を作ることで、目的が明確になり、手戻りの少ない効率的な開発が可能になることを実感した。
次はこの設計図を元に、実際のPythonコードを実装していく。