やられアプリ BadTodo - 22 A8:2017 - 安全でないデシリアライゼーション

前回:やられアプリ BadTodo - 21 A10:2021-サーバーサイドリクエストフォージェリ(SSRF) - demandosigno

シリアライズされたCookieの改変

OWASP Top10 2017 のp.14「安全でないデシリアライゼーション」の項によると、攻撃シナリオの例として「攻撃者はシリアライズされたオブジェクトを変更して攻撃者自身に管理者権限を与える」という例が取り上げられています。
BadTodo - 15 アクセス制御や認可制御の欠落 で一番最後に試した、Cookie値を変更することで管理者に成り代わったり権限を得ることができるという脆弱性がこれに該当するため、こちらにも転載しておきます。

Cookieでの権限指定

ログイン時に「ログインしたままにする」というチェックボックスにチェックを入れてログインします。

すると AUTOLOGIN というCookieが発行されます。

値は次の通りとなりますが、
O%3A4%3A%22User%22%3A3%3A%7Bs%3A8%3A%22%00User%00id%22%3Bs%3A1%3A%223%22%3Bs%3A12%3A%22%00User%00userid%22%3Bs%3A4%3A%22test%22%3Bs%3A11%3A%22%00User%00super%22%3Bs%3A1%3A%220%22%3B%7D
開発ツールの「デコードされたURLを表示する」にチェックを入れるとデコードされた値を確認できます。
O:4:"User":3:{s:8:"Userid";s:1:"3";s:12:"Useruserid";s:4:"test";s:11:"Usersuper";s:1:"1";}
シリアライズ化されたデータのようです。改行を入れてみます。
O:4:"User":3: (4字のオブジェクト。クラス名"User"。オブジェクトは3つの属性を持つ)
{
s:8:"Userid";s:1:"3";(keyと値。”Userid”の前後にはnullバイトが存在するので8字)
s:12:"Useruserid";s:4:"test";
s:11:"Usersuper";s:1:"0";
}

この Cookie値のUsersuperの値を"1"に書き換えリロードすると、管理者権限になることができます。

更新がうまくいかない場合は「TODOSESSID」を右クリックして削除した後に「一覧」をクリックするなどして再読み込みしてみてください。

続けてUseridの値も"1"に書き換えます。Useruseridを"test"のままにしているため、右上のこんにちは上は「test」さんとなっていますが

マイページを確認すると"id=1"番の管理者に成りすませていることが分かります。

シリアライズデータとデストラクタを組み合わせたオブジェクトの実行

youtu.be
youtu.be
安全でないデシリアライゼーション(Insecure Deserialization)入門 | 徳丸浩の日記
PHPのunserialize関数に外部由来の値を処理させると脆弱性の原因になる | 徳丸浩の日記
PHPで安全でないデシリアライゼーションを学ぼう

上記を参考に色々と試してみたのですが、うまくいきませんでした……。

コンストラクタ・デストラクタ

コンストラクタ → オブジェクトを new する際に呼ばれる。
function __construct()
デストラクタ → PHPの場合オブジェクトがどこからも参照されなくなった時(プログラム終了時)に呼ばれる。
function __destruct()

シリアライズ・デシリアライズ

  • シリアライズ → 構造を持ったデータを「バイト列」に変換して伝送や蓄積しやすい形式にすること。
object(User)#7 (3) {
  ["id":"User":private]=> string(1) "3"
  ["userid":"User":private]=> string(4) "test"
  ["super":"User":private]=> string(1) "0"
}

serialize($_COOKIE['AUTOLOGIN']);
→O:4:"User":3:{s:8:"Userid";s:1:"3";s:12:"Useruserid";s:4:"test";s:11:"Usersuper";s:1:"0";}

  • デシリアライズ → シリアライズされたバイト列を元に戻すこと。
  • 外部から受け取ったバイト列をデシリアライズすると、任意のクラスのオブジェクトが作れる。
  • オブジェクトを new しなくても、デシリアライズされたオブジェクトを作るといずれデストラクタが実行される。
  • デストラクタによっては悪いことができる場合がある。
  • ただし、クラスを新規に作れるわけではなく既存のものを使うのに限られるので、既存のクラス定義の中で「どこまでできるか」が問題。

そこで何かできそうなコードがあるか探しました。

  • logindo.php には serialize関数があり common.php を読み込んでいる。
  • common.php は badapp.php を読み込んでいる。
  • badapp.php には unserialize関数がある。
  • badapp.php は session.php を読み込んでいる。
  • session.php のデストラクタは空。
  • common.php にデストラクタがありログを書き出している。
  • 「安全なWebアプリケーションの作り方 p.353」に、ログ管理クラスを使って攻撃を実行するほぼ同じ例が掲載されている。(ログにphpinfoを作成する)

のような点が分かったのですが、現状うまく実行できていません。
後日デバッガ―を使ってトレースしながら確認してみます。

解けた方はコメントでご教示いただけると嬉しいです。

次回:BadTodo - 23 evalインジェクション - demandosigno

/* -----codeの行番号----- */