매우 어려웠던 문제.
같은 문제인 줄 알았는데, 아니었다.
소스코드
<?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'