A1. SQL Injection - 정의, 공격 방식(Form, Union, Stored Procedure, Mass), 공격 유형(Error based, Blind), 취약점 확인, 대응방법
1. SQL Injection 정의
- 웹 어플리케이션에서 입력 받은 값을 DB로 전달할 때 정상적인 SQL 쿼리를 변조, 삽입하여 불법 로그인, DB 열람,
시스템 명령 실행 등을 수행하여 비정상적인 DB 접근을 하는 공격 방법.
- DB의 데이터에 무단으로 접근하여 유출, 변조, 삭제 함으로써 데이터에 접근하는 사용자를 피싱 사이트로 가게 하거나 악의적인 사이트로 유도하고,
DB의 개인 정보를 노출시키는 등 큰 문제를 야기할 수 있음.
2. 공격 방식
- Form SQL Injection
① 사용자 인증을 위한 쿼리문의 조건을 조작하여 인증을 우회하는 기법. 즉, 쿼리문의 Where절이 항상 '참'이 되도록 하여
성공시 사용자 권한을 획득하게 됨.
② 취약점 판단 예: 로그인 폼에 ID=', PW=1234를 입력했을 때(즉, 특수문자(')가 입력됨) SQL 문법 에러 메시지가 보인다면
입력한 값이 DB 서버까지 전달되어 오류가 발생한 것으로 입력 값에 대한 검증이 이루어지지 않아 SQL Injection에 취약한 페이지로 판단할 수 있음.
③ ID에 'or 1=1# 또는 'or '1'='1'# 또는 'or 'a'='a'# 등 where절을 무조건 참으로 만드는 입력 값을 넣고, PW는 1234를 입력하면 실제 쿼리는 아래와 같음.
SELECT id, password FROM memberinfo WHERE id=''or 1=1#' and password='1234'
id는 null 이거나 1=1(즉, 참) 이고, #은 Mysql의 경우 주석 처리문자이니 뒤쪽에 password 부분은 전부 주석처리 되버림.
따라서 memberinfo table을 검색하는 쿼리는 SELECT id, password FROM memberinfo WHERE id='' or 1=1 이 되고, WHERE절은 항상 참이니
SELECT id, password FROM memberinfo만 질의된다고 봐도 될 것이다.
이럴경우 memberinfo table의 모든 id와 password들이 질의결과로 추출되며, 결과 리스트 중 가장 상위에 있는 id와 password의 계정으로 로그인 되게 된다.
④ 대응: PHP의 경우 php.ini 파일에서 "maginc_quotes_gpc = on" 으로 설정하면 '(single quote), "(double quote), \(back slash), Null 문자를
일반 문자로 치환해주기 때문에 SQL Injection이 방지된다.
또는 MySQL을 사용할 경우 라이브러리 함수인 mysql_real_escape_string()을 사용하여 특수문자를 일반문자로 치환하게 할수 있다.
또다른 방법은 Prepared Statement(선처리 질의문)사용이다. 일반 SQL문은 동적쿼리생성과정("컴파일, 권한체크, 쿼리 실행"을 SQL 실행시마다 매번 수행)을
거치는데 사용자 입력에 따라 의도치 않은 쿼리가 실행될 수 있는 문제가 있다.
선처리 질의문은 입력값을 제외한 나머지 쿼리 부분이 미리 컴파일 되어 있고 입력값은 바인딩되는 방법이다.
따라서 id에 'or 1=1#을 입력하면 'or 1=1# 자체를 id로 인식하게되어 SQL Injection이 되지 않는다.
- Union SQL Injection
두 개의 쿼리의 결과를 결합하여 공격하는 방법.
주의할 점: 각 SELECT 문의 필드 갯수가 같고, 타입이 호환가능해야 함.
① SELECT id, pass FROM users WHERE id='admin' UNION SELECT 'admin', '1234'의 실행결과 => id=admin, pass=1234 로 나오게 된다.
② 컬럼 갯수 파악하기: order by 절을 이용한 방법
id='order by 1 #, pw=1234를 입력하면,
실제 쿼리는 SELECT id, pass FROM users WHERE id='' order by 1#이 되므로 # 이하는 주석 처리되고, 결과는 등록된 id가 아니라고 나온다.
또다시 order by 2, order by 3, 순서대로 진행하면서 "Unknown column '3' in 'order clause'" 메시지가 보인다면 컬럼 갯수는 3개임을 알게 된다.
③ union select로 인증 우회
id=' union select 'admin', 'admin', 'admin'#, pw=1234를 입력하면 실제 SQL문은
SELECT id, pass, name FROM users WHERE id='' UNION SELECT 'admin', 'admin', 'admin' #이되고, #이하는 주석 처리됨.
질의 결과로 id=admin, pass=admin, name=admin 이 반환되면서 인증 우회가 된다.
* Union SQL Injection 방법이 매우 많고 다양해 구글링을 할것.
- Stored Procedure SQL Injection
쿼리를 함수처럼 실행하기 위해 함수화한 것이 stored procedure임.
SQL Server를 예로 들면,
xxx.php?no=123;EXEC master..xp_dirtree 'C:\' 를 실행하면 xp_dirtree 프로시져가 실행되고, C드라이브의 파일 목록을 볼수 있음.
* 파라미터 넘기면서 프로시져를 실행시키는 형태인것 같음.
3. 공격 유형
- Error based SQL Injection
DB 쿼리에 대한 에러값을 기반으로 점진적으로 DB 정보를 획득하는 방법. 즉, SQL문 관련 특수 문자를 삽입해서 SQL 에러를 보고 판단하는 것.
최근에는 웹 서버 보안으로 인해 에러값 노출이 많지 않지만 과거에는 흔했음.
① 테이블, 컬럼 정보 획득(SQL server 예)
"abc.php?no=' having 1=1 --" 으로 입력할 경우, 웹 서버 내부에서는
select * from xxx where user = '' having 1=1-- and password = '' 같이 동작하고, --로 인해 password는 주석처리 된다.
결과: SQL Server xxx.no 가 집계함수에 없고, group by 절이 없어서 select 사용 못한다고 나옴. 이를 통해 xxx 테이블명과, no라는 속성명을 알아내게 된다.
② 컬럼 정보 획득(SQL server 예)
"abc.php?no=' group by xxx.no having 1=1--"으로 입력할 경우, 웹 서버 내부에서는
select * from xxx where user= ''group by users.id having 1=1-- and password ='' 같이 동작하고, --로 인해 password는 주석처리 됨.
결과: xxx.name열이 집계함수나 group by 절에 없으므로 select 사용 못한다고 나옴.
이를 통해 name이라는 속성명을 알아냄. 계속해서 진행하다보면 모든 속성의 이름을 알아내게 됨.
- Blind SQL Injection
SQL 질의 결과가 상세히 나오지 않는 경우 참과 거짓을 통해 공격하는 방법
① 게시판에서 글을 검색하는 경우
검색란에 ' and 1=1-- 를 입력하게 되면
SELECT * FROM board WHERE title like '%' and 1=1 -- 가 실행되고, -- 이하는 주석 처리되며, 모든 게시들이 검색되게 된다.
* 사례가 너무 많고 다양해서 추가적인 방법은 구글링으로 알아 볼것.
4. SQL Injection 취약점 확인 방법
- 동적 쿼리 생성하는지 확인
- SQLMap, Nikto 같은 SQL Injection 취약점 스캐너 사용.
5. 대응
- DB와 연동되는 모든 웹 페이지들의 사용자 입력값을 체크한다.
- 사용하는 DB의 프로시져가 시스템의 명령을 실행하는지를 살펴보고, 가능한한 삭제한다.
- DB 사용자 권한을 필요한 사용자에게만 부여한다.
- SQL 에러 메시지 노출 방지
- 사용자의 입력값은 신뢰하지 말것
- Prepared Statement를 사용한다.
- OWASP ESAPI 같은 검증 라이브러리 사용
- 클라이언트측 자바스크립트로 폼 입력값을 한 번 검증하고, 서버측도 한번 더 입력값을 필터링 함. 정규표현식으로 필터링하는게 강력하고 좋음.
SQL 쿼리로 넘길 때 해당 파라미터를 prepared statement로 입력하며, 쿼리의 출력값을 한번 더 필터링하고(XSS 공격 방어 목적) 유저에게 전송.
- 보안 회사에 컨설팅 받기.
* 정리한다고 했지만 너무 내용이 방대해서 알아본 모든 것을 정리하지 못함.
기본 개념을 공부한다는 생각으로 보면 될 것 같음.
* 참고
1. OWASP TOP 10 2013
2. http://egloos.zum.com/laydios/v/2089967
3. https://blog.lael.be/post/55
댓글 없음:
댓글 쓰기