Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
StealMyBitcoin-PoC — Steal My Bitcoinチャレンジの公開リリース | Kitploit
ツール/GitHubGitHub/killaboi/stealmybitcoin-poc
メモリフォレンジック脆弱性分析エクスプロイトウェブアプリケーション悪用CTFペイロード開発バイナリエクスプロイトラボと実践
GitHubkillaboi/stealmybitcoin-poc

StealMyBitcoin-PoC

Steal My Bitcoinチャレンジの公開リリース

リポジトリを見る
21641601日前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

❤️ にてスポンサード hextree.io

Steal My Bitcoin CTF 概念実証

Steal My Bitcoin チャレンジに対する単一のライブ PHP コールバックを、最初から最後まで、標準ライブラリのみを使った単一の Python ファイルで。

Python Dependencies Target Lab

この README では stealmybitcoin_poc.py について説明します。これは、私の Steal My Bitcoin CTF 実行で使用したリクエストシーケンスを単一ファイルで再現した Python スクリプトです。Python の標準ライブラリのみを使用しています。スクリプトはリクエストを自身で構築し、次に進む前に各リークを検証し、新しい実行からの HTTP バイト列を記録します。

おそらく、余計なデバッグ用のガラクタをすべて省けばもっと簡単にできるでしょうし、Steam のローカル特権昇格に関する私の John Hammond の動画で発見したように、この醜い PoC もおそらく整理できるはずです。

[!NOTE] ⚠️ 正直なところ、これを整理するか、Sol にぐしゃぐしゃにされていない、より良いバージョンを自分で作ってください。 ⚠️

以下の内容はすべて Docker ラボに対して書かれたものであり、ライブチャレンジに対してではありません。ラボは nginx の背後にあるローカルの Alpine PHP 8.4.26 CLI サーバーであり、オフセットの調整に使用したのと同じビルドとワーカーモデルです。1 分で立ち上げて、チェーン全体を自分のマシン上でエンドツーエンドに実行できます。実際にチャレンジを解いたライブ実行は、末尾に歴史的な記録として残しています。

  stage                 what goes out                        what comes back
  ─────────────────────────────────────────────────────────────────────────────
  0  health      GET /php-version.php                 ->  PHP 8.4.26 confirmed
  1  heap leak   249,042 B producer + 8 x   6,672 B   ->  256 B cookie
                 (OOM poisons a worker)                   └─ Zend chunk base
  2  code leak   251,557 B producer + 8 x  92,388 B   ->   16 B cookie
                 (OOM poisons a worker)                   └─ zval_ptr_dtor
  3  callback    368,812 B POST                       ->  forged HashTable runs
                 (fake HashTable + command)               └─ zif_system(cmd)
  ─────────────────────────────────────────────────────────────────────────────
  20 HTTP requests at most. No looping, no retries.

概要

  1. 小さなマルチパートアップロードによって、PHP は回線サイズから想像されるよりもはるかに多くのメモリを消費します。
  2. セッションのアップロード進捗解析の途中でメモリが不足すると、PHP はワーカーに古い状態を残したままにし、そのワーカーがその後再利用されます。
  3. 後続のリクエストを適切に整形すると、セッション Cookie を通じてバイト列が漏えいします。私はそれをヒープアドレスと PHP コードアドレスとして読み取りました。
  4. 両方のアドレスが揃えば、最後のリクエストで偽造した PHP 構造体をクリーンアップが見つける場所に配置し、クリーンアップが zif_system(PHP の system ハンドラ)を呼び出します。
  5. そのコマンドは、まだ開いている接続を通じて新しい証明マーカーと 1 つの print-flag の結果を返します。

なぜ 2 つのアドレスが必要なのか? OS は PHP のコードとヒープが配置される場所を独立してランダム化します。ヒープリークは偽造構造体をどこに置くべきかをスクリプトに伝え、コードリークは呼び出したい関数が実際にどこにあるかを伝えます。以前のワーカーや以前の実行から得たアドレスは安全な代替にはならず、私が試すたびにその試行は単に失敗しました。

目次

  • ラボ
  • ここから始める
  • 各リクエストの役割
    • 1. 小さなプロデューサーがメモリ制限に達する仕組み
    • 2. ヒープアドレスを復元する仕組み
    • 3. PHP コードアドレスを復元する仕組み
    • 4. 最後のリクエストが system に到達する仕組み
  • 結果の読み方
  • 実際に成功する頻度
  • 解決に至ったライブラン
  • 用語の簡単な説明
  • 謝辞

ラボ

この PoC のオフセットは、4 つのワーカーで組み込み CLI サーバーを実行する Alpine PHP 8.4.26 向けに調整されています。ラボはまさにその構成を、nginx の背後で、ループバック上に再現します。

[!IMPORTANT] バージョン文字列よりもビルドの方が重要です。Debian の php:8.4.26-fpm スタックは同じ PHP/8.4.26 を報告しますが、バイナリレイアウトが異なるため、コードポインタのフィンガープリントは決して一致せず、実行はコードリークの段階で中止されます。以下の Alpine イメージを使用してください。

