SQL Injection
- 웹사이트의 보안상 허점을 이용해 데이터베이스를 공격하는 해킹 기법
- SQL 쿼리에 사용자의 입력 값이 삽입돼 사용자가 원하는 쿼리를 실행할 수 있는 취약점
대응 방법
- ORM과 같이 검증된 SQL 라이브러리를 사용하는 것이 권장된다.
- ORM(Object Relational Mapper): SQL 쿼리 작성을 돕기 위한 라이브러리로, 사용자의 입력 값을 스스로 escape 하고 쿼리에 매핑시킨다.
- 이를 통해 개발자가 직접 쿼리를 작성하는 Raw 쿼리를 사용하지 않아도 기능 구현이 가능해 상대적으로 안전하다.
공격 기법
Logic
- 논리 연산을 이용한 공격 방법
- 예제) 로그인 기능
사용자가 아이디와 패스워드를 입력해 서버에 전송하면 서버는 데이터베이스에서 해당 데이터의 존재 여부를 파악해 로그인 성공 여부를 판단한다.
MySQL에서 로그인을 처리하는 가장 간단한 형태의 쿼리는 다음과 같다.
select * from user_table
where uid='{uid}' and upw='{upw}';
사용자가 자신의 아이디와 패스워드를 입력하면 웹 어플리케이션에서는 {uid}, {upw} 부분에 사용자가 입력한 문자열을 삽입하고 DBMS로 전달해 실행한다.
위 쿼리는 해석할 때 '를 기준으로 문자열을 구분한다.
만약 사용자가 입력에 '를 포함해 문자열을 탈출하고 뒷 부분에 새로운 쿼리를 작성하여 전달하면 DBMS에서 사용자가 직접 작성한 쿼리를 실행할 수 있다.
idx | uid | upw |
1 | guest | guest |
2 | admin | ********** |
위와 같은 테이블 구조를 가지고 있을 때, uid=guest와 upw=guest 데이터를 입력하면 테이블 내에 존재하는 guest 정보를 출력한다.
admin의 upw를 몰라도, 논리적으로 참이 되는 구조를 만들어 SQL Injection을 통해 admin의 정보를 출력할 수 있다.
이 예제에서는 1'or'1 등의 공격 페이로드를 통해 모든 정보를 출력 가능하다.
Union
- SELECT 구문의 Union 절을 이용한 공격 방법
- Union 절은 다수의 SELECT 구문의 결과를 결합시키는 행위를 수행한다.
- 데이터베이스 조회 쿼리의 결과가 어플리케이션에 출력되는 경우 사용하기 유용한 공격 기법이다.
- Union 절 사용 시 만족되어야 하는 조건
1. 이전 SELECT 구문과 UNION SELECT 구문의 결과 컬럼의 수 일치
2. 특정 DBMS에서 사용 시 이전 컬럼과 UNION SELECT 구문의 컬럼의 타입 일치
Subquery
- 하나의 쿼리 내에 또 다른 쿼리를 사용하는 것
- (Sub Query)와 같이 괄호를 통해 선언할 수 있다.
- 메인 쿼리가 접근하는 테이블이 아닌 다른 테이블에 접근하거나, SELECT 구문이 아닌 구문에서 SQL Injection이 발생해도 서브 쿼리의 SELECT 구문을 사용해 테이블에 데이터에 접근하는 것이 가능하다.
Error Based
- 임의적으로 에러를 발생시켜 정보를 획득하는 기법
- 로그가 적게 남고 공격에 소요되는 시간이 단축된다.
Blind
- 데이터베이스 조회 후 결과를 직접적으로 확인할 수 없는 경우 사용될 수 있는 공격 기법
- DBMS의 함수 또는 연산 과정 등을 이용해 데이터베이스 내에 존재하는 데이터와 사용자 입력을 비교하며, 특정한 조건 발생 시 특별한 응답을 발생시켜 해당 비교에 대한 검증을 수행한다.
- Blind SQL Injection 수행을 위해 만족되어야 하는 조건
1. 데이터를 비교해 참/거짓을 구분
2. 참/거짓의 결과에 따른 특별한 응답 생성
Error Based Blind
- 임의적으로 에러를 발생시켜 참/거짓을 판단하는 공격 기법
- 예제)
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))
첫번째 예제는 if 절이 1=1로 참이 되면서 단순히 1을 반환한다.
두 번째 예제는 if 절이 거짓이 되면서 select 1 union select 2 라는 쿼리를 실행하고, 서브쿼리에서 복수의 값을 반환하면서 에러가 발생한다.
Efficient Blind
- Blind SQL Injection을 수행할 때, 한 글자를 알아내기 위해 90여회의 쿼리를 날려야 한다.
- 쿼리를 효율적으로 작성하면 한 글자당 7회의 쿼리만으로 공격이 가능하다.
- 각 글자를 10진수로 변환하고 다시 2진수로 변환한 후에 lpad 함수를 사용해 7글자로 맞춰준다.
- 페이로드: select substr(lpad(bin(ascii(substr('asdf',1,1))),7,0),1,1)
SQL Injection with information schema.processlist
- information schema.processlist 테이블은 현재 실행 중인 쿼리를 저장하고 있다. 이를 이용해 원하는 정보를 담고있는 테이블을 빠르게 찾을 수 있다.
- select info from information_schema.processlist 라는 쿼리를 통해 현재 실행 중인 쿼리를 볼 수 있다.
- 다른 사용자가 로그인중일 때 해당 쿼리를 조회하는데 성공했다면 회원들의 정보가 들어이쓴 컬럼명과 테이블명을 한번에 볼 수 있다.
필터링
MySQL syntax
- MySQL에서, Keyword는 SeLeCT와 같이 대소문자를 구분하지 않는다.
- select * from users와 같은 쿼리도 공백을 필터링하는 경우 %0a 같은 delimiter를 쓸 수 있다.
- select(*)from(users);와 같이 공백이 필요한 부분에 괄호를 감싸는 것도 적법한 문장이다.
- 이러한 MySQL의 문법적 특성을 이용해 여러가지 필터링을 우회할 수 있다.
- 주석, 연산자, 공백, 환경변수 등을 활용할 수 있다.
Keyword Filter
- injection을 가능하게 하는 키워드(union, select, limit, having, like 등)는 MySQL의 내장함수를 사용해 대체 가능하다.
- 예를 들어, and와 or은 각각 ||와 &&를 사용한다.
- Union select를 연달아 필터링 하는 경우, union(select(pass)from(users))와 같이 괄호를 사용한다.
Function Filter
- 널리 알려진 substr(), ascii()와 같은 내장 함수들이 필터링 당했을 때 다소 알려지지 않은 함수들의 조합등으로 이를 우회할 수 있다.
'WEB > 개념 정리' 카테고리의 다른 글
[생활코딩] MySQL 정리 (0) | 2021.03.07 |
---|---|
XSS 공격 개념 정리 (0) | 2021.02.28 |