티스토리 뷰

Security/웹 해킹

SQL 인젝션

on1ystar 2019. 1. 14. 06:12
728x90
반응형

본 글의 목적은 제가 공부한 내용을 바탕으로 정리하면서 저와 같이 공부하시는 분 들을 위함입니다. 때문에 부족한 부분이 있을 수 있고, 잘못된 부분이 있을 수 있습니다. 만약 있을 경우, 생각을 고칠 수 있도록 저에게 알려주시면 정말 감사하겠습니다 !!


(OWASP Top 10 - Korean Translation 문서를 참고하였습니다. 쓰다 보니까 공부한 내용이 심히 얕은 것 같네요... 이와 관련하여 후에 실습이나 웹 해킹 문제를 풀어봐야 겠습니다.)

[Injection]

말 그대로 주입을 통한 공격으로 환경변수, 파라미터, /외부 웹 서비스, 모든 유형의 사용자 등 거의 모든 데이터의 소스는 인젝션 공격요인이 될 수 있습니다. 악의적인 공격자가 악의적인 데이터를 인터프리터에 보낼 때 인젝션 결함이 발생합니다

여기서 인터프리터는 예를 들어 클라이언트가 웹 서버에게 어떠한 웹 페이지를 요청합니다. 그러면 웹 서버는 자신의 메모리에 그 문서를 찾아 해석하는데, 만약 그 문서에 PHP로 작성된 부분이 있으면, 그 부분을 해석하지 못하므로 PHP엔진에게 해석을 부탁합니다. 그러면 PHP엔진이 그 부분을 해석해 HTML로 바꿔주는 과정에서 DB에 접속해야 된다면 다시 DB서버에게 요청을 하게 됩니다

DB에서 PHP문에 입력되어 있는 SQL문을 통해 DB에서 정보를 가져와 읽고 그 정보를 바탕으로 PHP엔진은 HTML문을 작성해 웹 서버에게 다시 전달해 줍니다. 이때 중간 전달자 역할인 PHP엔진이나 SQL역시 인터프리터가 됩니다.

인젝션 취약점은 신뢰할 수 없는 데이터가 명령어나 쿼리문의 일부분으로써, 인터프리터로 보내질 때 발생합니다. 공격자의 악의적인 데이터는 예기치 않은 명령을 실행하거나 올바른 권한 없이 데이터에 접근하도록 인터프리터를 속일 수 있습니다

이 인젝션은 데이터손실, 파괴, 권한 없는 사용자에게 정보 노출, 승인되지 않은  당사자에게 정보 무단 공개, 책임 부재, 서비스 거부 결과를 초래할 수 있습니다. 게다가 호스트를 완전하게 탈취 할 수도 있습니다. 이처럼 공격 방법이 쉬우면서 취약점 또한 발견하기 쉬운 반면, 끼치는 피해는 매우 심각한 수준이므로 OWASP Top10에서 2013년에 이어 2017년 역시 1번을 차지합니다.



[SQL Injection]

가장 핵심은 공격자가 임의의 SQL을 웹 애플리케이션 데이터베이스 쿼리에 삽입하는 것입니다

보통의 웹 애플리케이션은 서식을 통해 클라이언트의 입력을 받습니다. 그 입력 받은 것을 front end back end로 전달하게 됩니다. 이때 클라이언트의 악의적인 입력을 걸러내지 못하면 해커가 원하는 sql back end 데이터베이스에 입력해 데이터베이스의 내용을 삭제, 복사 또는 수정할 수가 있게 됩니다

이 밖에도 쿠키를 수정하거나 HTML 헤더 등의 서버 변수를 이용할 수도 있습니다

하지만 이 SQL 인젝션을 차단하는 것은 보안에서도 기본적인 부분입니다. 공격을 당하면 개발자가 실수를 했다는 것이 확실시 되기에 스스로에게 치부가 되는 공격이기도 합니다. 보안 방법도 쉽고 주의를 기울이면 거의 대부분의 공격을 막을 수 있습니다. (단, 창의적인 공격 패턴은 계속 나오겠지만요...)



[공격 방법]

