[SQL Injection] SQL Injection
SQL Injection란 무엇인가?
DBMS에서 관리하는 데이터베이스에서는 회원 계정, 비밀 글과 같이 민감한 정보가 포함되어 있을 수 있습니다. 공격자는 데이터베이스 파일 탈취, SQL Injection 공격 등으로 해당 정보를 확보하고 악용하여 금전적인 이익을 얻을 수 있습니다. 따라서 임의의 정보 소유자 이외의 이용자에게 해당 정보가 출되지 않게 해야 합니다.
인젝션(Injection)
인젝션은 주입이라는 의미를 가진 영단어로, 인젝션 공격은 이용자의 입력값이 애플리케이션의 처리 과정에서 구조나 문법적인 데이터로 해석되어 발생하는 취약점을 의미합니다.
SQL Injection
SQL은 DBMS에 데이터를 질의하는 언어입니다. 웹 서비스는 이용자의 입력을 SQL 구문에 포함해 요청하는 경우가 있습니다. 예를 들면, 로그인 시에 ID/PW를 포함하거나, 게시글의 제목과 내용을 SQL 구문에 포함합니다. 아래 쿼리는 로그인 할 때 애플리케이션이 DBMS에 질의하는 예시 쿼리입니다.
/*
아래 쿼리 질의는 다음과 같은 의미를 가지고 있습니다.
- SELECT: 조회 명령어
- *: 테이블의 모든 컬럼 조회
- FROM accounts: accounts 테이블 에서 데이터를 조회할 것이라고 지정
- WHERE user_id='dreamhack' and user_pw='password': user_id 컬럼이 dreamhack이고, user_pw 컬럼이 password인 데이터로 범위 지정
즉, 이를 해석하면 DBMS에 저장된 accounts 테이블에서 이용자의 아이디가 dreamhack이고, 비밀번호가 password인 데이터를 조회
*/
SELECT * FROM accounts WHERE user_id='dreamhack' and user_pw='password'
쿼리문을 살펴보면, 이용자가 입력한 “dreamhack”과 “password” 문자열을 SQL 구문에 포함하는 것을 확인할 수 있습니다. 이렇게 이용자가 SQL 구문에 임의 문자열을 삽입하는 행위를 SQL Injection이라고 합니다. SQL Injection이 발생하면 조작된 쿼리로 인증을 우회하거나, 데이터베이스의 정보를 유출할 수 있습니다.
/*
아래 쿼리 질의는 다음과 같은 의미를 가지고 있습니다.
- SELECT: 조회 명령어
- *: 테이블의 모든 컬럼 조회
- FROM accounts: accounts 테이블 에서 데이터를 조회할 것이라고 지정
- WHERE user_id='admin': user_id 컬럼이 admin인 데이터로 범위 지정
즉, 이를 해석하면 DBMS에 저장된 accounts 테이블에서 이용자의 아이디가 admin인 데이터를 조회
*/
SELECT * FROM accounts WHERE user_id='admin'
Blind SQL Injection
데이터베이스 조회 후 결과를 직접적으로 확인할 수 없는 경우 사용할 수 있는 SQL Injection 공격 기법입니다.
아래 코드는 Blind SQL Injection 공격 시 사용할 수 있는 쿼리입니다.
# 첫 번째 글자 구하기
SELECT * FROM user_table WHERE uid='admin' and substr(upw,1,1)='a'-- ' and upw=''; # False
SELECT * FROM user_table WHERE uid='admin' and substr(upw,1,1)='b'-- ' and upw=''; # True
# 두 번째 글자 구하기
SELECT * FROM user_table WHERE uid='admin' and substr(upw,2,1)='d'-- ' and upw=''; # False
SELECT * FROM user_table WHERE uid='admin' and substr(upw,2,1)='e'-- ' and upw=''; # True
쿼리를 살펴보면, 두 개의 조건을 확인할 수 있습니다. 조건을 살펴보기 전에 substr 함수에 대하여 알아보겠습니다.
substr(string, position, length)
substr('ABCD', 1, 1) = 'A'
substr('ABCD', 2, 2) = 'BC'
공격 쿼리문의 두 번째 조건을 살펴보면, upw의 첫 번째 값을 아스키 형태로 변환한 값이 'a' 또는 'b'인지 질의합니다. 질의 결과는 로그인 성공 여부로 참/거짓을 판단할 수 있습니다. 만약 로그인이 실패할 경우 첫 번째 문자가 'a'가 아님을 의미합니다. 이처럼 쿼리문의 반환 결과를 통해 admin 계정의 비밀번호를 획득할 수 있습니다.
substr 외에도, 각 DBMS에서 제공하는 내장 함수를 잘 이용하는 것으로 원하는 데이터를 추출할 수 있습니다.
참고자료
1) Dreamhack - 웹 해킹 강좌 -
SeverSide: SQL Injection https://dreamhack.io/lecture/courses/191