매일 한 문제씩 푼다고 했는데 작심삼일도 못했다. 갑자기 일이 많아져서 뭔가 여유가 없다. 그래도 문제는 꾸준히 풀어야하니 오늘 잠깐 짬 났을때 하나 풀어 보았다.

문제 정보는 다음과 같다.

1
2
3
I have accounts. but, it's blocked.

can you login bypass filtering?

문제에 접속하면 로그인 화면이 하나 있고 소스코드를 볼 수 있게 되어있다. 소스코드는 다음과 같다.

 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php

if (isset($_GET['view-source'])) {
    show_source(__FILE__);
    exit();
}

/*
create table user(
 idx int auto_increment primary key,
 id char(32),
 ps char(32)
);
*/

 if(isset($_POST['id']) && isset($_POST['ps'])){
  include("../lib.php"); # include for auth_code function.

  mysql_connect("localhost","login_filtering","login_filtering_pz");
  mysql_select_db ("login_filtering");
  mysql_query("set names utf8");

  $key = auth_code("login filtering");

  $id = mysql_real_escape_string(trim($_POST['id']));
  $ps = mysql_real_escape_string(trim($_POST['ps']));

  $row=mysql_fetch_array(mysql_query("select * from user where id='$id' and ps=md5('$ps')"));

  if(isset($row['id'])){
   if($id=='guest' || $id=='blueh4g'){
    echo "your account is blocked";
   }else{
    echo "login ok"."<br />";
    echo "Password : ".$key;
   }
  }else{
   echo "wrong..";
  }
 }
?>
<!DOCTYPE html>
<style>
 * {margin:0; padding:0;}
 body {background-color:#ddd;}
 #mdiv {width:200px; text-align:center; margin:50px auto;}
 input[type=text],input[type=[password] {width:100px;}
 td {text-align:center;}
</style>
<body>
<form method="post" action="./">
<div id="mdiv">
<table>
<tr><td>ID</td><td><input type="text" name="id" /></td></tr>
<tr><td>PW</td><td><input type="password" name="ps" /></td></tr>
<tr><td colspan="2"><input type="submit" value="login" /></td></tr>
</table>
 <div><a href='?view-source'>get source</a></div>
</form>
</div>
</body>
<!--

you have blocked accounts.

guest / guest
blueh4g / blueh4g1234ps

-->

이 문제 풀면서 느낀건데 뭔가 난 아직 문제를 많이 안풀어봐서 그런건지, 아니면 센스가 부족한건지… 다른 시각이 필요한데 그걸 잘 못본다 ㅠㅠ 일단 처음에는 SQL Injection 문제인 줄 알았다.

인터넷을 찾아보니 mysql_real_escape_string 함수를 bypass 할 수 있다는 글이 있어서 bypass 해서 다른 계정으로 로그인을 하면 되는 줄 알았다. 그런데 등잔밑이 어둡다더니 취약점은 if 구문이었다. if 문을 살펴보면 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  if(isset($row['id'])){
   if($id=='guest' || $id=='blueh4g'){
    echo "your account is blocked";
   }else{
    echo "login ok"."<br />";
    echo "Password : ".$key;
   }
  }else{
   echo "wrong..";
  }

만약 쿼리를 실행 한 결과가 있다면, 해당 idguest 혹은 blueh4g 이라면 your account is blocked을 출력 해 준다. 그런데 이 때, ==를 사용하며 비교 대상은 쿼리 결과로 나온 $row['id']가 아니라 내가 입력 한 $id이다.

MySQL에서는 대소문자를 구분하지 않기 때문에 만약 내가 $id의 값으로 Guest를 입력 하더라도 DB에 guest가 있다면 idguest인 행을 얻어낼 수 있다. 그렇지만 if($id=='guest' || $id=='blueh4g') 구문에서 $id는 내가 입력 한 Guest일 테니, 조건문에 들어가지 않을 수 있다. SQL Injection인 줄 알았는데!!!

ID 자리에 Guest를, PW 자리에 guest를 입력하면 문제를 풀 수 있다. 너무 허무하다… ㅠㅠ

1
FLAG : 9783333beeb385184e9def185bc99ec81d72254b