매우 어려웠던 문제.

같은 문제인 줄 알았는데, 아니었다.

소스코드

<?php
    error_reporting(0);
    
    include("./config.php"); // hidden column name
    include("../lib.php"); // auth_code function

    mysql_connect("localhost","zairo","zairo_pz");
    mysql_select_db("zairo");

    /**********************************************************************************************************************/

    function rand_string()
    {
        $string = "1234567890abcdefghijklmnopqrstuvwxyz";
        return str_shuffle($string);
    }

    function reset_flag($count_column, $flag_column)
    {
        global $count;
        $flag = rand_string();
        $query = mysql_fetch_array(mysql_query("SELECT $count_column, $flag_column FROM findflag_2"));
        $count = $query[$count_column];
        if($query[$count_column] == 150)
        {
            if(mysql_query("UPDATE findflag_2 SET $flag_column='{$flag}';"))
            {
                mysql_query("UPDATE findflag_2 SET $count_column=0;");
                echo "reset flag<hr>";
            }
            return $flag;
        }
        else
        {
            mysql_query("UPDATE findflag_2 SET $count_column=($query[$count_column] + 1);");
        }
        return $query[$flag_column];
    }

    function get_pw($pw_column){
        $query = mysql_fetch_array(mysql_query("select $pw_column from findflag_2 limit 1"));
        return $query[$pw_column];
    }

    /**********************************************************************************************************************/

    $tmp_flag = "";
    $tmp_pw = "";
    $id = $_GET['id'];
    $pw = $_GET['pw'];
    $flags = $_GET['flag'];
    $count = 0;
    if(isset($id))
    {
        if(preg_match("/information|schema|user|where|=/i", $id) || substr_count($id,"(") > 0) exit("no hack");
        if(preg_match("/information|schema|user|where|=/i", $pw) || substr_count($pw,"(") > 0) exit("no hack");
        $tmp_flag = reset_flag($count_column, $flag_column);
        $tmp_pw = get_pw($pw_column);
        $query = mysql_fetch_array(mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';"));
        echo "<hr />NOW COUNT = {$count}<br />";
        if($query[$id_column])
        {
            if(isset($pw) && isset($flags) && $pw === $tmp_pw && $flags === $tmp_flag)
            {
                echo "good job!!<br />FLAG : <b>".auth_code("zairo")."</b><hr>";
            }
            else
            {
                echo "Hello ".$query[$id_column]."<hr>";
            }
        }
    }else {
        highlight_file(__FILE__);
    }
?>

바뀐점은 ( 를 사용할 수 없게 되었다는 점인데, 이 부분이 지난 문제에서 flag를 구할 때 핵심적으로 사용했던 부분이라 새로운 방법을 고안해야 했다.

풀이를 참조했고, order by를 통한 blind sql injection을 사용해야 한다고 했다.


blind sql injection Using order by

이 문제의 특징은 컬럼의 이름을 모른다는 점이다. 그런데 order by를 사용하면 컬럼의 이름을 모르는 상태에서도 컬럼을 정렬할 수 있다.

지난 문제에서처럼 컬럼의 순서를 바꾸어 가져올 수는 없지만, 열을 "정렬" 할 수 있다는 점 때문에 blind sql injection이 가능하다.

쿼리는 다음과 같다.

SELECT * FROM findflag_2 WHERE $id_column='1' and $pw_column='1' or 1=1 union select 1,99999,1,'a',1 order by 4-- g'