[dreamhack] adm1ngkyj

5q1·2025년 3월 11일

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__);
    }
?>

조건은 다음과 같다.

  1. id 를 구하고
  2. pw를 구하고
  3. flag를 구하여야 한다

그런데, 여기서 필터링을 우회하여야하는데
information, schema, user 를 우회하여야 한다.

우선 SQL Injection 포인트는 모든 파라미터에서 발생하고 있음을 확인할 수 있었고, union에도 아무런 필터링이 되어있지 않기 때문에, union sql injection을 사용하여, 데이터를 추출할 수 있음을 유추할 수 있었다.

  1. ID 구하기
    (첫 번째 값)

    (두 번째 값)

두 번째 값이 존재하지 않음을 통하여, 값이 하나만 있음을 확인할 수 있었다.

  1. Union 사전 준비 (Order by)

union의 경우 선 컬럼의 갯수와 후 컬럼의 갯수가 동일하여야 하기에, order by를 통해 갯수를 파악하였을 때, 5개의 컬럼을 호출하고 있음을 확인할 수 있었다.

  1. union point!

2 번째 컬럼에서 입력 값이 노출되고 있음을 확인할 수 있었고
해당 부분에 쿼리를 입력하여, 데이터를 추출할 수 있음을 확인할 수 있었다.

  1. pw Column 출력하기
    "SELECT * FROM findflag_2 WHERE id_column='{id}' and pw_column='{pw}';")
    해당 구문에서, $pw_column 전까지를 문자열로 전환하고 이를 출력하면, pw_column명을 획득할 수 있다.

and = 와 같은 잡다한 문자열도 섞여있으므로, 이걸 무시하고 pw_column을 읽으면 된다.

  1. pw 출력하기

테이블 명도 이미 쿼리문 안에 노출되고 있으므로, 쉽게 pw를 출력할 수 있었다.

  1. flag 추출하기
    해당 문제의 포인트이다.

information_schema가 필터링되고 있을 때, 서브쿼리를 통해, 컬럼을 읽어올 수 있다.
여기서 중요한 점은, flag라는 것은 별칭이고, 만약 age가 필요하다면,

... select 1,2,3,4 as flag,5,6 union select * from member limit 1,1)a;

를 통해 추출할 수 있다.

그러므로, 여기서 flag_column을 출력하여야 하기 때문에, 해당 위치를 찾아야한다.
위치를 찾았다면, 값을 출력하면 된다.


만약 limit 절이 존재하지 않는다면, 위의 1,2,3,4,5에 대해 우선적으로 출력하고, 아래에 모든 데이터에 대해 출력을 하기 때문에 내가 필요한 정보가 어느 위치에 있는지도 파악하여야 한다.

그럼 flag_column의 값도 나왔으므로, 이를 전달하면 flag가 노출된다.

profile
+82 02 web vulnerability tester

0개의 댓글