Self-Improvement

블라인드 SQLi (조건부 응답, 조건부 에러, CASE 구문) 본문

SQLi

블라인드 SQLi (조건부 응답, 조건부 에러, CASE 구문)

JoGeun 2020. 4. 21. 14:44

블라인드 SQLi는 DB의 에러 메시지가 노출되지 않는 경우가 많기 때문에 취약점 탐지에 많은 주의가 필요하다. 이 부분에서는 UNION, Error 기법으로는 되지 않으며 공격난이도가 더 높다고도 할 수 있다.

블라인드 SQLi는 크게 부울(bolean)기반과 시간(Time)기반으로 구분된다.

 

 

조건부 응답

블라인드 방식으로 취약점 여부를 확인한느 방법은 참/거짓 명제를 주입해서 테스트하는 방법이 일반적이다.

참/거짓 명제에 대해서 알아보자면 "and 1=1" 또는 "and 1=2" "OR 1=1"와 같은 조건식 주입문이다.

 

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
 
if(!$link = mysql_connect('localhost''root''root')) {
        echo 'Could not connect to mysql';
        exit;
}
 
if (!mysql_select_db('northwind'$link)){
        echo 'Could not select database';
        exit;
}
 
$_empid = $_GET['empid'];
$sql = 'SELECT * FROM Employees WHERE employeeid=' . $_empid;
if(strpos(strtolower($_empid),"union")==FALSE) $result = mysql_query($sql$link);
 
if(!$result){
        echo "db error, could not query the database\n";
        //echo 'MySQL error: '.mysql_Error();
        exit;
}
 
print "<table border=1 cellpadding=5 cellspacing=0>\n";
print "\t<tr>\n\t\t<td>Employee ID</td><td>First Name</td><td>Title</td><td>Hire Date</td>\n\t</tr>";
while($row = mysql_fetch_assoc($result)){
        print "\t<tr>\n\t\t<td>".$row['EmployeeID']."</td><td>".$row['FirstName']."</td><td>".$row['Title']."</td><td>".$row['HireDate']."</td>\n\t</tr>\n";
}
print "</table>\n";
 
mysql_free_result($result);
?>
 
cs

소스코드를 보면 UNION 단어를 필터링하고 있으며 DB Error 메시지를 주석처리 했다.

 

페이지에 접속해보자.

- http://192.168.1.46/empinfo_id_blind.php?empid=1

 

원래 싱글쿼터를 주입하면 DB Error 내용이 노출됬지만 현재는 노출되지 않는 블라인드 상태이다.

이때는 블라인드의 참/거짓 명제로 주입을 해본다.

1 and 1=1

1 and 1=2

참인 명제를 주입할시에는 정상적으로 출력되며 거짓 명제를 주입할 시엔 데이터가 제대로 출력이 안되는 상황으로 보아 SQLi가 가능하다는 것을 알 수 있다. 이는 응답 데이터의 변화를 보며 확인하는 것이다.

 

DB의 버전을 알아내는 참/거짓 명제를 해본다.

1 and substr(version(),1,1)=1--

1 and substr(version(),1,1)=5--

DB의 버전은 5.5.52-MariaDB이며 substr() 함수로 첫번째 글자인 '5'을 비교하는 것이며 참인 명제를 했을 시에 데이터가 정상적으로 나왔다.

이러한 방법을 조건부 응답이라고 한다.

 

조건부 에러

조건부 에러는 참/거짓 명제 대신에 에러 유발 구문이 사용된다.

참/거짓 명제와 차이가 없지만 조건에 따라서 쿼리문 실행이 가능하다는 것이다.

여기서 유용하게 사용되는 건 CASE 구문이며 이를 통해 조건부를 나타낼 수 있다.

select version() from dual where 1=(case when 1=1 then 1 else 2 end)

 

에러 유발 구문은 DBMS에서 쿼리를 실행해야만 에러 유무 판단이 가능한 쿼리를 사용해야한다.

그렇지 않을 경우 DBMS의 쿼리 분석기에서 먼저 에러가 발생하기 때문에 조건에 따른 에러 유발이 불가하다. 

거짓 조건일 경우 아래의 쿼리를 실행하면 무조건 에러가 유발한다.

(select table_name from information_schema.tables)=1

 

CASE 구문을 이용하여 참일 경우 버전 정보를 출력하고 거짓일 경우 에러가 발생하는 예시를 해본다.

1 and (case when substr(version(),1,1)=1 then 1 else (select table_name from information_schema.tables)=1 end)--

DB의 버전의 첫글자는 "5"로 시작함으로 위의 CASE문은 거짓 명제가 되어 에러가 발생하는 쿼리문이 수행된다. 

그리하여 결과적으로는 에러가 발생하는 것이다

 

이번에는 참인 명제를 주입해본다.

1 and (case when substr(version(),1,1)=5 then 1 else (select table_name from information_schema.tables)=1 end)--