wargame.kr 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.

이번 포스트에서는 login_filtering 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.


이번 문제에서는 앞서 소개드렸던 문제들보다 심도 있는 이해가 요구됩니다.


큰 어려움은 없으니 차근차근 설명해보도록 하겠습니다.



 

 문제 이해


문제는 다음과 같습니다.

문제에서는 계정이 있는데, 블록되어 막혔다고 합니다.

이를 우회하여 들어갈 수 있는지 물어보는 문제입니다.


문제로 들어가 소스를 확인해보았습니다.

<?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

-->


25번 라인과 26번 라인을 보니 id, pw에는 real_escape 필터링이 되어 있어 싱글쿼터가 먹히질 않습니다.

그 말은 즉슨 sql injection을 하는 길을 모두 막아뒀다는 것입니다.


또 다른 필터링은 눈에띄지 않습니다.


다만 우리가 사용할 수 있는 계정은 guest/guest와, blueh4a/blueh4g1234ps라는 것입니다.



 

 문제 풀이


이번 문제에서는 코드를 보고 어떻게 우회할지 고민하는 문제입니다.

따라서 피들러를 사용할 필요가 없습니다.


원래는 피들러와 같은 툴로 이것저것 찔러봐야 알 수 있지만, 여기서는 삽질의 과정을 제외하고 풀이 과정만 작성해보려 합니다.


문제 풀이에 앞서, PHP와 MySQL 사이의 통신을 살펴보도록 하겠습니다.


 

 PHP와 MySQL의 대소문자 구분


PHP에서는 대소문자를 기본적으로 구분하여 인식합니다.


그 말은 즉, 우리가 Guest, gUest 등으로 입력하게 되면 PHP는 대소문자를 구분하기 때문에 guest라는 값과 다르게 인식한다는 것입니다.


그러나, MySQL은 기본적으로 대소문자를 구분하지 않습니다.


즉, 우리가 Guest를 입력하든, gUest를 입력하든 모두 같은 guest로 인식한다는 것입니다.


이러한 이유로 다음과 같은 경우의 쿼리 결과 값이 같아지기도 하는 현상이 발생합니다.


select * from testtable where id like 'a%';

select * from testtable where id like 'A%';


위의 like문에서 a와 A는 전혀 다른 값이지만, MySQL에서는 같은 값으로 인식합니다.



 

 대소문자 구분을 통한 우회


누구는 대소문자를 구분하고, 누구는 대소문자를 구분할 수 없는 이런 아이러니함을 이용하여, 이번 문제를 풀어보려 합니다.


위의 소스에서 PHP에서는 대소문자를 구분하여 블록된 아이디를 입력하면, 블록처리를 하게 됩니다.


그렇다면 여기서 guest 대신 Guest를 입력하게 되면 일단, PHP는 우회가 가능합니다.


또한 Guest라는 값은 MySQL에 들어갈 때 guest와 동일한 값으로 인식되기 때문에 쿼리는 다음과 같이 변하게 됩니다.


select * from user where id='guest' and ps=md5('guest');


이로 인해 문제가 풀리게 됩니다.



+ Recent posts