문제 설명

php로 작성된 페이지입니다.

알맞은 Id과 Password를 입력하여 플래그를 획득하세요.

플래그의 형식은 DH{…} 입니다.


풀이

문제에 접속하면 아래와 같이 Id와 Password를 입력하는 폼이 존재한다.

image-20240219003152357


소스 코드를 한 번 살펴봐야 한다. index.php에서 중요하게 살펴봐야 할 소스 코드는 아래와 같다. action을 check.php로 하고 있고 POST 메소드로 Id, Password를 각각 input1, input2라는 이름으로 check.php에 데이터를 전송한다. 또한 div 태그 아래에 require_once 함수를 사용해서 flag.php 파일을 삽입하고 있다

<div class="container">
  <div class="box">
  <h4>Enter the correct ID & Password.</h4>
    <p>
      <form method="post" action="/check.php">
          <input type="text" placeholder="Id" name="input1">
          <input type="text" placeholder="Password" name="input2">
          <input type="submit" value="제출">
      </form>
    </p>
  </div>

<?php
    require_once('flag.php');
    error_reporting(0);
?> 
</div> 


check.php의 소스 코드를 살펴보면, getRandStr 함수를 사용해 랜덤한 문자열을 $id 변수에 저장하고, $pw에는 sha1 함수를 사용하여 1을 해쉬한 값을 저장하고 있다. 그 아래에는 사용자가 입력한 값을 int 형으로 강제 변환하고, ==이라는 비교적 약한 비교를 사용하고 있기 때문에 여기에서 취약점이 발생한다.

<body>
    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">Type c-j</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Index page</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav><br/><br/><br/>
    <div class="container">
    <?php
    function getRandStr($length = 10) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
    
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[mt_rand(0, $charactersLength - 1)];
        }
        return $randomString;

    }
    require_once('flag.php');
    error_reporting(0);
    $id = getRandStr();
    $pw = sha1("1");
    // POST request
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
      $input_id = $_POST["input1"] ? $_POST["input1"] : "";
      $input_pw = $_POST["input2"] ? $_POST["input2"] : "";
      sleep(1);

      if((int)$input_id == $id && strlen($input_id) === 10){
        echo '<h4>ID pass.</h4><br>';
        if((int)$input_pw == $pw && strlen($input_pw) === 8){
            echo "<pre>FLAG\n";
            echo $flag;
            echo "</pre>";
          }
        } else{
          echo '<h4>Try again.</h4><br>';
        }
      }else {
      echo '<h3>Fail...</h3>';
     }
    ?> 
    </div> 
</body>


input_id 값이 0e로 시작하게 될 경우 php에서는 int 형 변환으로 인해 0으로 해석되고, 오른쪽에 있는 String 문자열도 최적의 비교를 하기 위해 int로 형 변환을 하게 되면서 문자열이므로 0으로 변환된다. 따라서 0을 10번 입력해주거나 0e로 시작하여 10의 길이로 입력해주면 된다. 그럼 ID pass 문자열을 확인할 수 있다.

image-20240219170133538

image-20240219170205069


비밀번호인 $pw에는 1을 SHA1으로 해쉬한 값을 저장하고 있었다. SHA1을 해쉬해주는 사이트에서 1을 해싱한 후 앞 8자리만 잘라 붙여넣어주면 flag를 얻을 수 있다.

image-20240219170400850

image-20240219170417919

댓글남기기