데이터 베이스 정보노출, 데이터 삽입, 삭제 및 변경, 데이터 베이스 서비스 중지, 사용자 인증 우회
데이터 베이스(DB)와 연동된 응용 프로그램에서 입력된 데이터에 대한 유효선 검증을 하지 않을 경우, 공격자가 입력
데이터에 SQL 쿼리문을 삽입하여 DB로 부터 정보를 열람하거나 조작할 수 있는 보안 취약점을 말한다.
위 그림과 같이 공격자는 쿼리를 조작할 수 있는 문자열을 입력하여 조작된 요청을 보낸다. 서버가 입력값을 검증하지
않고 DB쿼리 실행에 사용하는 경우 인가 되지 않는 사용자가 DB 데이터를 무단으로 조회 또는 삭제할 수 있다.
1. 어플리케이션에서 DB연결을 통해 데이터를 처리하는 경우 최소 권한이 설정된 계정을 사용해야 한다.
→ 취약한 어플리케이션으로 인해 침해 사고가 발생하더라도 나머지 부분에 대해 공격자가 액세스 권한을 가지지
않도록 어플리케이션에서 사용하는 DB연결 계정은 해당 어플리케이현이 사용하는 데이터에 대한 읽기,쓰기,삭제,
업데이트 권한만 설정한다.
2.외부입력값이 삽입되는 SQL 쿼리문을 동적으로 생성해서 실행하지 않도록 해야 한다.
→ 쿼리문의 구조가 외부입력값에 의해 변경되지 않는 API를 사용하도록 시큐어 코딩 규칙을 지정한다.
3.외부 입력값을 이용해 동적으로 SQL쿼리문을 생성해야 하는 경우, 입력값에 대한 검증을 수행한 뒤 사용한다.
→ 클라이언트와 서버 양층에서 입력값에 대해 안전한 값만 사용할 수 있도록 검증 작업을 수행한다.
3-1. 필터를 이용한 입력값 검증
→ 외부입력값에서 SQL 삽입이 가능한 문자열들을 필터링하여 안전한 값으로 치환하도록 하는 필터링을
생성하고 , DB에서 관리하는 데이터를 처리하는 모든 애플리케이션에 일괄 적용한다.
3-2. 인터셉트를 이용한 입력값 검증
→ MVC프레임워크를 사용하는 경우 인터셈터 컴포넌트를 사용하여 입력값에 대한 검증 작업을 수행 한 뒤
요청을 차단하거나 허용하는 정책을 어플리케이션에 일관 적용한다.
3-3. 라이브러리 또는 Validator컴포넌트를 이용한 입력값 검증
→ 입력값을 검증하는 Validator 컴포넌트를 공통 코드로 생성하고, 모든 개발자가 SQL문에 삽입되는
입력값에 대해 검증작업을 해당 컴포넌트에서 수행하도록 시큐어 코딩 규칙을 정의한다.
SQL 인젝션 취약점 실습
웹 어플리케이션의 일반적인 인증 절차
- 계정정보(ID/PW) 입력
- SQL 쿼리(Query) 생성
- DB로 쿼리(Query) 전송
- DB에서 쿼리(Query) 실행
- 반환되는 return 값에 따라 인증 여부 판단
데이터 베이스 정보가 노출되는지 시도하는것을 목표로 두는것이 모의해킹의 목표이고, SQL injection 취약점
존재 유무를 파악하는것이 취약점 진단이라고 할 수 있다.
SQL injection은 크게 Error-based SQL injection, Blind injection 등으로 나눠생각해 볼 수 있다.
Error-based 취약점
공격자가 쿼리(Query) 를 이용해서 의도적으로 에러를 발생시키고 에러를 발생 시켰을 떄 웹 서버에는 디폴트
에러 페이지를 만들어서 사용자에게 반환해준다. 디폴트 에러 페이지는 소스코드 오류나 디버깅, 에러를
해결하기 위한 형태로 구성된 페이지이며 이러한 형태는 공격자에게 매우 큰 도움이되기 때문에 공격자는 에러
페이지를 유발 시켜 웹서버의 기본정보나, DB정보를 얻을 수 있다.
실습환경 MS-SQL
1). Database 이름 알아내기
1-1). MS-SQL의 Database 이름을 반환하는 함수를 이용한다. → DB_NAME()
1-2). SQL injection 취약점이 있는 로그인 페이지
→ 'and DB NAME() >1 --
↑ 문자열과 정수를 비교할 수 없기 때문에 오류가 발생 했다.
# 해당 오류를 통해서 oyesmall이라는 DB명을 알아낼 수 있다.
2). Table 및 Column 이름 알아내기
2-1). Having
→ Group by절을 이용하여 지정한 컬럼의 필드값을 집계(묶음)후 조건 비교할 떄 사용한다.
Group by user id 를 사용하면 user id 컬럼안에 값을 같은 필드값들을 묶어 준다. Having은 묶어진
필드값들을 한번 더 조건 검사를 수해한다.
Having을 group by뒤에 쓴다. having은 group by와 함께 쓰이기 때문에 having을 써서 오류를 만들어
낸다면 group by와 함께 쓰라는 오류를 표시하면서 컬럼값을 알아낼 수 있다.
↑ SELECT * FROM Members WHERE user_id = "having 1=1 --
# having 오류 특정상 모든 컬럼을 알려주지만 에러 페이지 특성으로 인해 첫번째 컬럼 값만 알려준다.
# Table : Members, Column : num
↑ 동일한 데이터를 묶어서 무엇을 할건지 나와있지 않기 때문에 에러가 발생했다.
# 해당 에러를 통해서 다음 컬럼값을 유추해 낼 수 있다.
3)Field값(Record) 값 알아내기
SELECT user_id FROM members WHERE num > 0 → members 테이블의 user_id 컬럼의 모든 필드값을 가져온다.
↑
WHERE 조건의 in과 not in을 이용한 field값 조회
'or 1 in (select user_id from members where num > 0) --
=>oyes
'or 1 in (select user_id from members where num > 1) --
=>bisang2da
=>kisec
'or 1in(select user_id from members where user_id not in('oyes','bisang2da') ) --
=>kisec
'or 1in(select user_id from members where user_id not in('oyes','bisang2da','kisec') ) --
=> kisectest
고객사의 특성에따라 모의해킹 시나오도 달라진다. 현재는 위험성을 확인하는 수준의 모의해킹 시도라고
볼 수 있다 권한이 있는 사용자가 SQL문을 이용해서 특정 테이블의 컬럼값을 알아야 하는데
이때 테이블,필드값을 알아야한다. 때문에 공격자도 테이블과 컬럼값을 알아야 한다.
members table의 필드값을 획득할 수 있다면 다른 사용자의 권한으로 로그인할 수 있다. 이는 SQL injection의
가장 기본적인 목표이다. 이를 위해 Error-based, UNION등 다양한 유형의 injection을 시도해 볼 수 있다.
참고
- K-shield.jr 2기 정보보호 관리진단 과정
- KISA : 웹 취약점 분석 및 기술지원
- KISA : SW개발 보안 가이드