小さなファイルが 3 つあります。空のディレクトリに配置してください:

public/php-version.php(ヘルスエンドポイントであり、PoC が必要とする唯一のページ)

<?php
header('Content-Type: text/plain');
echo 'PHP ', PHP_VERSION, "\n";
echo 'PID: ', getmypid(), "\n";

print-flag(チャレンジバイナリの代替であり、実行可能である必要があります)

#!/bin/sh
printf '%s\n' 'LOCAL_DUMMY_WIF_NEVER_USE'

nginx.conf

events {}
http {
    server {
        listen 80;
        server_name _;
        location / {
            proxy_pass http://ctf-cross-php:8000;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
        }
    }
}

Then bring it up:

docker network create ctf-cross-net

docker run -d --name ctf-cross-php --network ctf-cross-net \
  --read-only --tmpfs /tmp:rw,size=32m,mode=1777 --memory 1g \
  -v "$PWD/public:/app:ro" \
  -v "$PWD/print-flag:/usr/local/bin/print-flag:ro" \
  -e PHP_CLI_SERVER_WORKERS=4 \
  php:8.4.26-fpm-alpine3.23 php -S 0.0.0.0:8000 -t /app

docker run -d --name ctf-cross-nginx --network ctf-cross-net \
  -p 127.0.0.1:18166:80 \
  -v "$PWD/nginx.conf:/etc/nginx/nginx.conf:ro" \
  nginx:1.27-alpine

Check it:

$ curl -s http://127.0.0.1:18166/php-version.php
PHP 8.4.26
PID: 1

PID は応答するワーカーによって変わり、それは問題ない。PoC がチェックするのはバージョン行の部分である。

docker rm -f ctf-cross-nginx ctf-cross-php && docker network rm ctf-cross-net で削除する。

[!TIP] Windows では、これらの docker run コマンドを PowerShell から実行するか、$PWD を C:/lab のような完全なドライブパスに置き換えてください。Git Bash では $PWD が /tmp/... のような MSYS パスに展開され、Docker Desktop はそれを自身の VM 内で解決します。その結果、バインドマウントは nginx.conf と print-flag があるべき場所に空のディレクトリを黙って作成し、コンテナは壊れた状態で起動します。

このレシピについていくつか補足する。イメージは fpm タグだがコンテナは php -S を実行するため、SAPI は cli-server となり、これがキャリブレーションの測定対象である。PHP_CLI_SERVER_WORKERS=4 は、リーク段階で複数のワーカーを競合させるために必要な設定である。私自身のラボハーネスでは、ワーカーにトレーサーをアタッチできるよう --cap-add SYS_PTRACE --security-opt seccomp=unconfined も渡していたが、PoC 自体はそれを決して行わないため、上記では省略している。


ここから始める

Python 3.11 以降、標準ライブラリのみ、インストール不要:

python .\stealmybitcoin_poc.py --url http://127.0.0.1:18166/php-version.php

引数なしで実行すると、ヘルプを表示してネットワークに一切アクセスせずに終了します。

正常な実行結果は次のようになります:

[health] PHP 8.4.26 confirmed
[heap] strict Zend base 0x78113e800000
[code] strict zval_ptr_dtor 0x615b1f512930
{"stage": "final", "nonce": "1ef0e73d8615157a", "execution_proof_verified": true, "response_path": "..."}

その zval_ptr_dtor 値の下位 21 ビットに注目してください: 0x112930 は、この Alpine ビルドに対してスクリプトが期待するフィンガープリントと正確に一致します。これが、不一致のイメージを拒否するチェックです。

返ってくるレスポンスボディは次のとおりです:

<br />
<b>Fatal error</b>:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 131072 bytes) in <b>Unknown</b> on line <b>0</b><br />
1ef0e73d8615157a
uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
0ec066e8b91457c7c19b5612f3e2ded7f117df08f402693669c1ffc2cfc24942  /usr/local/bin/print-flag
LOCAL_DUMMY_WIF_NEVER_USE

PHPの致命的エラー、次にこの実行で生成されたnonce、次にid、次に解決されたバイナリのハッシュ、最後にダミーフラグ。終了ステータスは検証済みの実行で0、それ以外では1です。

[!WARNING] プロデューサは意図的にPHPをメモリ制限まで追い込みます。この動作が許可されている場所でのみ実行してください。スクリプトはチャレンジのエンドポイントまたはループバックのラボURLにのみ通信し、それ以外の場合はパケットが送信される前に中止されます。

1回の実行は、ヘルスチェックのGET 1回、最大2バッチのリーク、そして最大1回の最終リクエストを意味します。ループもリトライもありません。各マルチパートボディは1 MiB未満に収まりますが、各リークバッチは9つの個別リクエストを1つの接続にパイプライン化します。

フラグ動作
--urlラボのエンドポイント、またはチャレンジ。何かを行うには必須。
--output-dir実行の証拠を書き込む場所。デフォルトはpoc-run-<UTC timestamp>。

各リクエストの動作

ツールをダウンロード