information_schema MySQL서버가 운영하는 모든 다른 데이터베이스에 대한 정보를 저장하는 장소입니다. 그 중에는 데이터베이스 이름, 테이블 이름, 컬럼의 자료형, 접근 권한처럼 공격에 이용될 수 있는 민감한 정보들도 포함되어 있습니다.

이를 통해 컬럼 정보 역시 알 수 있고, 그것들을 조합해 원하는 데이터를 뽑아낼 수 있습니다.

substr 함수는 문자열과 자를 문자열의 범위를 파라미터로 받아서 해당 부분의 문자열을 리턴 해 주는 함수입니다.

-substr 함수 : substr(“string”,자르기 시작할 문자의 인덱스,자를 문자의 개수)

※ ascii 함수는 파라미터로 받은 값의 아스키 코드 값을 리턴 해주는 함수입니다.

-ascii 함수 : ascii(변환할 문자)

인증우회


보통 아이디와 패스워드를 입력하는 로그인 페이지를 타겟으로 하여 공격하는 기법입니다. 쿼리문의 논리적 연산 오류를 이용하여 아이디나 패스워드를 모르더라도 해당 값을 참으로 만들어 인증을 무력화 시키는 방법입니다. 먼저 웹 사이트가 클라이언트에게 알려주는 메시지들을 이용해 로그인 쿼리 구조를 유추하여 그에 맞는 패턴을 생각해내면 됩니다. 패턴을 알아 냈다면

ID : 'or 1=1 PASSWORD : 'or 1=1

ID : 'or 1=1-- PASSWORD : any 

등을 이용해 SELECT 조건문을 참으로 만들어 로그인을 우회할 수 있습니다.

먼저 'or 1=1에서 '는 앞 조건을 false로 만들기 위한 싱클쿼트이고, or 뒤에 무조건 참인 1=1을 주어 SELECT문 전체를 참으로 만드는 패턴입니다.

