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

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


이번 문제에서는 모르면 못 푸는 문제가 아닌가 싶습니다. ㅎㅎ...


그래도 큰 어려움은 없으니 풀어보도록 합시다.



 

 문제 이해


문제는 다음과 같습니다.

문제에서 md5('value', true)라고 나옵니다.

PHP의 md5 함수에서는 뒤에 boolean 옵션이 있습니다. 이 옵션은 기본적으로 false가 되어 있는데, 어째서인지 문제에서는 true로 작성해두었습니다.


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

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

 if(isset($_POST['ps'])){
  sleep(1);
  mysql_connect("localhost","md5_password","md5_password_pz");
  mysql_select_db("md5_password");
  mysql_query("set names utf8");
  /*
  
  create table admin_password(
   password char(64) unique
  );
  
  */

  include "../lib.php"; // include for auth_code function.
  $key=auth_code("md5 password");
  $ps = mysql_real_escape_string($_POST['ps']);
  $row=@mysql_fetch_array(mysql_query("select * from admin_password where password='".md5($ps,true)."'"));
  if(isset($row[0])){
   echo "hello admin!"."<br />";
   echo "Password : ".$key;
  }else{
   echo "wrong..";
  }
 }
?>
<style>
 input[type=text] {width:200px;}
</style>
<br />
<br />
<form method="post" action="./index.php">
password : <input type="text" name="ps" /><input type="submit" value="login" />
</form>
<div><a href='?view-source'>get source</a></div>


22번 라인에서는 싱글쿼터 우회를 방지하기 위해 real_escape가 걸려 있는 것을 볼 수 있습니다.

단, 23번 라인에서 우리가 입력한 값이 md5 함수에 들어가고 옵션이 true가 되어 있는 것을 볼 수 있습니다.

이 문제를 풀기 앞서 이 문제는 2010년에 플로리다 대학교에서 열린 Leet More CTF2010의 문제 중 하나입니다.


해당 참고 링크입니다.


http://cvk.posthaven.com/sql-injection-with-raw-md5-hashes




 

 문제 풀이


일단 이번 문제를 풀기 앞서 md5함수의 이해와 MySQL의 우회 방법에 대해 이해해야 합니다.


 

 md5('value', true) 이해


PHP의 md5함수의 bool 옵션은 기본적으로 false가 되어 있으나, true로 바뀔 경우 다음과 같은 변화가 있습니다.


md5('abcd', false) ==> e2fc714c4727ee9395f324cd2e7f331f

md5('abcd', true) ==> ��qLG'�$�.3


원래는 false의 경우처럼 hex로 된 값을 string으로 변환하여 반환해주는데, true 옵션을 넣어주게 되면, e2fc714c4727ee9395f324cd2e7f331f  hex값이 그대로 binary 형태로 보이게 됩니다. 


이해를 돕기 위해 다음과 같이 설명드리겠습니다.



 

 MySQL 우회


MySQL에서는 정상적인 조건문을 넣게 되면 당연하게도 정상적이게 실행됩니다.

select * from testtable where pw='abcd';


그러나 MySQL에서 만약 다음과 같이 조건문이 들어가게 되면 어떻게 되는지 알아보도록 하겠습니다.

select * from testtable where pw='abcd'='qwer';


이렇게 실행하게 되면 마치 아래의 쿼리와 같은 행동을 하게 됩니다.

select * from testtable where pw=0;


이는 'abcd'='qwer'이 거짓이기 때문에 0을 반환하게 되는 원리를 이용한 것입니다.


이해가 안 된다면 select 'abcd'='qwer'; 을 실행해보도록 합니다.



혹은 등호 말고도 or를 이용할 수도 있습니다.

select * from testtable where pw='abcd'or'1';


단 or 뒤에는 숫자가 나와야 합니다!!


이해가 되지 않는다면,

select 'adcd'or'1';

select 'abcd'or'a'; 

select 'abcd'or'1a';

select 'abcd'or'a1';

 각각 입력해보면 어떤 경우에 참인지 거짓인지 알 수 있습니다.




 

 위의 기법을 응용한 문제풀이


이제 위의 기법을 응용하여 문제를 풀어보도록 하겠습니다.

만약, md5() 해쉬로 나온 값에서 273d27 라는 값을 중간에 품고 있다면?


즉, 0x273d27 라는 값은 '=' 값입니다.


위의 값이 hash 중간에 들어가 있다면, binary를 그대로 출력해줄 때 ~~1~'='~~2~ 의 형태가 되게 됩니다.


그 말은 즉, select * from admin_password where password='~~1~'='~~2~' 의 형태로 쿼리가 만들어지게 되고, MySQL 우회 기법과 마찬가지로 문제가 풀리게 된다는 의미입니다.


이에 해당하는 값은 사실 브루트포싱을 통해 알아내야 합니다.


그런데 알아내는데 시간이 너무 오래걸립니다... ㅠㅠ


그래서 일단 저는 기존의 풀이대로 129581926211651571912466741651878684928 를 값으로 입력하였습니다.   


+ Recent posts