1. SQL Injection이란?
: SQL Injection 공격은 클라이언트 입력값에 임의의 SQL 문을 주입해서 데이터베이스에 저장된 중요한 데이터를 가져오는 공격이다.
난이도가 비교적 쉬운 편이고 공격에 성공할 경우 큰 피해를 입힐 수 있다는 특징이 있다.
인젝션 공격은 OWASP Top10에 항상 상위권에 속해 있고, 주요정보통신기반시설 기술적 취약점 분석 가이드에서도 찾아볼 수 있다. (참고로 OWASP은 악용가능성, 탐지가능성 및 영향에 대해 빈도수가 높고 보안상 영향을 크게 줄 수 있는 10가지 웹 애플리케이션 보안 취약점 목록이다. 3~4년 주기로 발표된다.)
2. 공격 유형
(세세한 공격 방식을 설명하기에는 글이 너무 길어질 것 같아서 여기선 각 공격의 발생 환경 등 대략적인 설명만 하겠습니다.)
1) Error Based Sql Injection
: 데이터베이스 에러 메시지를 활용하여 데이터베이스에 대한 정보를 획득하는 공격 기법
보통 개발자는 개발을 할 때 어떤 코드에 오류가 있는지 확인하기 위해 일부러 에러 메시지가 출력되게 설정한다. 이것이 서버를 운영할 때 그대로 이어지는 경우가 많은데, 공격자가 이 에러 메시지를 악용하는 것이다.
잘못된 SQL 문을 삽입해서 나오는 에러 메시지를 통해 공격자는 데이터베이스의 구조와 정보를 파악할 수 있다. 이를 통해 민감한 데이터를 탈취한다.
DB 종류에 따라 다양한 문법과 함수를 활용한다는 특징이 있다.
참고)
에러의 종류는 크게 문법 에러와 로직 에러가 있는데, Error Based SQLi에서는 로직 에러를 사용한다.
문법 에러는 대표적으로 필요한 문장 부호를 빠뜨리는 경우가 있다 ('인 경우가 가장 많다) . 따라서 구문 자체가 성립하지 않기 때문에 실행조차 되지 않는다.
로직 에러는 사용자가 의도한 작업을 프로그램에서 수행하지 못하는 오류이다. sql문에는 오류가 없어 실행될 수 있지만 결과가 개발자의 의도와 다르게 나온다. Error Based SQLi가 이용하는 에러가 바로 이것이다.
2) Union Based SQl Injeciton
: union 키워드를 사용해서 2개의 쿼리를 요청해서 내부 데이터를 얻어내는 공격 기법
원래의 요청에 union으로 한 개의 쿼리를 추가해서 정보를 얻어내는 것이 목적이다. 보통 게시글 페이지 같이 데이터베이스에 저장된 데이터가 보이는 경우에 사용한다.
3) Blind Sql Injection
: 데이터베이스 에러 메시지나 데이터가 직접적으로 노출되지 않을 때 사용하는 공격 기법
조작된 sql문을 삽입해도 어떠한 정보가 뜨지 않는 경우에 쓰는 최후의 보루이다. sql 문의 결과가 참 또는 거짓에 따라 서버의 응답이 달라지는 경우에 사용되며, 공격자는 참/거짓 여부로 공격의 성공 여부를 판단한다. 대표적으로 로그인 성공 or 실패를 알려주는 로그인 페이지가 있다.
이 공격은 데이터베이스의 이름, 테이블 이름, 컬럼 이름, 저장된 데이터를 순서대로 한글자 한글자... sql 문을 변경해가며 추출해야 하므로 시간이 매우 오래 걸린다. 따라서 자동화가 필수이다.
(요즘엔 웹사이트마다 보안이 철저하게 되어있어 sqli 공격이 통한다면 거의 Blind라고 한다.)
3. 방어 기법
(1) Prepared Statement 사용하기
Prepared Statement란?
구문 분석(parse) 과정을 최초 1회만 수행하여 생성된 결과 컴파일하여 메모리에 저장해 필요할 때마다 사용하는 방법이다.
사용자 입력값을 변수로 선언하여 미리 컴파일된 SQL 구문에 대입하기 때문에 SQL 문법에 영항을 미치는 특수문자나 구문이 입력되어도 문법적인 의미로 작용하지 못함.
처리의 효율성과 보안성 때문에 이미 대부분의 기업에서는 Prepared Statement를 사용중이다.
그렇다면 왜 SQL Injection을 공부해야하는걸까?
=> 아직까지 다음과 같은 보안 허점을 종종 발견할 수 있기 때문이다.
1. SQL 구문을 잘못 작성한 경우
> 사용자 입력값을 받는 부분을 '?'로 두고 컴파일해야 하는데 '?'를 사용하지 않은 경우가 가끔 존재
2. Prepared Statement를 사용하지 못하는 경우
> order by 같이 컬럼을 입력하는 곳에서는 사용하지 못한다.
> 그래서 order by에서 일어나는 경우가 많음
(2) 화이트 리스트 기반 필터링
Prepared Statement 사용이 불가한 경우에 사용한다.
안전한 문자열을 정의 & 허용한다.
개별 문자를 지정하는 것보다는 정규식 등을 이용해 패턴화해두는 것이 유용하다.
4. 실습
sql 인젝션 공격 범위는 데이터 탈취, 로그인 우회 등 다양하다. 여기서는 sql 인젝션 공격의 가장 기본이 되는 로그인 우회를 시도해볼것이다. 실습환경은 내가 개발한 로그인페이지이다. (id: admin / pw: admin1234)
(일반 웹 사이트에 공격을 시도했다가 실제로 공격이 통하면 범죄가 되니까 주의해야한다.)
공격을 시도하기 전 먼저 sql 인젝션 취약점이 존재하는지 확인하기 위해 id에 admin' #, pw는 기존에 사용하는 admin1234을 입력해서 로그인을 시도해본다.
만약 로그인이 된다면 다음 두 가지 경우 중 하나이다.
1. sql 문이 조작이 되는 경우
2. admin' #이라는 id가 존재하는 경우
하지만 두번째 경우일 확률은 매우 희박하기 때문에 로그인이 된다면 sql 문 조작이 가능한 것으로 취약점이 있음을 확인할 수 있다.
로그인을 해보니 다음과 같이 나를 환영해준다. sql 인젝션 취약점이 존재하는 페이지를 찾았다.
sql 인젝션 취약점 발견했다면, 서버에서 사용자로부터 입력받은 데이터를 처리하기 위해 어떤 sql문을 사용할지 파악하는 것이 중요하다.
여기서와 같이 로그인을 우회하려는 경우에는 입력한 id와 pw가 어떤 sql문으로 처리되는지 생각해봐야 한다. 만약 식별과 인증이 동시에 진행되는 경우라면 select id, pw from member where id='입력한 id' and pw='입력한 pw'일 것이다. (맞다 그렇게 설계했다.) 실제로는 이것 저것 여러가지를 시도해보면서 파악하면 된다.
이제 진짜 로그인 우회 공격을 시도해보자. id에 ' or '1'='1' #, pw에 1234 (그냥 아무 숫자)를 입력하고 로그인을 해본다.
로그인에 성공했다. sumin으로 로그인이 된 이유는 데이터베이스에 저장된 맨 처음 계정이 sumin이라 그렇다.
지난번에 포스팅 했던 것처럼 로그인 로직만 해도 식별/인증 동시, 식별/인증 분리 등 여러가지 경우가 있으니까 각각의 경우 마다 로그인 우회하는 방식을 생각해보는 것이 sqli를 이해하는 데 도움이 될 것같다.
이제 좀 더 자세한 공격 방식을 포스팅하러 가야겠다.
'웹 해킹 > SQL Injection' 카테고리의 다른 글
LORD OF SQLINJECTION - ORGE (0) | 2024.07.21 |
---|---|
[SQL Injection] Blind SQL Injection이란? (공격 절차, 실습) (0) | 2023.12.22 |
[SQL Injection] Union Based SQL Injection란? (공격 절차, 실습) (0) | 2023.12.19 |
[SQL Injection] Error Based SQL Injection란? (공격 절차, 실습) (1) | 2023.12.12 |