TryHackMe 歴1ヵ月半が参加する Advent of Cyber 2022 [Day 16]

16 日目。

[Day 16] SQLi’s the king, the carolers sing

今回は与えられたサイトのソースコードを Elf Exploit(赤い方)と Elf Admin(青い方)にチェックしてもらいながら直していく。

What is the value of Flag1?

Flag1 と Flag2 は解説を読みながら直していけばよい。

はじめは id パラメータ周りに問題があるので修正していく。4 行目の

$query="select * from users where id=".$_GET['id'];

$query="select * from users where id=".intval($_GET['id']);

に、さらに 17 行目の

$query="select * from toys where creator_id=".$_GET['id'];

$query="select * from toys where creator_id=".intval($_GET['id']);

に直して保存し、Run Checks ボタンをクリックすると Flag1 が得られる。

What is the value of Flag2?

2 問目は q パラメータ周りに問題がある。search-toys.php 4-5 行目の

$query="select * from toys where name like '%".$_GET['q']."%' or description like '%".$_GET['q']."%'";
$toys_rs=mysqli_query($db,$query);

$q = "%".$_GET['q']."%";
$query="select * from toys where name like ? or description like ?";
$stmt = mysqli_prepare($db, $query);
mysqli_stmt_bind_param($stmt, 'ss', $q, $q);
mysqli_stmt_execute($stmt);
$toys_rs=mysqli_stmt_get_result($stmt);

に直して保存し、Run Checks ボタンをクリックすると Flag2 が得られる。

What is the value of Flag3?

ここからは自力でコードを修正しなければならない。Elf Exploit のコメントを見るに 1 問目と同様、id パラメータ周りに問題があるので修正する。

今回は 2 か所修正する。まず 4 行目の

$query="select * from toys where id=".$_GET['id'];

$query="select * from toys where id=".intval($_GET['id']);

に、さらに 30 行目の

$query="select * from kids where assigned_toy_id=".$_GET['id'];

$query="select * from kids where assigned_toy_id=".intval($_GET['id']);

に直して保存し、Run Checks ボタンをクリックすると Flag3 が得られる。

What is the value of Flag4?

Elf Exploit のコメントを見ると POST で受け取った username パラメータに問題があるようなので修正を行う。

username パラメータは文字列なので、2 問目と同様にプレースホルダを用いる形に変更する。

<?php
require_once("connection.php");
session_start();

if(isset($_POST['username']) && isset($_POST['password'])){
    $username=$_POST['username'];
    $password=$_POST['password'];
    $query="select * from users where username=? and password='".$password."'";
    $stmt = mysqli_prepare($db, $query);
    mysqli_stmt_bind_param($stmt, 's', $username);
    mysqli_stmt_execute($stmt);
    $users_rs=mysqli_stmt_get_result($stmt);
    
    if(mysqli_num_rows($users_rs)>0)
    {
        $_SESSION['username']=$username;
        echo "<script>window.location='admin.php';</script>";
    }
    else
    {
        $message="Incorrect username/password found!";
        echo "<script type='text/javascript'>alert('$message');</script>";
    }
}

?>

...

これを保存して実行すると今度は password パラメータ周りに問題があると指摘される。

先ほどと同様に password パラメータ周りを修正する。

<?php
require_once("connection.php");
session_start();

if(isset($_POST['username']) && isset($_POST['password'])){
    $username=$_POST['username'];
    $password=$_POST['password'];
    $query="select * from users where username=? and password=?";
    $stmt = mysqli_prepare($db, $query);
    mysqli_stmt_bind_param($stmt, 'ss', $username, $password);
    mysqli_stmt_execute($stmt);
    $users_rs=mysqli_stmt_get_result($stmt);
    
    if(mysqli_num_rows($users_rs)>0)
    {
        $_SESSION['username']=$username;
        echo "<script>window.location='admin.php';</script>";
    }
    else
    {
        $message="Incorrect username/password found!";
        echo "<script type='text/javascript'>alert('$message');</script>";
    }
}

?>

...

If you'd like more SQLi in your life, check out this room!

No answer needed

感想

SQL はまあまあわかる程度、PHP はミリ知ら状態だったが解説が非常に親切で助かった。途中出てきた Goodboy Score なる用語でクレしんを思い出した(たしか良い子ポイントがたまらないとプレゼントがもらえないとかなんとかの回)。あとやっぱりそういう文化は海の向こうでもあるんだなぁと。