두 번째 패턴에서 --는 뒤의 내용을 주석처리 하겠다는 의미로 따라서 PASSWORD에 아무 값을 입력해도 그 부분은 주석처리가 되고, 앞의 1=1조건에 의해 전체 SELECT문이 참이 되어 로그인이 가능하게 됩니다. 이 밖에도 인증을 우회하는 패턴은 수도 없이 많고 창의적으로 더 만들어 낼 수 있습니다.( 주로 -- Oracle, MSSQL에서의 주석처리이고 # MySQL에서 사용하는 주석처리 기호입니다.)

Error Based SQL Injection


에러메시지를 기반으로 하는 기법으로 쉽고 빠르게 공격할 수 있는 기법이지만 에러메시지를 출력해주는 친절한 웹 페이지에 한해서 공격이 가능합니다. GET, POST 요청필드, HTTP헤더 값, 쿠키값 등에 싱글쿼트 혹인 세미콜론 등을 삽입 시 SQL 에러가 발생된다면 취약점이 있다고 판단할 수 있습니다.

주로 SQL구문 중 group by having 구문을 사용하여 일부러 에러를 유발시켜 그 정보를 바탕으로 데이터베이스 명이나 테이블, 컬럼, 궁극적으로 데이터를 얻는 것이 가능합니다.

예를 들어 취약점이 있는 웹 페이지의 URL 

?idx=1'having 1=1--

을 입력하면

member.idx 열이 집계 함수에 없고 GROUP BY 절이 없으므로 SELECT 목록에서 사용할 수 없습니다.

라는 에러 메시지가 얻어진다면 현재 쿼리에서 사용되는 테이블은 member이고 첫 번째 컬럼은 idx라는 정보를 얻을 수 있습니다. 그러면 이 얻어낸 컬럼 명을 group by절에 추가해 다음 컬럼을 알아내고, 다시 또 알아내고 이를 반복해 모든 컬럼 명을 알아낼 수가 있습니다.

Blind SQL Injection


만약 에러 정보를 노출하지 않는 사이트일 경우 악의적인 문자열 삽입 대신 쿼리결과(참 혹은 거짓)에 따라 정보를 취득하는 기법을 사용할 수 있습니다. 이 기법은 참과 거짓을 비교하는 과정을 거쳐가며 계속 질의를 보내어 결과들을 조합해 원하는 정보를 얻어내는 방법이므로 악의적인 목적을 가진 크래커들은 자동화된 툴을 시용하여 공격합니다.

만약에 ID admin인 곳을 공격한다고 생각해 봅시다.

그러면 ID admin을 입력해주고 뒤에

and ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table' limit 0,1),1,1)) <120#

의 쿼리를 이어 붙여줍니다. 그러면 먼저 table_type base table인 테이블 중 가장 위에 있는 테이블명을 한 개를 가져옵니다.

그 후 그 테이블명에서 앞의 한 글자를 반환하고 그 글자를 다시 아스키 값으로 반환해줍니다. 그러면 그 아스키 값과 120을 비교연산을 해 참이면 로그인이 되고 거짓이면 로그인이 안되겠죠? 로그인이 되면 120보다 작은 115를 넣어주거나, 로그인이 안되면 더 큰 125를 넣어주는 식으로 한 글자 씩 찾아나가는 겁니다.

#의 경우는 앞서 말했듯이 뒤의 패스워드를 모르기 때문에 패스워드를 입력하는 부분을 주석처리 해주기 위함입니다.

Union SQL Injection


2개 이상의 쿼리를 요청하여 결과를 얻는 Union연산자를 이용해 원하는 추가 쿼리를 삽입하여 정보를 얻는 기법입니다. 이 기법은 공격을 시도하는 두 개의 테이블의 컬럼의 갯수와 데이터 형식이 모두 같아야 합니다.

때문에 이 Union 기법도 역시 order by를 이용한 컬럼의 갯수를 파악하는 것이 핵심이 될 수 있습니다. order by : order by에서 뒤 조건에 숫자를 넣을 경우 이 숫자의 의미는 컬럼의 갯수가 됩니다. 이를 통해 숫자를 하나 씩 증가시키면서 참이 될 때를 확인하면 컬럼의 갯수를 알 수가 있습니다.

컬럼의 갯수를 알았으면 웹 페이지에 사용되는 컬럼을 알아내기 위해 파라미터 값에 부정조건을 전달해 줍니다

?idx=-99+UNION+SELECT+1,2,3,4,5 

이런 식으로 작성하면 앞의 조건은 거짓이 되고 뒤의 

UNION+SELECT+1,2,3,4,5

만 유효한 쿼리문이 됩니다. 따라서 해당되는 컬림이 웹 페이지에 나타나게 됩니다.

만약 3번 컬럼이 사용되었다면 

?idx=-99+UNION+SELECT+1,2,database(),4,5--

를 통해 데이터베이스 명을 알 수 있습니다. 또한 information_schema.tables를 이용하면 해당 데이터베이스의 테이블 리스트를 뽑아 낼 수도 있습니다.


[대응 방안]


기본적으로 Secure Coding이 필요합니다. 즉 절절한 문자 값 필터링을 해주어야 합니다.

URL 입력 값이나 인자 값을 처리하는 페이지에서 입력 값을 검증
홈페이지 및 게시판에서 사용하는 입력 페이지에서 입력 값에 대한 필터링
특수문자와 SQL 구문 필터링등이 있는데 
이러한 필터링들을 우회하는 방법들도 다양하게 존재하고 계속해서 나오기 때문에 지속적인 관리와 업데이트를 해주어야 합니다.


또한 SQL 서버 시스템 차원에서의 필터링도 필요합니다.

DB에 관련된 문자열 삽입 제한

불필요한 계정 삭제 및 모든 계정의 비밀번호 암호화와 검사

모든 샘플 DB 제거 및 DB에 불필요한 확장 프로시저 제거

IDS 및 웹 방화벽 등이 있습니다.

MySQL 라이브러리에서는 SQL 인젝션의 방어를 위한 mysql_real_escape_string 함수를 제공합니다. 이 함수는 어떤 값이 SQL 변조가 가능한지 확인하여 해당 문자를 모두 날려버리는 기능을 수행합니다. 물론 MySQL 외에도 여러 데이터베이스 라이브러리에서 관련 함수를 제공하고 있습니다.


728x90
반응형

'Security > 웹 해킹' 카테고리의 다른 글

webhacking.kr 23번  (0) 2019.01.10
Webhacking.kr 18번  (0) 2019.01.10
XSS  (0) 2019.01.10
댓글